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 546 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 } | 557 } |
558 | 558 |
559 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, | 559 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, |
560 Handle<Object> handler) { | 560 Handle<Object> handler) { |
561 DCHECK(UseVector()); | 561 DCHECK(UseVector()); |
562 if (kind() == Code::LOAD_IC) { | 562 if (kind() == Code::LOAD_IC) { |
563 LoadICNexus* nexus = casted_nexus<LoadICNexus>(); | 563 LoadICNexus* nexus = casted_nexus<LoadICNexus>(); |
564 nexus->ConfigureMonomorphic(map, handler); | 564 nexus->ConfigureMonomorphic(map, handler); |
565 } else if (kind() == Code::LOAD_GLOBAL_IC) { | 565 } else if (kind() == Code::LOAD_GLOBAL_IC) { |
566 LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); | 566 LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>(); |
567 nexus->ConfigureHandlerMode(Handle<Code>::cast(handler)); | 567 nexus->ConfigureHandlerMode(handler); |
568 } else if (kind() == Code::KEYED_LOAD_IC) { | 568 } else if (kind() == Code::KEYED_LOAD_IC) { |
569 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); | 569 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); |
570 nexus->ConfigureMonomorphic(name, map, handler); | 570 nexus->ConfigureMonomorphic(name, map, handler); |
571 } else if (kind() == Code::STORE_IC) { | 571 } else if (kind() == Code::STORE_IC) { |
572 StoreICNexus* nexus = casted_nexus<StoreICNexus>(); | 572 StoreICNexus* nexus = casted_nexus<StoreICNexus>(); |
573 nexus->ConfigureMonomorphic(map, handler); | 573 nexus->ConfigureMonomorphic(map, handler); |
574 } else { | 574 } else { |
575 DCHECK(kind() == Code::KEYED_STORE_IC); | 575 DCHECK(kind() == Code::KEYED_STORE_IC); |
576 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); | 576 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); |
577 nexus->ConfigureMonomorphic(name, map, handler); | 577 nexus->ConfigureMonomorphic(name, map, handler); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
787 map_list.Add(handle(target_map)); | 787 map_list.Add(handle(target_map)); |
788 transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list); | 788 transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list); |
789 } | 789 } |
790 return transitioned_map == target_map; | 790 return transitioned_map == target_map; |
791 } | 791 } |
792 | 792 |
793 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { | 793 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { |
794 DCHECK(IsHandler(*handler)); | 794 DCHECK(IsHandler(*handler)); |
795 // Currently only LoadIC and KeyedLoadIC support non-code handlers. | 795 // Currently only LoadIC and KeyedLoadIC support non-code handlers. |
796 DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC || | 796 DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC || |
| 797 kind() == Code::LOAD_GLOBAL_IC || |
797 kind() == Code::KEYED_LOAD_IC || | 798 kind() == Code::KEYED_LOAD_IC || |
798 kind() == Code::STORE_IC || | 799 kind() == Code::STORE_IC || |
799 kind() == Code::KEYED_STORE_IC); | 800 kind() == Code::KEYED_STORE_IC); |
800 switch (state()) { | 801 switch (state()) { |
801 case UNINITIALIZED: | 802 case UNINITIALIZED: |
802 case PREMONOMORPHIC: | 803 case PREMONOMORPHIC: |
803 UpdateMonomorphicIC(handler, name); | 804 UpdateMonomorphicIC(handler, name); |
804 break; | 805 break; |
805 case RECOMPUTE_HANDLER: | 806 case RECOMPUTE_HANDLER: |
806 case MONOMORPHIC: | 807 case MONOMORPHIC: |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 } | 852 } |
852 | 853 |
853 namespace { | 854 namespace { |
854 | 855 |
855 template <bool fill_array = true> | 856 template <bool fill_array = true> |
856 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, | 857 int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map, |
857 Handle<JSObject> holder, Handle<FixedArray> array, | 858 Handle<JSObject> holder, Handle<FixedArray> array, |
858 Handle<Name> name, int first_index) { | 859 Handle<Name> name, int first_index) { |
859 DCHECK(holder.is_null() || holder->HasFastProperties()); | 860 DCHECK(holder.is_null() || holder->HasFastProperties()); |
860 | 861 |
861 // The following kinds of receiver maps require custom handler compilation. | |
862 if (receiver_map->IsJSGlobalObjectMap()) { | |
863 return -1; | |
864 } | |
865 // 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 |
866 // passed the access check for current native context and the access | 863 // passed the access check for current native context and the access |
867 // can't be revoked. | 864 // can't be revoked. |
868 | 865 |
869 HandleScope scope(isolate); | 866 HandleScope scope(isolate); |
870 int checks_count = 0; | 867 int checks_count = 0; |
871 | 868 |
872 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { | 869 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { |
873 // The validity cell check for primitive and global proxy receivers does | 870 // The validity cell check for primitive and global proxy receivers does |
874 // not guarantee that certain native context ever had access to other | 871 // not guarantee that certain native context ever had access to other |
875 // native context. However, a handler created for one native context could | 872 // native context. However, a handler created for one native context could |
876 // be used in other native context through the megamorphic stub cache. | 873 // be used in other native context through the megamorphic stub cache. |
877 // So we record the original native context to which this handler | 874 // So we record the original native context to which this handler |
878 // corresponds. | 875 // corresponds. |
879 if (fill_array) { | 876 if (fill_array) { |
880 Handle<Context> native_context = isolate->native_context(); | 877 Handle<Context> native_context = isolate->native_context(); |
881 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, | 878 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, |
882 native_context->self_weak_cell()); | 879 native_context->self_weak_cell()); |
883 } | 880 } |
884 checks_count++; | 881 checks_count++; |
| 882 |
| 883 } else if (receiver_map->IsJSGlobalObjectMap()) { |
| 884 if (fill_array) { |
| 885 Handle<JSGlobalObject> global = isolate->global_object(); |
| 886 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( |
| 887 global, name, PropertyCellType::kInvalidated); |
| 888 DCHECK(cell->value()->IsTheHole(isolate)); |
| 889 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); |
| 890 array->set(LoadHandler::kFirstPrototypeIndex + checks_count, *weak_cell); |
| 891 } |
| 892 checks_count++; |
885 } | 893 } |
886 | 894 |
887 // Create/count entries for each global or dictionary prototype appeared in | 895 // Create/count entries for each global or dictionary prototype appeared in |
888 // the prototype chain contains from receiver till holder. | 896 // the prototype chain contains from receiver till holder. |
889 for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { | 897 for (PrototypeIterator iter(receiver_map); !iter.IsAtEnd(); iter.Advance()) { |
890 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); | 898 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter); |
891 if (holder.is_identical_to(current)) break; | 899 if (holder.is_identical_to(current)) break; |
892 Handle<Map> current_map(current->map(), isolate); | 900 Handle<Map> current_map(current->map(), isolate); |
893 | 901 |
894 if (current_map->IsJSGlobalObjectMap()) { | 902 if (current_map->IsJSGlobalObjectMap()) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
930 } | 938 } |
931 | 939 |
932 } // namespace | 940 } // namespace |
933 | 941 |
934 Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, | 942 Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map, |
935 Handle<JSObject> holder, | 943 Handle<JSObject> holder, |
936 Handle<Name> name, | 944 Handle<Name> name, |
937 Handle<Object> smi_handler) { | 945 Handle<Object> smi_handler) { |
938 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); | 946 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); |
939 DCHECK_LE(0, checks_count); | 947 DCHECK_LE(0, checks_count); |
940 DCHECK(!receiver_map->IsJSGlobalObjectMap()); | |
941 | 948 |
942 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { | 949 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { |
943 DCHECK(!receiver_map->is_dictionary_map()); | 950 DCHECK(!receiver_map->is_dictionary_map()); |
944 DCHECK_LE(1, checks_count); // For native context. | 951 DCHECK_LE(1, checks_count); // For native context. |
945 smi_handler = | 952 smi_handler = |
946 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); | 953 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); |
947 } else if (receiver_map->is_dictionary_map()) { | 954 } else if (receiver_map->is_dictionary_map() && |
| 955 !receiver_map->IsJSGlobalObjectMap()) { |
948 smi_handler = | 956 smi_handler = |
949 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); | 957 LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler); |
950 } | 958 } |
951 | 959 |
952 Handle<Cell> validity_cell = | 960 Handle<Cell> validity_cell = |
953 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 961 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
954 DCHECK(!validity_cell.is_null()); | 962 DCHECK(!validity_cell.is_null()); |
955 | 963 |
956 Handle<WeakCell> holder_cell = | 964 Handle<WeakCell> holder_cell = |
957 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); | 965 Map::GetOrCreatePrototypeWeakCell(holder, isolate()); |
(...skipping 10 matching lines...) Expand all Loading... |
968 InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name, | 976 InitPrototypeChecks(isolate(), receiver_map, holder, handler_array, name, |
969 LoadHandler::kFirstPrototypeIndex); | 977 LoadHandler::kFirstPrototypeIndex); |
970 return handler_array; | 978 return handler_array; |
971 } | 979 } |
972 | 980 |
973 Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, | 981 Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map, |
974 Handle<Name> name) { | 982 Handle<Name> name) { |
975 Handle<JSObject> holder; // null handle | 983 Handle<JSObject> holder; // null handle |
976 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); | 984 int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, holder); |
977 DCHECK_LE(0, checks_count); | 985 DCHECK_LE(0, checks_count); |
978 DCHECK(!receiver_map->IsJSGlobalObjectMap()); | |
979 | 986 |
980 Handle<Object> smi_handler = LoadHandler::LoadNonExistent( | 987 Handle<Object> smi_handler = LoadHandler::LoadNonExistent( |
981 isolate(), receiver_map->is_dictionary_map()); | 988 isolate(), receiver_map->is_dictionary_map()); |
982 | 989 |
983 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { | 990 if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) { |
984 DCHECK(!receiver_map->is_dictionary_map()); | 991 DCHECK(!receiver_map->is_dictionary_map()); |
985 DCHECK_LE(1, checks_count); // For native context. | 992 DCHECK_LE(1, checks_count); // For native context. |
986 smi_handler = | 993 smi_handler = |
987 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); | 994 LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler); |
988 } | 995 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1059 ConfigureVectorState(PREMONOMORPHIC, Handle<Object>()); | 1066 ConfigureVectorState(PREMONOMORPHIC, Handle<Object>()); |
1060 TRACE_IC("LoadIC", lookup->name()); | 1067 TRACE_IC("LoadIC", lookup->name()); |
1061 return; | 1068 return; |
1062 } | 1069 } |
1063 | 1070 |
1064 Handle<Object> code; | 1071 Handle<Object> code; |
1065 if (lookup->state() == LookupIterator::JSPROXY || | 1072 if (lookup->state() == LookupIterator::JSPROXY || |
1066 lookup->state() == LookupIterator::ACCESS_CHECK) { | 1073 lookup->state() == LookupIterator::ACCESS_CHECK) { |
1067 code = slow_stub(); | 1074 code = slow_stub(); |
1068 } else if (!lookup->IsFound()) { | 1075 } else if (!lookup->IsFound()) { |
1069 if (kind() == Code::LOAD_IC) { | 1076 if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) { |
1070 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); | 1077 if (FLAG_tf_load_ic_stub) { |
1071 code = LoadNonExistent(receiver_map(), lookup->name()); | 1078 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); |
1072 } else if (kind() == Code::LOAD_GLOBAL_IC) { | 1079 code = LoadNonExistent(receiver_map(), lookup->name()); |
1073 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), | 1080 } else { |
1074 receiver_map()); | 1081 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), |
1075 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. | 1082 receiver_map()); |
1076 if (code.is_null()) code = slow_stub(); | 1083 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. |
| 1084 if (code.is_null()) code = slow_stub(); |
| 1085 } |
1077 } else { | 1086 } else { |
1078 code = slow_stub(); | 1087 code = slow_stub(); |
1079 } | 1088 } |
1080 } else { | 1089 } else { |
1081 if (kind() == Code::LOAD_GLOBAL_IC && | 1090 if (kind() == Code::LOAD_GLOBAL_IC && |
1082 lookup->state() == LookupIterator::DATA && | 1091 lookup->state() == LookupIterator::DATA && |
1083 lookup->GetHolder<Object>()->IsJSGlobalObject()) { | 1092 lookup->GetHolder<Object>()->IsJSGlobalObject()) { |
1084 #if DEBUG | 1093 #if DEBUG |
1085 Handle<Object> holder = lookup->GetHolder<Object>(); | 1094 Handle<Object> holder = lookup->GetHolder<Object>(); |
1086 Handle<Object> receiver = lookup->GetReceiver(); | 1095 Handle<Object> receiver = lookup->GetReceiver(); |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1394 return isolate()->builtins()->LoadIC_Normal(); | 1403 return isolate()->builtins()->LoadIC_Normal(); |
1395 } | 1404 } |
1396 | 1405 |
1397 // -------------- Fields -------------- | 1406 // -------------- Fields -------------- |
1398 if (lookup->property_details().type() == DATA) { | 1407 if (lookup->property_details().type() == DATA) { |
1399 FieldIndex field = lookup->GetFieldIndex(); | 1408 FieldIndex field = lookup->GetFieldIndex(); |
1400 Handle<Object> smi_handler = SimpleFieldLoad(field); | 1409 Handle<Object> smi_handler = SimpleFieldLoad(field); |
1401 if (receiver_is_holder) { | 1410 if (receiver_is_holder) { |
1402 return smi_handler; | 1411 return smi_handler; |
1403 } | 1412 } |
1404 if (FLAG_tf_load_ic_stub && kind() != Code::LOAD_GLOBAL_IC) { | 1413 if (FLAG_tf_load_ic_stub) { |
1405 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); | 1414 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); |
1406 return LoadFromPrototype(map, holder, lookup->name(), smi_handler); | 1415 return LoadFromPrototype(map, holder, lookup->name(), smi_handler); |
1407 } | 1416 } |
1408 break; // Custom-compiled handler. | 1417 break; // Custom-compiled handler. |
1409 } | 1418 } |
1410 | 1419 |
1411 // -------------- Constant properties -------------- | 1420 // -------------- Constant properties -------------- |
1412 DCHECK(lookup->property_details().type() == DATA_CONSTANT); | 1421 DCHECK(lookup->property_details().type() == DATA_CONSTANT); |
1413 if (FLAG_tf_load_ic_stub) { | 1422 if (FLAG_tf_load_ic_stub) { |
1414 Handle<Object> smi_handler = | 1423 Handle<Object> smi_handler = |
1415 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); | 1424 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); |
1416 if (receiver_is_holder) { | 1425 if (receiver_is_holder) { |
1417 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); | 1426 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); |
1418 return smi_handler; | 1427 return smi_handler; |
1419 } | 1428 } |
1420 if (kind() != Code::LOAD_GLOBAL_IC) { | 1429 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); |
1421 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); | 1430 return LoadFromPrototype(map, holder, lookup->name(), smi_handler); |
1422 return LoadFromPrototype(map, holder, lookup->name(), smi_handler); | |
1423 } | |
1424 } else { | 1431 } else { |
1425 if (receiver_is_holder) { | 1432 if (receiver_is_holder) { |
1426 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); | 1433 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub); |
1427 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); | 1434 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
1428 return stub.GetCode(); | 1435 return stub.GetCode(); |
1429 } | 1436 } |
1430 } | 1437 } |
1431 break; // Custom-compiled handler. | 1438 break; // Custom-compiled handler. |
1432 } | 1439 } |
1433 | 1440 |
(...skipping 1806 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3240 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); | 3247 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); |
3241 it.Next(); | 3248 it.Next(); |
3242 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | 3249 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
3243 Object::GetProperty(&it)); | 3250 Object::GetProperty(&it)); |
3244 } | 3251 } |
3245 | 3252 |
3246 return *result; | 3253 return *result; |
3247 } | 3254 } |
3248 } // namespace internal | 3255 } // namespace internal |
3249 } // namespace v8 | 3256 } // namespace v8 |
OLD | NEW |