| 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 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 684 for (int current = 0; current < receiver_maps->length(); ++current) { | 684 for (int current = 0; current < receiver_maps->length(); ++current) { |
| 685 if (!receiver_maps->at(current).is_null() && | 685 if (!receiver_maps->at(current).is_null() && |
| 686 receiver_maps->at(current).is_identical_to(new_receiver_map)) { | 686 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
| 687 return false; | 687 return false; |
| 688 } | 688 } |
| 689 } | 689 } |
| 690 receiver_maps->Add(new_receiver_map); | 690 receiver_maps->Add(new_receiver_map); |
| 691 return true; | 691 return true; |
| 692 } | 692 } |
| 693 | 693 |
| 694 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) { | 694 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) { |
| 695 DCHECK(code->IsSmi() || code->IsCode()); | 695 DCHECK(IsHandler(*handler)); |
| 696 if (!code->IsSmi() && !Code::cast(*code)->is_handler()) { | |
| 697 return false; | |
| 698 } | |
| 699 if (is_keyed() && state() != RECOMPUTE_HANDLER) return false; | 696 if (is_keyed() && state() != RECOMPUTE_HANDLER) return false; |
| 700 Handle<Map> map = receiver_map(); | 697 Handle<Map> map = receiver_map(); |
| 701 MapHandleList maps; | 698 MapHandleList maps; |
| 702 List<Handle<Object>> handlers; | 699 List<Handle<Object>> handlers; |
| 703 | 700 |
| 704 TargetMaps(&maps); | 701 TargetMaps(&maps); |
| 705 int number_of_maps = maps.length(); | 702 int number_of_maps = maps.length(); |
| 706 int deprecated_maps = 0; | 703 int deprecated_maps = 0; |
| 707 int handler_to_overwrite = -1; | 704 int handler_to_overwrite = -1; |
| 708 | 705 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 728 if (number_of_valid_maps >= 4) return false; | 725 if (number_of_valid_maps >= 4) return false; |
| 729 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { | 726 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { |
| 730 return false; | 727 return false; |
| 731 } | 728 } |
| 732 DCHECK(UseVector()); | 729 DCHECK(UseVector()); |
| 733 if (!nexus()->FindHandlers(&handlers, maps.length())) return false; | 730 if (!nexus()->FindHandlers(&handlers, maps.length())) return false; |
| 734 | 731 |
| 735 number_of_valid_maps++; | 732 number_of_valid_maps++; |
| 736 if (number_of_valid_maps > 1 && is_keyed()) return false; | 733 if (number_of_valid_maps > 1 && is_keyed()) return false; |
| 737 if (number_of_valid_maps == 1) { | 734 if (number_of_valid_maps == 1) { |
| 738 ConfigureVectorState(name, receiver_map(), code); | 735 ConfigureVectorState(name, receiver_map(), handler); |
| 739 } else { | 736 } else { |
| 740 if (handler_to_overwrite >= 0) { | 737 if (handler_to_overwrite >= 0) { |
| 741 handlers.Set(handler_to_overwrite, code); | 738 handlers.Set(handler_to_overwrite, handler); |
| 742 if (!map.is_identical_to(maps.at(handler_to_overwrite))) { | 739 if (!map.is_identical_to(maps.at(handler_to_overwrite))) { |
| 743 maps.Set(handler_to_overwrite, map); | 740 maps.Set(handler_to_overwrite, map); |
| 744 } | 741 } |
| 745 } else { | 742 } else { |
| 746 maps.Add(map); | 743 maps.Add(map); |
| 747 handlers.Add(code); | 744 handlers.Add(handler); |
| 748 } | 745 } |
| 749 | 746 |
| 750 ConfigureVectorState(name, &maps, &handlers); | 747 ConfigureVectorState(name, &maps, &handlers); |
| 751 } | 748 } |
| 752 | 749 |
| 753 return true; | 750 return true; |
| 754 } | 751 } |
| 755 | 752 |
| 756 void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) { | 753 void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) { |
| 757 DCHECK(handler->IsSmi() || | 754 DCHECK(IsHandler(*handler)); |
| 758 (handler->IsCode() && Handle<Code>::cast(handler)->is_handler())); | |
| 759 ConfigureVectorState(name, receiver_map(), handler); | 755 ConfigureVectorState(name, receiver_map(), handler); |
| 760 } | 756 } |
| 761 | 757 |
| 762 | 758 |
| 763 void IC::CopyICToMegamorphicCache(Handle<Name> name) { | 759 void IC::CopyICToMegamorphicCache(Handle<Name> name) { |
| 764 MapHandleList maps; | 760 MapHandleList maps; |
| 765 List<Handle<Object>> handlers; | 761 List<Handle<Object>> handlers; |
| 766 TargetMaps(&maps); | 762 TargetMaps(&maps); |
| 767 if (!nexus()->FindHandlers(&handlers, maps.length())) return; | 763 if (!nexus()->FindHandlers(&handlers, maps.length())) return; |
| 768 for (int i = 0; i < maps.length(); i++) { | 764 for (int i = 0; i < maps.length(); i++) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 779 source_map->elements_kind(), target_elements_kind); | 775 source_map->elements_kind(), target_elements_kind); |
| 780 Map* transitioned_map = nullptr; | 776 Map* transitioned_map = nullptr; |
| 781 if (more_general_transition) { | 777 if (more_general_transition) { |
| 782 MapHandleList map_list; | 778 MapHandleList map_list; |
| 783 map_list.Add(handle(target_map)); | 779 map_list.Add(handle(target_map)); |
| 784 transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list); | 780 transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list); |
| 785 } | 781 } |
| 786 return transitioned_map == target_map; | 782 return transitioned_map == target_map; |
| 787 } | 783 } |
| 788 | 784 |
| 789 void IC::PatchCache(Handle<Name> name, Handle<Object> code) { | 785 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { |
| 790 DCHECK(code->IsCode() || (code->IsSmi() && (kind() == Code::LOAD_IC || | 786 DCHECK(IsHandler(*handler)); |
| 791 kind() == Code::KEYED_LOAD_IC))); | 787 // Currently only LoadIC and KeyedLoadIC support non-code handlers. |
| 788 DCHECK_IMPLIES(!handler->IsCode(), |
| 789 kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC); |
| 792 switch (state()) { | 790 switch (state()) { |
| 793 case UNINITIALIZED: | 791 case UNINITIALIZED: |
| 794 case PREMONOMORPHIC: | 792 case PREMONOMORPHIC: |
| 795 UpdateMonomorphicIC(code, name); | 793 UpdateMonomorphicIC(handler, name); |
| 796 break; | 794 break; |
| 797 case RECOMPUTE_HANDLER: | 795 case RECOMPUTE_HANDLER: |
| 798 case MONOMORPHIC: | 796 case MONOMORPHIC: |
| 799 if (kind() == Code::LOAD_GLOBAL_IC) { | 797 if (kind() == Code::LOAD_GLOBAL_IC) { |
| 800 UpdateMonomorphicIC(code, name); | 798 UpdateMonomorphicIC(handler, name); |
| 801 break; | 799 break; |
| 802 } | 800 } |
| 803 // Fall through. | 801 // Fall through. |
| 804 case POLYMORPHIC: | 802 case POLYMORPHIC: |
| 805 if (!is_keyed() || state() == RECOMPUTE_HANDLER) { | 803 if (!is_keyed() || state() == RECOMPUTE_HANDLER) { |
| 806 if (UpdatePolymorphicIC(name, code)) break; | 804 if (UpdatePolymorphicIC(name, handler)) break; |
| 807 // For keyed stubs, we can't know whether old handlers were for the | 805 // For keyed stubs, we can't know whether old handlers were for the |
| 808 // same key. | 806 // same key. |
| 809 CopyICToMegamorphicCache(name); | 807 CopyICToMegamorphicCache(name); |
| 810 } | 808 } |
| 811 DCHECK(UseVector()); | 809 DCHECK(UseVector()); |
| 812 ConfigureVectorState(MEGAMORPHIC, name); | 810 ConfigureVectorState(MEGAMORPHIC, name); |
| 813 // Fall through. | 811 // Fall through. |
| 814 case MEGAMORPHIC: | 812 case MEGAMORPHIC: |
| 815 UpdateMegamorphicCache(*receiver_map(), *name, *code); | 813 UpdateMegamorphicCache(*receiver_map(), *name, *handler); |
| 816 // Indicate that we've handled this case. | 814 // Indicate that we've handled this case. |
| 817 DCHECK(UseVector()); | 815 DCHECK(UseVector()); |
| 818 vector_set_ = true; | 816 vector_set_ = true; |
| 819 break; | 817 break; |
| 820 case GENERIC: | 818 case GENERIC: |
| 821 UNREACHABLE(); | 819 UNREACHABLE(); |
| 822 break; | 820 break; |
| 823 } | 821 } |
| 824 } | 822 } |
| 825 | 823 |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 case Code::KEYED_STORE_IC: | 955 case Code::KEYED_STORE_IC: |
| 958 return isolate()->store_stub_cache(); | 956 return isolate()->store_stub_cache(); |
| 959 | 957 |
| 960 default: | 958 default: |
| 961 break; | 959 break; |
| 962 } | 960 } |
| 963 UNREACHABLE(); | 961 UNREACHABLE(); |
| 964 return nullptr; | 962 return nullptr; |
| 965 } | 963 } |
| 966 | 964 |
| 967 void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* code) { | 965 void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) { |
| 968 if (code->IsSmi()) { | 966 stub_cache()->Set(name, map, handler); |
| 969 // TODO(jkummerow): Support Smis in the code cache. | |
| 970 Handle<Map> map_handle(map, isolate()); | |
| 971 Handle<Name> name_handle(name, isolate()); | |
| 972 FieldIndex index = | |
| 973 FieldIndex::ForLoadByFieldOffset(map, Smi::cast(code)->value()); | |
| 974 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); | |
| 975 LoadFieldStub stub(isolate(), index); | |
| 976 Code* handler = *stub.GetCode(); | |
| 977 stub_cache()->Set(*name_handle, *map_handle, handler); | |
| 978 return; | |
| 979 } | |
| 980 DCHECK(code->IsCode()); | |
| 981 stub_cache()->Set(name, map, Code::cast(code)); | |
| 982 } | 967 } |
| 983 | 968 |
| 984 Handle<Object> IC::ComputeHandler(LookupIterator* lookup, | 969 Handle<Object> IC::ComputeHandler(LookupIterator* lookup, |
| 985 Handle<Object> value) { | 970 Handle<Object> value) { |
| 986 // Try to find a globally shared handler stub. | 971 // Try to find a globally shared handler stub. |
| 987 Handle<Object> handler_or_index = GetMapIndependentHandler(lookup); | 972 Handle<Object> handler = GetMapIndependentHandler(lookup); |
| 988 if (!handler_or_index.is_null()) { | 973 if (!handler.is_null()) { |
| 989 DCHECK(handler_or_index->IsCode() || handler_or_index->IsSmi()); | 974 DCHECK(IC::IsHandler(*handler)); |
| 990 return handler_or_index; | 975 return handler; |
| 991 } | 976 } |
| 992 | 977 |
| 993 // Otherwise check the map's handler cache for a map-specific handler, and | 978 // Otherwise check the map's handler cache for a map-specific handler, and |
| 994 // compile one if the cache comes up empty. | 979 // compile one if the cache comes up empty. |
| 995 bool receiver_is_holder = | 980 bool receiver_is_holder = |
| 996 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); | 981 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); |
| 997 CacheHolderFlag flag; | 982 CacheHolderFlag flag; |
| 998 Handle<Map> stub_holder_map; | 983 Handle<Map> stub_holder_map; |
| 999 if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC || | 984 if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC || |
| 1000 kind() == Code::KEYED_LOAD_IC) { | 985 kind() == Code::KEYED_LOAD_IC) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1017 if (!handler.is_identical_to(code)) { | 1002 if (!handler.is_identical_to(code)) { |
| 1018 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); | 1003 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); |
| 1019 return code; | 1004 return code; |
| 1020 } | 1005 } |
| 1021 } else { | 1006 } else { |
| 1022 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. | 1007 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. |
| 1023 // In MEGAMORPHIC case, check if the handler in the megamorphic stub | 1008 // In MEGAMORPHIC case, check if the handler in the megamorphic stub |
| 1024 // cache (which just missed) is different from the cached handler. | 1009 // cache (which just missed) is different from the cached handler. |
| 1025 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { | 1010 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { |
| 1026 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); | 1011 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); |
| 1027 Code* megamorphic_cached_code = stub_cache()->Get(*lookup->name(), map); | 1012 Object* megamorphic_cached_handler = |
| 1028 if (megamorphic_cached_code != *code) { | 1013 stub_cache()->Get(*lookup->name(), map); |
| 1014 if (megamorphic_cached_handler != *code) { |
| 1029 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); | 1015 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); |
| 1030 return code; | 1016 return code; |
| 1031 } | 1017 } |
| 1032 } else { | 1018 } else { |
| 1033 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); | 1019 TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); |
| 1034 return code; | 1020 return code; |
| 1035 } | 1021 } |
| 1036 } | 1022 } |
| 1037 } | 1023 } |
| 1038 | 1024 |
| (...skipping 1874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2913 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); | 2899 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); |
| 2914 it.Next(); | 2900 it.Next(); |
| 2915 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | 2901 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, |
| 2916 Object::GetProperty(&it)); | 2902 Object::GetProperty(&it)); |
| 2917 } | 2903 } |
| 2918 | 2904 |
| 2919 return *result; | 2905 return *result; |
| 2920 } | 2906 } |
| 2921 } // namespace internal | 2907 } // namespace internal |
| 2922 } // namespace v8 | 2908 } // namespace v8 |
| OLD | NEW |