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 } |
871 } | 902 } |
872 return true; | 903 return checks_count; |
| 904 } |
| 905 |
| 906 } // namespace |
| 907 |
| 908 int LoadIC::GetPrototypeCheckCount(Handle<Map> receiver_map, |
| 909 Handle<JSObject> holder) { |
| 910 return InitPrototypeChecks<false>(isolate(), receiver_map, holder, |
| 911 Handle<FixedArray>(), Handle<Name>()); |
873 } | 912 } |
874 | 913 |
875 Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, | 914 Handle<Object> LoadIC::SimpleLoadFromPrototype(Handle<Map> receiver_map, |
876 Handle<JSObject> holder, | 915 Handle<JSObject> holder, |
| 916 Handle<Name> name, |
877 Handle<Object> smi_handler) { | 917 Handle<Object> smi_handler) { |
878 DCHECK(IsPrototypeValidityCellCheckEnough(receiver_map, holder)); | 918 int checks_count = GetPrototypeCheckCount(receiver_map, holder); |
| 919 DCHECK_LE(0, checks_count); |
879 | 920 |
880 if (receiver_map->IsJSGlobalProxyMap() || | 921 if (receiver_map->IsJSGlobalProxyMap() || |
881 receiver_map->IsJSGlobalObjectMap()) { | 922 receiver_map->IsJSGlobalObjectMap()) { |
882 UNREACHABLE(); | 923 UNREACHABLE(); |
883 } else if (receiver_map->is_dictionary_map()) { | 924 } else if (receiver_map->is_dictionary_map()) { |
884 smi_handler = | 925 smi_handler = |
885 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); | 926 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); |
886 } | 927 } |
887 | 928 |
888 Handle<Cell> validity_cell = | 929 Handle<Cell> validity_cell = |
889 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 930 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
890 DCHECK(!validity_cell.is_null()); | 931 DCHECK(!validity_cell.is_null()); |
891 | 932 |
892 Handle<WeakCell> holder_cell = | 933 Handle<WeakCell> holder_cell = |
893 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); | 934 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); |
894 return isolate()->factory()->NewTuple3(validity_cell, holder_cell, | 935 |
895 smi_handler); | 936 if (checks_count == 0) { |
| 937 return isolate()->factory()->NewTuple3(holder_cell, smi_handler, |
| 938 validity_cell); |
| 939 } |
| 940 Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray( |
| 941 LoadHandler::kFirstPrototypeIndex + checks_count, TENURED)); |
| 942 handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler); |
| 943 handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell); |
| 944 handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell); |
| 945 InitPrototypeChecks<true>(isolate(), receiver_map, holder, handler_array, |
| 946 name); |
| 947 return handler_array; |
896 } | 948 } |
897 | 949 |
898 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { | 950 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { |
899 DCHECK(lookup->state() == LookupIterator::ACCESSOR); | 951 DCHECK(lookup->state() == LookupIterator::ACCESSOR); |
900 Isolate* isolate = lookup->isolate(); | 952 Isolate* isolate = lookup->isolate(); |
901 Handle<Object> accessors = lookup->GetAccessors(); | 953 Handle<Object> accessors = lookup->GetAccessors(); |
902 if (accessors->IsAccessorInfo()) { | 954 if (accessors->IsAccessorInfo()) { |
903 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); | 955 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); |
904 if (info->getter() != NULL && | 956 if (info->getter() != NULL && |
905 !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) { | 957 !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(); | 1275 return isolate()->builtins()->LoadIC_Normal(); |
1224 } | 1276 } |
1225 | 1277 |
1226 // -------------- Fields -------------- | 1278 // -------------- Fields -------------- |
1227 if (lookup->property_details().type() == DATA) { | 1279 if (lookup->property_details().type() == DATA) { |
1228 FieldIndex field = lookup->GetFieldIndex(); | 1280 FieldIndex field = lookup->GetFieldIndex(); |
1229 Handle<Object> smi_handler = SimpleFieldLoad(field); | 1281 Handle<Object> smi_handler = SimpleFieldLoad(field); |
1230 if (receiver_is_holder) { | 1282 if (receiver_is_holder) { |
1231 return smi_handler; | 1283 return smi_handler; |
1232 } | 1284 } |
1233 if (FLAG_tf_load_ic_stub && | 1285 if (FLAG_tf_load_ic_stub && GetPrototypeCheckCount(map, holder) >= 0) { |
1234 IsPrototypeValidityCellCheckEnough(map, holder)) { | |
1235 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); | 1286 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); |
1236 return SimpleLoadFromPrototype(map, holder, smi_handler); | 1287 return SimpleLoadFromPrototype(map, holder, lookup->name(), |
| 1288 smi_handler); |
1237 } | 1289 } |
1238 break; // Custom-compiled handler. | 1290 break; // Custom-compiled handler. |
1239 } | 1291 } |
1240 | 1292 |
1241 // -------------- Constant properties -------------- | 1293 // -------------- Constant properties -------------- |
1242 DCHECK(lookup->property_details().type() == DATA_CONSTANT); | 1294 DCHECK(lookup->property_details().type() == DATA_CONSTANT); |
1243 if (FLAG_tf_load_ic_stub) { | 1295 if (FLAG_tf_load_ic_stub) { |
1244 Handle<Object> smi_handler = | 1296 Handle<Object> smi_handler = |
1245 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); | 1297 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); |
1246 if (receiver_is_holder) { | 1298 if (receiver_is_holder) { |
1247 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); | 1299 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); |
1248 return smi_handler; | 1300 return smi_handler; |
1249 } | 1301 } |
1250 if (IsPrototypeValidityCellCheckEnough(map, holder)) { | 1302 if (GetPrototypeCheckCount(map, holder) >= 0) { |
1251 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); | 1303 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); |
1252 return SimpleLoadFromPrototype(map, holder, smi_handler); | 1304 return SimpleLoadFromPrototype(map, holder, lookup->name(), |
| 1305 smi_handler); |
1253 } | 1306 } |
1254 } else { | 1307 } else { |
1255 if (receiver_is_holder) { | 1308 if (receiver_is_holder) { |
1256 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); | 1309 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); |
1257 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); | 1310 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
1258 return stub.GetCode(); | 1311 return stub.GetCode(); |
1259 } | 1312 } |
1260 } | 1313 } |
1261 break; // Custom-compiled handler. | 1314 break; // Custom-compiled handler. |
1262 } | 1315 } |
(...skipping 1750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3013 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); | 3066 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); |
3014 it.Next(); | 3067 it.Next(); |
3015 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | 3068 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
3016 Object::GetProperty(&it)); | 3069 Object::GetProperty(&it)); |
3017 } | 3070 } |
3018 | 3071 |
3019 return *result; | 3072 return *result; |
3020 } | 3073 } |
3021 } // namespace internal | 3074 } // namespace internal |
3022 } // namespace v8 | 3075 } // namespace v8 |
OLD | NEW |