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 "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/api-arguments-inl.h" | 8 #include "src/api-arguments-inl.h" |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 828 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
839 Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) { | 839 Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) { |
840 if (FLAG_tf_load_ic_stub) { | 840 if (FLAG_tf_load_ic_stub) { |
841 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); | 841 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); |
842 return LoadHandler::LoadField(isolate(), index); | 842 return LoadHandler::LoadField(isolate(), index); |
843 } | 843 } |
844 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); | 844 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); |
845 LoadFieldStub stub(isolate(), index); | 845 LoadFieldStub stub(isolate(), index); |
846 return stub.GetCode(); | 846 return stub.GetCode(); |
847 } | 847 } |
848 | 848 |
849 bool LoadIC::IsPrototypeValidityCellCheckEnough(Handle<Map> receiver_map, | 849 namespace { |
850 Handle<JSObject> holder) { | 850 |
851 template <bool fill_array> | |
852 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, | |
853 Handle<JSObject> holder, Handle<FixedArray> array, | |
854 Handle<Name> name) { | |
851 DCHECK(holder->HasFastProperties()); | 855 DCHECK(holder->HasFastProperties()); |
852 | 856 |
853 // The following kinds of receiver maps require custom handler compilation. | 857 // The following kinds of receiver maps require custom handler compilation. |
854 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap() || | 858 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap() || |
855 receiver_map->IsJSGlobalObjectMap()) { | 859 receiver_map->IsJSGlobalObjectMap()) { |
856 return false; | 860 return -1; |
857 } | 861 } |
858 | 862 |
863 HandleScope scope(isolate); | |
864 int checks_count = 0; | |
865 | |
859 // Switch to custom compiled handler if the prototype chain contains global | 866 // Switch to custom compiled handler if the prototype chain contains global |
860 // or dictionary objects. | 867 // or dictionary objects. |
861 for (PrototypeIterator iter(*receiver_map); !iter.IsAtEnd(); iter.Advance()) { | 868 for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { |
862 JSObject* current = iter.GetCurrent<JSObject>(); | 869 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
863 if (current == *holder) break; | 870 if (*current == *holder) break; |
864 Map* current_map = current->map(); | 871 Handle<Map> current_map(current->map(), isolate); |
872 | |
873 // Only global objects and objects that do not require access | |
874 // checks are allowed in stubs. | |
875 DCHECK(current_map->IsJSGlobalProxyMap() || | |
876 !current_map->is_access_check_needed()); | |
877 | |
865 if (current_map->IsJSGlobalObjectMap()) { | 878 if (current_map->IsJSGlobalObjectMap()) { |
866 return false; | 879 if (fill_array) { |
880 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current); | |
881 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( | |
882 global, name, PropertyCellType::kInvalidated); | |
883 DCHECK(cell->value()->IsTheHole(isolate)); | |
884 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); | |
885 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, | |
886 *weak_cell); | |
887 } | |
888 checks_count++; | |
889 | |
867 } else if (current_map->is_dictionary_map()) { | 890 } else if (current_map->is_dictionary_map()) { |
868 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. | 891 DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast. |
869 return false; | 892 if (fill_array) { |
893 DCHECK_EQ(NameDictionary::kNotFound, | |
894 current->property_dictionary()->FindEntry(name)); | |
895 Handle<WeakCell> weak_cell = | |
896 Map::GetOrCreatePrototypeWeakCell(current, isolate); | |
897 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, | |
898 *weak_cell); | |
899 } | |
900 checks_count++; | |
870 } | 901 } |
902 // We don't have to perform access checks for global proxy objects appeared | |
Jakob Kummerow
2016/10/27 11:30:54
nit: s/appeared/appearing/
Igor Sheludko
2016/10/27 14:55:30
Given I'm going to remove the access checks in the
| |
903 // in the middle of prototype chain because the receiver's map check | |
904 // already guarantees that we receiver belongs to the same native context. | |
Jakob Kummerow
2016/10/27 11:30:54
nit: s/we/the/
Igor Sheludko
2016/10/27 14:55:31
Acknowledged.
| |
871 } | 905 } |
872 return true; | 906 return checks_count; |
907 } | |
908 | |
909 } // namespace | |
910 | |
911 int LoadIC::GetPrototypeCheckCount(Handle<Map> receiver_map, | |
912 Handle<JSObject> holder) { | |
913 return InitPrototypeChecks<false>(isolate(), receiver_map, holder, | |
914 Handle<FixedArray>(), Handle<Name>()); | |
873 } | 915 } |
874 | 916 |
875 Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, | 917 Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, |
876 Handle<JSObject> holder, | 918 Handle<JSObject> holder, |
919 Handle<Name> name, | |
877 Handle<Object> smi_handler) { | 920 Handle<Object> smi_handler) { |
878 DCHECK(IsPrototypeValidityCellCheckEnough(receiver_map, holder)); | 921 int checks_count = GetPrototypeCheckCount(receiver_map, holder); |
922 DCHECK_LE(0, checks_count); | |
879 | 923 |
880 if (receiver_map->IsJSGlobalProxyMap() || | 924 if (receiver_map->IsJSGlobalProxyMap() || |
881 receiver_map->IsJSGlobalObjectMap()) { | 925 receiver_map->IsJSGlobalObjectMap()) { |
882 UNREACHABLE(); | 926 UNREACHABLE(); |
883 } else if (receiver_map->is_dictionary_map()) { | 927 } else if (receiver_map->is_dictionary_map()) { |
884 smi_handler = | 928 smi_handler = |
885 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); | 929 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); |
886 } | 930 } |
887 | 931 |
888 Handle<Cell> validity_cell = | 932 Handle<Cell> validity_cell = |
889 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 933 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
890 DCHECK(!validity_cell.is_null()); | 934 DCHECK(!validity_cell.is_null()); |
891 | 935 |
892 Handle<WeakCell> holder_cell = | 936 Handle<WeakCell> holder_cell = |
893 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); | 937 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); |
894 return isolate()->factory()->NewTuple3(validity_cell, holder_cell, | 938 |
895 smi_handler); | 939 if (checks_count == 0) { |
940 return isolate()->factory()->NewTuple3(holder_cell, smi_handler, | |
941 validity_cell); | |
942 } | |
943 Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray( | |
944 LoadHandler::kFirstPrototypeIndex + checks_count)); | |
945 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); | |
946 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); | |
947 handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell); | |
948 InitPrototypeChecks<true>(isolate(), receiver_map, holder, handler_array, | |
949 name); | |
950 return handler_array; | |
896 } | 951 } |
897 | 952 |
898 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { | 953 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { |
899 DCHECK(lookup->state() == LookupIterator::ACCESSOR); | 954 DCHECK(lookup->state() == LookupIterator::ACCESSOR); |
900 Isolate* isolate = lookup->isolate(); | 955 Isolate* isolate = lookup->isolate(); |
901 Handle<Object> accessors = lookup->GetAccessors(); | 956 Handle<Object> accessors = lookup->GetAccessors(); |
902 if (accessors->IsAccessorInfo()) { | 957 if (accessors->IsAccessorInfo()) { |
903 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); | 958 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); |
904 if (info->getter() != NULL && | 959 if (info->getter() != NULL && |
905 !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) { | 960 !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) { |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1223 return isolate()->builtins()->LoadIC_Normal(); | 1278 return isolate()->builtins()->LoadIC_Normal(); |
1224 } | 1279 } |
1225 | 1280 |
1226 // -------------- Fields -------------- | 1281 // -------------- Fields -------------- |
1227 if (lookup->property_details().type() == DATA) { | 1282 if (lookup->property_details().type() == DATA) { |
1228 FieldIndex field = lookup->GetFieldIndex(); | 1283 FieldIndex field = lookup->GetFieldIndex(); |
1229 Handle<Object> smi_handler = SimpleFieldLoad(field); | 1284 Handle<Object> smi_handler = SimpleFieldLoad(field); |
1230 if (receiver_is_holder) { | 1285 if (receiver_is_holder) { |
1231 return smi_handler; | 1286 return smi_handler; |
1232 } | 1287 } |
1233 if (FLAG_tf_load_ic_stub && | 1288 if (FLAG_tf_load_ic_stub && GetPrototypeCheckCount(map, holder) >= 0) { |
1234 IsPrototypeValidityCellCheckEnough(map, holder)) { | |
1235 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); | 1289 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); |
1236 return SimpleLoadFromPrototype(map, holder, smi_handler); | 1290 return SimpleLoadFromPrototype(map, holder, lookup->name(), |
1291 smi_handler); | |
1237 } | 1292 } |
1238 break; // Custom-compiled handler. | 1293 break; // Custom-compiled handler. |
1239 } | 1294 } |
1240 | 1295 |
1241 // -------------- Constant properties -------------- | 1296 // -------------- Constant properties -------------- |
1242 DCHECK(lookup->property_details().type() == DATA_CONSTANT); | 1297 DCHECK(lookup->property_details().type() == DATA_CONSTANT); |
1243 if (FLAG_tf_load_ic_stub) { | 1298 if (FLAG_tf_load_ic_stub) { |
1244 Handle<Object> smi_handler = | 1299 Handle<Object> smi_handler = |
1245 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); | 1300 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); |
1246 if (receiver_is_holder) { | 1301 if (receiver_is_holder) { |
1247 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); | 1302 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); |
1248 return smi_handler; | 1303 return smi_handler; |
1249 } | 1304 } |
1250 if (IsPrototypeValidityCellCheckEnough(map, holder)) { | 1305 if (GetPrototypeCheckCount(map, holder) >= 0) { |
1251 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); | 1306 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); |
1252 return SimpleLoadFromPrototype(map, holder, smi_handler); | 1307 return SimpleLoadFromPrototype(map, holder, lookup->name(), |
1308 smi_handler); | |
1253 } | 1309 } |
1254 } else { | 1310 } else { |
1255 if (receiver_is_holder) { | 1311 if (receiver_is_holder) { |
1256 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); | 1312 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); |
1257 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); | 1313 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
1258 return stub.GetCode(); | 1314 return stub.GetCode(); |
1259 } | 1315 } |
1260 } | 1316 } |
1261 break; // Custom-compiled handler. | 1317 break; // Custom-compiled handler. |
1262 } | 1318 } |
(...skipping 1750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3013 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); | 3069 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); |
3014 it.Next(); | 3070 it.Next(); |
3015 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | 3071 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
3016 Object::GetProperty(&it)); | 3072 Object::GetProperty(&it)); |
3017 } | 3073 } |
3018 | 3074 |
3019 return *result; | 3075 return *result; |
3020 } | 3076 } |
3021 } // namespace internal | 3077 } // namespace internal |
3022 } // namespace v8 | 3078 } // namespace v8 |
OLD | NEW |