| 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 |