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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/api.h" | 8 #include "src/api.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 Code* IC::GetOriginalCode() const { | 195 Code* IC::GetOriginalCode() const { |
196 HandleScope scope(isolate()); | 196 HandleScope scope(isolate()); |
197 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); | 197 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); |
198 DCHECK(Debug::HasDebugInfo(shared)); | 198 DCHECK(Debug::HasDebugInfo(shared)); |
199 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); | 199 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); |
200 DCHECK(original_code->IsCode()); | 200 DCHECK(original_code->IsCode()); |
201 return original_code; | 201 return original_code; |
202 } | 202 } |
203 | 203 |
204 | 204 |
205 static bool HasInterceptorSetter(JSObject* object) { | |
206 return !object->GetNamedInterceptor()->setter()->IsUndefined(); | |
207 } | |
208 | |
209 | |
210 static void LookupForRead(LookupIterator* it) { | 205 static void LookupForRead(LookupIterator* it) { |
211 for (; it->IsFound(); it->Next()) { | 206 for (; it->IsFound(); it->Next()) { |
212 switch (it->state()) { | 207 switch (it->state()) { |
213 case LookupIterator::NOT_FOUND: | 208 case LookupIterator::NOT_FOUND: |
| 209 case LookupIterator::TRANSITION: |
214 UNREACHABLE(); | 210 UNREACHABLE(); |
215 case LookupIterator::JSPROXY: | 211 case LookupIterator::JSPROXY: |
216 return; | 212 return; |
217 case LookupIterator::INTERCEPTOR: { | 213 case LookupIterator::INTERCEPTOR: { |
218 // If there is a getter, return; otherwise loop to perform the lookup. | 214 // If there is a getter, return; otherwise loop to perform the lookup. |
219 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 215 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
220 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { | 216 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { |
221 return; | 217 return; |
222 } | 218 } |
223 break; | 219 break; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 if (!name->IsName()) return false; | 291 if (!name->IsName()) return false; |
296 Name* stub_name = target()->FindFirstName(); | 292 Name* stub_name = target()->FindFirstName(); |
297 if (*name != stub_name) return false; | 293 if (*name != stub_name) return false; |
298 } | 294 } |
299 | 295 |
300 return true; | 296 return true; |
301 } | 297 } |
302 | 298 |
303 | 299 |
304 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { | 300 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
305 receiver_type_ = CurrentTypeOf(receiver, isolate()); | 301 update_receiver_type(receiver); |
306 if (!name->IsString()) return; | 302 if (!name->IsString()) return; |
307 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; | 303 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; |
308 if (receiver->IsUndefined() || receiver->IsNull()) return; | 304 if (receiver->IsUndefined() || receiver->IsNull()) return; |
309 | 305 |
310 // Remove the target from the code cache if it became invalid | 306 // Remove the target from the code cache if it became invalid |
311 // because of changes in the prototype chain to avoid hitting it | 307 // because of changes in the prototype chain to avoid hitting it |
312 // again. | 308 // again. |
313 if (TryRemoveInvalidPrototypeDependentStub(receiver, | 309 if (TryRemoveInvalidPrototypeDependentStub(receiver, |
314 Handle<String>::cast(name))) { | 310 Handle<String>::cast(name))) { |
315 MarkPrototypeFailure(name); | 311 MarkPrototypeFailure(name); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
614 Object); | 610 Object); |
615 return result; | 611 return result; |
616 } | 612 } |
617 | 613 |
618 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; | 614 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
619 | 615 |
620 // Named lookup in the object. | 616 // Named lookup in the object. |
621 LookupIterator it(object, name); | 617 LookupIterator it(object, name); |
622 LookupForRead(&it); | 618 LookupForRead(&it); |
623 | 619 |
624 // If we did not find a property, check if we need to throw an exception. | 620 if (it.IsFound() || !IsUndeclaredGlobal(object)) { |
625 if (!it.IsFound()) { | 621 // Update inline cache and stub cache. |
626 if (IsUndeclaredGlobal(object)) { | 622 if (use_ic) UpdateCaches(&it); |
627 return ReferenceError("not_defined", name); | 623 |
| 624 // Get the property. |
| 625 Handle<Object> result; |
| 626 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it), |
| 627 Object); |
| 628 if (it.IsFound()) { |
| 629 return result; |
| 630 } else if (!IsUndeclaredGlobal(object)) { |
| 631 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 632 return result; |
628 } | 633 } |
629 LOG(isolate(), SuspectReadEvent(*name, *object)); | |
630 } | 634 } |
631 | 635 return ReferenceError("not_defined", name); |
632 // Update inline cache and stub cache. | |
633 if (use_ic) UpdateCaches(&it, object, name); | |
634 | |
635 // Get the property. | |
636 Handle<Object> result; | |
637 ASSIGN_RETURN_ON_EXCEPTION( | |
638 isolate(), result, Object::GetProperty(&it), Object); | |
639 // If the property is not present, check if we need to throw an exception. | |
640 if (!it.IsFound() && IsUndeclaredGlobal(object)) { | |
641 return ReferenceError("not_defined", name); | |
642 } | |
643 | |
644 return result; | |
645 } | 636 } |
646 | 637 |
647 | 638 |
648 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, | 639 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
649 Handle<Map> new_receiver_map) { | 640 Handle<Map> new_receiver_map) { |
650 DCHECK(!new_receiver_map.is_null()); | 641 DCHECK(!new_receiver_map.is_null()); |
651 for (int current = 0; current < receiver_maps->length(); ++current) { | 642 for (int current = 0; current < receiver_maps->length(); ++current) { |
652 if (!receiver_maps->at(current).is_null() && | 643 if (!receiver_maps->at(current).is_null() && |
653 receiver_maps->at(current).is_identical_to(new_receiver_map)) { | 644 receiver_maps->at(current).is_identical_to(new_receiver_map)) { |
654 return false; | 645 return false; |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 } | 855 } |
865 } | 856 } |
866 | 857 |
867 | 858 |
868 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) { | 859 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) { |
869 LoadFieldStub stub(isolate(), index); | 860 LoadFieldStub stub(isolate(), index); |
870 return stub.GetCode(); | 861 return stub.GetCode(); |
871 } | 862 } |
872 | 863 |
873 | 864 |
874 void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object, | 865 void LoadIC::UpdateCaches(LookupIterator* lookup) { |
875 Handle<Name> name) { | |
876 if (state() == UNINITIALIZED) { | 866 if (state() == UNINITIALIZED) { |
877 // This is the first time we execute this inline cache. | 867 // This is the first time we execute this inline cache. Set the target to |
878 // Set the target to the pre monomorphic stub to delay | 868 // the pre monomorphic stub to delay setting the monomorphic state. |
879 // setting the monomorphic state. | |
880 set_target(*pre_monomorphic_stub()); | 869 set_target(*pre_monomorphic_stub()); |
881 TRACE_IC("LoadIC", name); | 870 TRACE_IC("LoadIC", lookup->name()); |
882 return; | 871 return; |
883 } | 872 } |
884 | 873 |
885 Handle<Code> code; | 874 Handle<Code> code; |
886 if (lookup->state() == LookupIterator::JSPROXY || | 875 if (lookup->state() == LookupIterator::JSPROXY || |
887 lookup->state() == LookupIterator::ACCESS_CHECK) { | 876 lookup->state() == LookupIterator::ACCESS_CHECK) { |
888 code = slow_stub(); | 877 code = slow_stub(); |
889 } else if (!lookup->IsFound()) { | 878 } else if (!lookup->IsFound()) { |
890 if (kind() == Code::LOAD_IC) { | 879 if (kind() == Code::LOAD_IC) { |
891 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name, | 880 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), |
892 receiver_type()); | 881 receiver_type()); |
893 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. | 882 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. |
894 if (code.is_null()) code = slow_stub(); | 883 if (code.is_null()) code = slow_stub(); |
895 } else { | 884 } else { |
896 code = slow_stub(); | 885 code = slow_stub(); |
897 } | 886 } |
898 } else { | 887 } else { |
899 code = ComputeHandler(lookup, object, name); | 888 code = ComputeHandler(lookup); |
900 } | 889 } |
901 | 890 |
902 PatchCache(name, code); | 891 PatchCache(lookup->name(), code); |
903 TRACE_IC("LoadIC", name); | 892 TRACE_IC("LoadIC", lookup->name()); |
904 } | 893 } |
905 | 894 |
906 | 895 |
907 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) { | 896 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) { |
908 if (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC) return; | 897 if (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC) return; |
909 Map* map = *TypeToMap(type, isolate()); | 898 Map* map = *TypeToMap(type, isolate()); |
910 isolate()->stub_cache()->Set(name, map, code); | 899 isolate()->stub_cache()->Set(name, map, code); |
911 } | 900 } |
912 | 901 |
913 | 902 |
914 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object, | 903 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) { |
915 Handle<Name> name, Handle<Object> value) { | |
916 bool receiver_is_holder = | 904 bool receiver_is_holder = |
917 object.is_identical_to(lookup->GetHolder<JSObject>()); | 905 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); |
918 CacheHolderFlag flag; | 906 CacheHolderFlag flag; |
919 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( | 907 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( |
920 *receiver_type(), receiver_is_holder, isolate(), &flag); | 908 *receiver_type(), receiver_is_holder, isolate(), &flag); |
921 | 909 |
922 Handle<Code> code = PropertyHandlerCompiler::Find( | 910 Handle<Code> code = PropertyHandlerCompiler::Find( |
923 name, stub_holder_map, kind(), flag, | 911 lookup->name(), stub_holder_map, kind(), flag, |
924 lookup->holder_map()->is_dictionary_map() ? Code::NORMAL : Code::FAST); | 912 lookup->holder_map()->is_dictionary_map() ? Code::NORMAL : Code::FAST); |
925 // Use the cached value if it exists, and if it is different from the | 913 // Use the cached value if it exists, and if it is different from the |
926 // handler that just missed. | 914 // handler that just missed. |
927 if (!code.is_null()) { | 915 if (!code.is_null()) { |
928 if (!maybe_handler_.is_null() && | 916 if (!maybe_handler_.is_null() && |
929 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { | 917 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { |
930 return code; | 918 return code; |
931 } | 919 } |
932 if (maybe_handler_.is_null()) { | 920 if (maybe_handler_.is_null()) { |
933 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. | 921 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. |
934 // In MEGAMORPHIC case, check if the handler in the megamorphic stub | 922 // In MEGAMORPHIC case, check if the handler in the megamorphic stub |
935 // cache (which just missed) is different from the cached handler. | 923 // cache (which just missed) is different from the cached handler. |
936 if (state() == MEGAMORPHIC && object->IsHeapObject()) { | 924 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { |
937 Map* map = Handle<HeapObject>::cast(object)->map(); | 925 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); |
938 Code* megamorphic_cached_code = | 926 Code* megamorphic_cached_code = |
939 isolate()->stub_cache()->Get(*name, map, code->flags()); | 927 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags()); |
940 if (megamorphic_cached_code != *code) return code; | 928 if (megamorphic_cached_code != *code) return code; |
941 } else { | 929 } else { |
942 return code; | 930 return code; |
943 } | |
944 } | |
945 } | |
946 | |
947 code = CompileHandler(lookup, object, name, value, flag); | |
948 DCHECK(code->is_handler()); | |
949 | |
950 if (code->type() != Code::NORMAL) { | |
951 Map::UpdateCodeCache(stub_holder_map, name, code); | |
952 } | |
953 | |
954 return code; | |
955 } | |
956 | |
957 | |
958 Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup, | |
959 Handle<Object> object, Handle<Name> name, | |
960 Handle<Object> value) { | |
961 bool receiver_is_holder = lookup->ReceiverIsHolder(object); | |
962 CacheHolderFlag flag; | |
963 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( | |
964 *receiver_type(), receiver_is_holder, isolate(), &flag); | |
965 | |
966 Handle<Code> code = PropertyHandlerCompiler::Find( | |
967 name, stub_holder_map, handler_kind(), flag, | |
968 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL); | |
969 // Use the cached value if it exists, and if it is different from the | |
970 // handler that just missed. | |
971 if (!code.is_null()) { | |
972 if (!maybe_handler_.is_null() && | |
973 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { | |
974 return code; | |
975 } | |
976 if (maybe_handler_.is_null()) { | |
977 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. | |
978 // In MEGAMORPHIC case, check if the handler in the megamorphic stub | |
979 // cache (which just missed) is different from the cached handler. | |
980 if (state() == MEGAMORPHIC && object->IsHeapObject()) { | |
981 Map* map = Handle<HeapObject>::cast(object)->map(); | |
982 Code* megamorphic_cached_code = | |
983 isolate()->stub_cache()->Get(*name, map, code->flags()); | |
984 if (megamorphic_cached_code != *code) return code; | |
985 } else { | |
986 return code; | |
987 } | 931 } |
988 } | 932 } |
989 } | 933 } |
990 | 934 |
991 code = CompileStoreHandler(lookup, object, name, value, flag); | 935 code = CompileHandler(lookup, value, flag); |
992 DCHECK(code->is_handler()); | 936 DCHECK(code->is_handler()); |
993 | 937 |
994 if (code->type() != Code::NORMAL) { | 938 if (code->type() != Code::NORMAL) { |
995 Map::UpdateCodeCache(stub_holder_map, name, code); | 939 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); |
996 } | 940 } |
997 | 941 |
998 return code; | 942 return code; |
999 } | 943 } |
1000 | 944 |
1001 | 945 |
1002 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, | 946 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, |
1003 Handle<Object> object, Handle<Name> name, | |
1004 Handle<Object> unused, | 947 Handle<Object> unused, |
1005 CacheHolderFlag cache_holder) { | 948 CacheHolderFlag cache_holder) { |
1006 if (object->IsString() && | 949 Handle<Object> receiver = lookup->GetReceiver(); |
1007 Name::Equals(isolate()->factory()->length_string(), name)) { | 950 if (receiver->IsString() && |
| 951 Name::Equals(isolate()->factory()->length_string(), lookup->name())) { |
1008 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); | 952 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); |
1009 return SimpleFieldLoad(index); | 953 return SimpleFieldLoad(index); |
1010 } | 954 } |
1011 | 955 |
1012 if (object->IsStringWrapper() && | 956 if (receiver->IsStringWrapper() && |
1013 Name::Equals(isolate()->factory()->length_string(), name)) { | 957 Name::Equals(isolate()->factory()->length_string(), lookup->name())) { |
1014 StringLengthStub string_length_stub(isolate()); | 958 StringLengthStub string_length_stub(isolate()); |
1015 return string_length_stub.GetCode(); | 959 return string_length_stub.GetCode(); |
1016 } | 960 } |
1017 | 961 |
1018 // Use specialized code for getting prototype of functions. | 962 // Use specialized code for getting prototype of functions. |
1019 if (object->IsJSFunction() && | 963 if (receiver->IsJSFunction() && |
1020 Name::Equals(isolate()->factory()->prototype_string(), name) && | 964 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) && |
1021 Handle<JSFunction>::cast(object)->should_have_prototype() && | 965 Handle<JSFunction>::cast(receiver)->should_have_prototype() && |
1022 !Handle<JSFunction>::cast(object)->map()->has_non_instance_prototype()) { | 966 !Handle<JSFunction>::cast(receiver) |
| 967 ->map() |
| 968 ->has_non_instance_prototype()) { |
1023 Handle<Code> stub; | 969 Handle<Code> stub; |
1024 FunctionPrototypeStub function_prototype_stub(isolate()); | 970 FunctionPrototypeStub function_prototype_stub(isolate()); |
1025 return function_prototype_stub.GetCode(); | 971 return function_prototype_stub.GetCode(); |
1026 } | 972 } |
1027 | 973 |
1028 Handle<HeapType> type = receiver_type(); | 974 Handle<HeapType> type = receiver_type(); |
1029 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); | 975 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
1030 bool receiver_is_holder = object.is_identical_to(holder); | 976 bool receiver_is_holder = receiver.is_identical_to(holder); |
1031 // -------------- Interceptors -------------- | 977 // -------------- Interceptors -------------- |
1032 if (lookup->state() == LookupIterator::INTERCEPTOR) { | 978 if (lookup->state() == LookupIterator::INTERCEPTOR) { |
1033 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 979 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1034 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 980 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1035 cache_holder); | 981 cache_holder); |
1036 // Perform a lookup behind the interceptor. Copy the LookupIterator since | 982 // Perform a lookup behind the interceptor. Copy the LookupIterator since |
1037 // the original iterator will be used to fetch the value. | 983 // the original iterator will be used to fetch the value. |
1038 LookupIterator it(lookup); | 984 LookupIterator it(lookup); |
1039 it.Next(); | 985 it.Next(); |
1040 LookupForRead(&it); | 986 LookupForRead(&it); |
1041 return compiler.CompileLoadInterceptor(&it, name); | 987 return compiler.CompileLoadInterceptor(&it); |
1042 } | 988 } |
1043 DCHECK(lookup->state() == LookupIterator::PROPERTY); | |
1044 | 989 |
1045 // -------------- Accessors -------------- | 990 // -------------- Accessors -------------- |
| 991 DCHECK(lookup->state() == LookupIterator::PROPERTY); |
1046 if (lookup->property_kind() == LookupIterator::ACCESSOR) { | 992 if (lookup->property_kind() == LookupIterator::ACCESSOR) { |
1047 // Use simple field loads for some well-known callback properties. | 993 // Use simple field loads for some well-known callback properties. |
1048 if (receiver_is_holder) { | 994 if (receiver_is_holder) { |
1049 DCHECK(object->IsJSObject()); | 995 DCHECK(receiver->IsJSObject()); |
1050 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 996 Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); |
1051 int object_offset; | 997 int object_offset; |
1052 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name, | 998 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(), |
1053 &object_offset)) { | 999 &object_offset)) { |
1054 FieldIndex index = | 1000 FieldIndex index = |
1055 FieldIndex::ForInObjectOffset(object_offset, receiver->map()); | 1001 FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); |
1056 return SimpleFieldLoad(index); | 1002 return SimpleFieldLoad(index); |
1057 } | 1003 } |
1058 } | 1004 } |
1059 | 1005 |
1060 Handle<Object> accessors = lookup->GetAccessors(); | 1006 Handle<Object> accessors = lookup->GetAccessors(); |
1061 if (accessors->IsExecutableAccessorInfo()) { | 1007 if (accessors->IsExecutableAccessorInfo()) { |
1062 Handle<ExecutableAccessorInfo> info = | 1008 Handle<ExecutableAccessorInfo> info = |
1063 Handle<ExecutableAccessorInfo>::cast(accessors); | 1009 Handle<ExecutableAccessorInfo>::cast(accessors); |
1064 if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub(); | 1010 if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub(); |
1065 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, | 1011 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
1066 type)) { | 1012 type)) { |
1067 return slow_stub(); | 1013 return slow_stub(); |
1068 } | 1014 } |
1069 if (!holder->HasFastProperties()) return slow_stub(); | 1015 if (!holder->HasFastProperties()) return slow_stub(); |
1070 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1016 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1071 cache_holder); | 1017 cache_holder); |
1072 return compiler.CompileLoadCallback(name, info); | 1018 return compiler.CompileLoadCallback(lookup->name(), info); |
1073 } | 1019 } |
1074 if (accessors->IsAccessorPair()) { | 1020 if (accessors->IsAccessorPair()) { |
1075 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), | 1021 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), |
1076 isolate()); | 1022 isolate()); |
1077 if (!getter->IsJSFunction()) return slow_stub(); | 1023 if (!getter->IsJSFunction()) return slow_stub(); |
1078 if (!holder->HasFastProperties()) return slow_stub(); | 1024 if (!holder->HasFastProperties()) return slow_stub(); |
1079 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | 1025 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
1080 if (!object->IsJSObject() && !function->IsBuiltin() && | 1026 if (!receiver->IsJSObject() && !function->IsBuiltin() && |
1081 function->shared()->strict_mode() == SLOPPY) { | 1027 function->shared()->strict_mode() == SLOPPY) { |
1082 // Calling sloppy non-builtins with a value as the receiver | 1028 // Calling sloppy non-builtins with a value as the receiver |
1083 // requires boxing. | 1029 // requires boxing. |
1084 return slow_stub(); | 1030 return slow_stub(); |
1085 } | 1031 } |
1086 CallOptimization call_optimization(function); | 1032 CallOptimization call_optimization(function); |
1087 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1033 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1088 cache_holder); | 1034 cache_holder); |
1089 if (call_optimization.is_simple_api_call() && | 1035 if (call_optimization.is_simple_api_call() && |
1090 call_optimization.IsCompatibleReceiver(object, holder)) { | 1036 call_optimization.IsCompatibleReceiver(receiver, holder)) { |
1091 return compiler.CompileLoadCallback(name, call_optimization); | 1037 return compiler.CompileLoadCallback(lookup->name(), call_optimization); |
1092 } | 1038 } |
1093 return compiler.CompileLoadViaGetter(name, function); | 1039 return compiler.CompileLoadViaGetter(lookup->name(), function); |
1094 } | 1040 } |
1095 // TODO(dcarney): Handle correctly. | 1041 // TODO(dcarney): Handle correctly. |
1096 DCHECK(accessors->IsDeclaredAccessorInfo()); | 1042 DCHECK(accessors->IsDeclaredAccessorInfo()); |
1097 return slow_stub(); | 1043 return slow_stub(); |
1098 } | 1044 } |
1099 | 1045 |
1100 // -------------- Dictionary properties -------------- | 1046 // -------------- Dictionary properties -------------- |
1101 DCHECK(lookup->property_kind() == LookupIterator::DATA); | 1047 DCHECK(lookup->property_kind() == LookupIterator::DATA); |
1102 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { | 1048 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { |
1103 if (kind() != Code::LOAD_IC) return slow_stub(); | 1049 if (kind() != Code::LOAD_IC) return slow_stub(); |
1104 if (holder->IsGlobalObject()) { | 1050 if (holder->IsGlobalObject()) { |
1105 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1051 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1106 cache_holder); | 1052 cache_holder); |
1107 Handle<PropertyCell> cell = lookup->GetPropertyCell(); | 1053 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
1108 Handle<Code> code = | 1054 Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(), |
1109 compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable()); | 1055 lookup->IsConfigurable()); |
1110 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1056 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
1111 CacheHolderFlag flag; | 1057 CacheHolderFlag flag; |
1112 Handle<Map> stub_holder_map = | 1058 Handle<Map> stub_holder_map = |
1113 GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag); | 1059 GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag); |
1114 Map::UpdateCodeCache(stub_holder_map, name, code); | 1060 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); |
1115 return code; | 1061 return code; |
1116 } | 1062 } |
1117 // There is only one shared stub for loading normalized | 1063 // There is only one shared stub for loading normalized |
1118 // properties. It does not traverse the prototype chain, so the | 1064 // properties. It does not traverse the prototype chain, so the |
1119 // property must be found in the object for the stub to be | 1065 // property must be found in the object for the stub to be |
1120 // applicable. | 1066 // applicable. |
1121 if (!receiver_is_holder) return slow_stub(); | 1067 if (!receiver_is_holder) return slow_stub(); |
1122 return isolate()->builtins()->LoadIC_Normal(); | 1068 return isolate()->builtins()->LoadIC_Normal(); |
1123 } | 1069 } |
1124 | 1070 |
1125 // -------------- Fields -------------- | 1071 // -------------- Fields -------------- |
1126 DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR); | 1072 DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR); |
1127 if (lookup->property_details().type() == FIELD) { | 1073 if (lookup->property_details().type() == FIELD) { |
1128 FieldIndex field = lookup->GetFieldIndex(); | 1074 FieldIndex field = lookup->GetFieldIndex(); |
1129 if (receiver_is_holder) { | 1075 if (receiver_is_holder) { |
1130 return SimpleFieldLoad(field); | 1076 return SimpleFieldLoad(field); |
1131 } | 1077 } |
1132 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1078 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1133 cache_holder); | 1079 cache_holder); |
1134 return compiler.CompileLoadField(name, field); | 1080 return compiler.CompileLoadField(lookup->name(), field); |
1135 } | 1081 } |
1136 | 1082 |
1137 // -------------- Constant properties -------------- | 1083 // -------------- Constant properties -------------- |
1138 DCHECK(lookup->property_details().type() == CONSTANT); | 1084 DCHECK(lookup->property_details().type() == CONSTANT); |
1139 if (receiver_is_holder) { | 1085 if (receiver_is_holder) { |
1140 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); | 1086 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
1141 return stub.GetCode(); | 1087 return stub.GetCode(); |
1142 } | 1088 } |
1143 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 1089 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
1144 cache_holder); | 1090 cache_holder); |
1145 return compiler.CompileLoadConstant(name, lookup->GetConstantIndex()); | 1091 return compiler.CompileLoadConstant(lookup->name(), |
| 1092 lookup->GetConstantIndex()); |
1146 } | 1093 } |
1147 | 1094 |
1148 | 1095 |
1149 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1096 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
1150 // This helper implements a few common fast cases for converting | 1097 // This helper implements a few common fast cases for converting |
1151 // non-smi keys of keyed loads/stores to a smi or a string. | 1098 // non-smi keys of keyed loads/stores to a smi or a string. |
1152 if (key->IsHeapNumber()) { | 1099 if (key->IsHeapNumber()) { |
1153 double value = Handle<HeapNumber>::cast(key)->value(); | 1100 double value = Handle<HeapNumber>::cast(key)->value(); |
1154 if (std::isnan(value)) { | 1101 if (std::isnan(value)) { |
1155 key = isolate->factory()->nan_string(); | 1102 key = isolate->factory()->nan_string(); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1277 Handle<Object> result; | 1224 Handle<Object> result; |
1278 ASSIGN_RETURN_ON_EXCEPTION( | 1225 ASSIGN_RETURN_ON_EXCEPTION( |
1279 isolate(), | 1226 isolate(), |
1280 result, | 1227 result, |
1281 Runtime::GetObjectProperty(isolate(), object, key), | 1228 Runtime::GetObjectProperty(isolate(), object, key), |
1282 Object); | 1229 Object); |
1283 return result; | 1230 return result; |
1284 } | 1231 } |
1285 | 1232 |
1286 | 1233 |
1287 static bool LookupForWrite(Handle<Object> object, Handle<Name> name, | 1234 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, |
1288 Handle<Object> value, LookupResult* lookup, IC* ic) { | 1235 JSReceiver::StoreFromKeyed store_mode) { |
1289 // Disable ICs for non-JSObjects for now. | 1236 // Disable ICs for non-JSObjects for now. |
1290 if (!object->IsJSObject()) return false; | 1237 Handle<Object> receiver = it->GetReceiver(); |
1291 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1238 if (!receiver->IsJSObject()) return false; |
| 1239 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated()); |
1292 | 1240 |
1293 Handle<JSObject> holder = receiver; | 1241 for (; it->IsFound(); it->Next()) { |
1294 receiver->Lookup(name, lookup); | 1242 switch (it->state()) { |
1295 if (lookup->IsFound()) { | 1243 case LookupIterator::NOT_FOUND: |
1296 if (lookup->IsInterceptor() && !HasInterceptorSetter(lookup->holder())) { | 1244 case LookupIterator::TRANSITION: |
1297 receiver->LookupOwnRealNamedProperty(name, lookup); | 1245 UNREACHABLE(); |
1298 if (!lookup->IsFound()) return false; | 1246 case LookupIterator::JSPROXY: |
| 1247 return false; |
| 1248 case LookupIterator::INTERCEPTOR: { |
| 1249 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
| 1250 InterceptorInfo* info = holder->GetNamedInterceptor(); |
| 1251 if (it->HolderIsReceiverOrHiddenPrototype()) { |
| 1252 if (!info->setter()->IsUndefined()) return true; |
| 1253 } else if (!info->getter()->IsUndefined() || |
| 1254 !info->query()->IsUndefined()) { |
| 1255 return false; |
| 1256 } |
| 1257 break; |
| 1258 } |
| 1259 case LookupIterator::ACCESS_CHECK: |
| 1260 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false; |
| 1261 break; |
| 1262 case LookupIterator::PROPERTY: |
| 1263 if (!it->HasProperty()) break; |
| 1264 if (it->IsReadOnly()) return false; |
| 1265 if (it->property_kind() == LookupIterator::ACCESSOR) return true; |
| 1266 if (it->GetHolder<Object>().is_identical_to(receiver)) { |
| 1267 it->PrepareForDataProperty(value); |
| 1268 // The previous receiver map might just have been deprecated, |
| 1269 // so reload it. |
| 1270 update_receiver_type(receiver); |
| 1271 return true; |
| 1272 } |
| 1273 |
| 1274 // Receiver != holder. |
| 1275 if (receiver->IsJSGlobalProxy()) { |
| 1276 PrototypeIterator iter(it->isolate(), receiver); |
| 1277 return it->GetHolder<Object>().is_identical_to( |
| 1278 PrototypeIterator::GetCurrent(iter)); |
| 1279 } |
| 1280 |
| 1281 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
| 1282 return it->IsCacheableTransition(); |
1299 } | 1283 } |
1300 | |
1301 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | |
1302 if (lookup->holder() == *receiver) return lookup->CanHoldValue(value); | |
1303 if (lookup->IsPropertyCallbacks()) return true; | |
1304 // JSGlobalProxy either stores on the global object in the prototype, or | |
1305 // goes into the runtime if access checks are needed, so this is always | |
1306 // safe. | |
1307 if (receiver->IsJSGlobalProxy()) { | |
1308 PrototypeIterator iter(lookup->isolate(), receiver); | |
1309 return lookup->holder() == *PrototypeIterator::GetCurrent(iter); | |
1310 } | |
1311 // Currently normal holders in the prototype chain are not supported. They | |
1312 // would require a runtime positive lookup and verification that the details | |
1313 // have not changed. | |
1314 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; | |
1315 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); | |
1316 } | 1284 } |
1317 | 1285 |
1318 // While normally LookupTransition gets passed the receiver, in this case we | 1286 it->PrepareTransitionToDataProperty(value, NONE, store_mode); |
1319 // pass the holder of the property that we overwrite. This keeps the holder in | 1287 return it->IsCacheableTransition(); |
1320 // the LookupResult intact so we can later use it to generate a prototype | |
1321 // chain check. This avoids a double lookup, but requires us to pass in the | |
1322 // receiver when trying to fetch extra information from the transition. | |
1323 receiver->map()->LookupTransition(*holder, *name, lookup); | |
1324 if (!lookup->IsTransition() || lookup->IsReadOnly()) return false; | |
1325 | |
1326 // If the value that's being stored does not fit in the field that the | |
1327 // instance would transition to, create a new transition that fits the value. | |
1328 // This has to be done before generating the IC, since that IC will embed the | |
1329 // transition target. | |
1330 // Ensure the instance and its map were migrated before trying to update the | |
1331 // transition target. | |
1332 DCHECK(!receiver->map()->is_deprecated()); | |
1333 if (!lookup->CanHoldValue(value)) { | |
1334 Handle<Map> target(lookup->GetTransitionTarget()); | |
1335 Representation field_representation = value->OptimalRepresentation(); | |
1336 Handle<HeapType> field_type = value->OptimalType( | |
1337 lookup->isolate(), field_representation); | |
1338 Map::GeneralizeRepresentation( | |
1339 target, target->LastAdded(), | |
1340 field_representation, field_type, FORCE_FIELD); | |
1341 // Lookup the transition again since the transition tree may have changed | |
1342 // entirely by the migration above. | |
1343 receiver->map()->LookupTransition(*holder, *name, lookup); | |
1344 if (!lookup->IsTransition()) return false; | |
1345 if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false; | |
1346 ic->MarkPrototypeFailure(name); | |
1347 return true; | |
1348 } | |
1349 | |
1350 return true; | |
1351 } | 1288 } |
1352 | 1289 |
1353 | 1290 |
1354 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, | 1291 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, |
1355 Handle<Name> name, | 1292 Handle<Name> name, |
1356 Handle<Object> value, | 1293 Handle<Object> value, |
1357 JSReceiver::StoreFromKeyed store_mode) { | 1294 JSReceiver::StoreFromKeyed store_mode) { |
1358 // TODO(verwaest): Let SetProperty do the migration, since storing a property | 1295 // TODO(verwaest): Let SetProperty do the migration, since storing a property |
1359 // might deprecate the current map again, if value does not fit. | 1296 // might deprecate the current map again, if value does not fit. |
1360 if (MigrateDeprecated(object) || object->IsJSProxy()) { | 1297 if (MigrateDeprecated(object) || object->IsJSProxy()) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1392 if (object->IsHeapObject() && | 1329 if (object->IsHeapObject() && |
1393 Handle<HeapObject>::cast(object)->map()->is_observed()) { | 1330 Handle<HeapObject>::cast(object)->map()->is_observed()) { |
1394 Handle<Object> result; | 1331 Handle<Object> result; |
1395 ASSIGN_RETURN_ON_EXCEPTION( | 1332 ASSIGN_RETURN_ON_EXCEPTION( |
1396 isolate(), result, | 1333 isolate(), result, |
1397 Object::SetProperty(object, name, value, strict_mode(), store_mode), | 1334 Object::SetProperty(object, name, value, strict_mode(), store_mode), |
1398 Object); | 1335 Object); |
1399 return result; | 1336 return result; |
1400 } | 1337 } |
1401 | 1338 |
1402 LookupResult lookup(isolate()); | 1339 LookupIterator it(object, name); |
1403 bool can_store = LookupForWrite(object, name, value, &lookup, this); | 1340 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode); |
1404 if (!can_store && | |
1405 strict_mode() == STRICT && | |
1406 !(lookup.IsProperty() && lookup.IsReadOnly()) && | |
1407 object->IsGlobalObject()) { | |
1408 // Strict mode doesn't allow setting non-existent global property. | |
1409 return ReferenceError("not_defined", name); | |
1410 } | |
1411 if (FLAG_use_ic) { | |
1412 if (state() == UNINITIALIZED) { | |
1413 Handle<Code> stub = pre_monomorphic_stub(); | |
1414 set_target(*stub); | |
1415 TRACE_IC("StoreIC", name); | |
1416 } else if (can_store) { | |
1417 UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value); | |
1418 } else if (lookup.IsNormal() || | |
1419 (lookup.IsField() && lookup.CanHoldValue(value))) { | |
1420 Handle<Code> stub = generic_stub(); | |
1421 set_target(*stub); | |
1422 } | |
1423 } | |
1424 | 1341 |
1425 // Set the property. | 1342 // Set the property. |
1426 Handle<Object> result; | 1343 Handle<Object> result; |
1427 ASSIGN_RETURN_ON_EXCEPTION( | 1344 ASSIGN_RETURN_ON_EXCEPTION( |
1428 isolate(), result, | 1345 isolate(), result, |
1429 Object::SetProperty(object, name, value, strict_mode(), store_mode), | 1346 Object::SetProperty(&it, value, strict_mode(), store_mode), Object); |
1430 Object); | |
1431 return result; | 1347 return result; |
1432 } | 1348 } |
1433 | 1349 |
1434 | 1350 |
1435 OStream& operator<<(OStream& os, const CallIC::State& s) { | 1351 OStream& operator<<(OStream& os, const CallIC::State& s) { |
1436 return os << "(args(" << s.arg_count() << "), " | 1352 return os << "(args(" << s.arg_count() << "), " |
1437 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") | 1353 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") |
1438 << ", "; | 1354 << ", "; |
1439 } | 1355 } |
1440 | 1356 |
(...skipping 27 matching lines...) Expand all Loading... |
1468 } | 1384 } |
1469 | 1385 |
1470 | 1386 |
1471 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate, | 1387 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate, |
1472 StrictMode strict_mode) { | 1388 StrictMode strict_mode) { |
1473 ExtraICState state = ComputeExtraICState(strict_mode); | 1389 ExtraICState state = ComputeExtraICState(strict_mode); |
1474 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state); | 1390 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state); |
1475 } | 1391 } |
1476 | 1392 |
1477 | 1393 |
1478 void StoreIC::UpdateCaches(LookupResult* lookup, | 1394 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, |
1479 Handle<JSObject> receiver, | 1395 JSReceiver::StoreFromKeyed store_mode) { |
1480 Handle<Name> name, | 1396 if (state() == UNINITIALIZED) { |
1481 Handle<Object> value) { | 1397 // This is the first time we execute this inline cache. Set the target to |
1482 DCHECK(lookup->IsFound()); | 1398 // the pre monomorphic stub to delay setting the monomorphic state. |
| 1399 set_target(*pre_monomorphic_stub()); |
| 1400 TRACE_IC("StoreIC", lookup->name()); |
| 1401 return; |
| 1402 } |
1483 | 1403 |
1484 // These are not cacheable, so we never see such LookupResults here. | 1404 Handle<Code> code = LookupForWrite(lookup, value, store_mode) |
1485 DCHECK(!lookup->IsHandler()); | 1405 ? ComputeHandler(lookup, value) |
| 1406 : slow_stub(); |
1486 | 1407 |
1487 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); | 1408 PatchCache(lookup->name(), code); |
1488 | 1409 TRACE_IC("StoreIC", lookup->name()); |
1489 PatchCache(name, code); | |
1490 TRACE_IC("StoreIC", name); | |
1491 } | 1410 } |
1492 | 1411 |
1493 | 1412 |
1494 Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup, | 1413 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, |
1495 Handle<Object> object, | 1414 Handle<Object> value, |
1496 Handle<Name> name, | 1415 CacheHolderFlag cache_holder) { |
1497 Handle<Object> value, | 1416 DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); |
1498 CacheHolderFlag cache_holder) { | 1417 |
1499 if (object->IsAccessCheckNeeded()) return slow_stub(); | |
1500 DCHECK(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS || | |
1501 (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject())); | |
1502 // This is currently guaranteed by checks in StoreIC::Store. | 1418 // This is currently guaranteed by checks in StoreIC::Store. |
1503 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1419 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); |
| 1420 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
| 1421 DCHECK(!receiver->IsAccessCheckNeeded()); |
1504 | 1422 |
1505 Handle<JSObject> holder(lookup->holder()); | 1423 // -------------- Transition -------------- |
| 1424 if (lookup->state() == LookupIterator::TRANSITION) { |
| 1425 Handle<Map> transition = lookup->transition_map(); |
| 1426 // Currently not handled by CompileStoreTransition. |
| 1427 if (!holder->HasFastProperties()) return slow_stub(); |
1506 | 1428 |
1507 if (lookup->IsTransition()) { | 1429 DCHECK(lookup->IsCacheableTransition()); |
1508 // Explicitly pass in the receiver map since LookupForWrite may have | 1430 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
1509 // stored something else than the receiver in the holder. | 1431 return compiler.CompileStoreTransition(transition, lookup->name()); |
1510 Handle<Map> transition(lookup->GetTransitionTarget()); | 1432 } |
1511 PropertyDetails details = lookup->GetPropertyDetails(); | |
1512 | 1433 |
1513 if (details.type() != CALLBACKS && details.attributes() == NONE && | 1434 // -------------- Interceptors -------------- |
1514 holder->HasFastProperties()) { | 1435 if (lookup->state() == LookupIterator::INTERCEPTOR) { |
| 1436 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); |
| 1437 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1438 return compiler.CompileStoreInterceptor(lookup->name()); |
| 1439 } |
| 1440 |
| 1441 // -------------- Accessors -------------- |
| 1442 DCHECK(lookup->state() == LookupIterator::PROPERTY); |
| 1443 if (lookup->property_kind() == LookupIterator::ACCESSOR) { |
| 1444 if (!holder->HasFastProperties()) return slow_stub(); |
| 1445 Handle<Object> accessors = lookup->GetAccessors(); |
| 1446 if (accessors->IsExecutableAccessorInfo()) { |
| 1447 Handle<ExecutableAccessorInfo> info = |
| 1448 Handle<ExecutableAccessorInfo>::cast(accessors); |
| 1449 if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub(); |
| 1450 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
| 1451 receiver_type())) { |
| 1452 return slow_stub(); |
| 1453 } |
1515 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1454 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
1516 return compiler.CompileStoreTransition(transition, name); | 1455 return compiler.CompileStoreCallback(receiver, lookup->name(), info); |
| 1456 } else if (accessors->IsAccessorPair()) { |
| 1457 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), |
| 1458 isolate()); |
| 1459 if (!setter->IsJSFunction()) return slow_stub(); |
| 1460 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
| 1461 CallOptimization call_optimization(function); |
| 1462 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1463 if (call_optimization.is_simple_api_call() && |
| 1464 call_optimization.IsCompatibleReceiver(receiver, holder)) { |
| 1465 return compiler.CompileStoreCallback(receiver, lookup->name(), |
| 1466 call_optimization); |
| 1467 } |
| 1468 return compiler.CompileStoreViaSetter(receiver, lookup->name(), |
| 1469 Handle<JSFunction>::cast(setter)); |
1517 } | 1470 } |
1518 } else { | 1471 // TODO(dcarney): Handle correctly. |
1519 switch (lookup->type()) { | 1472 DCHECK(accessors->IsDeclaredAccessorInfo()); |
1520 case FIELD: { | 1473 return slow_stub(); |
1521 bool use_stub = true; | 1474 } |
1522 if (lookup->representation().IsHeapObject()) { | 1475 |
1523 // Only use a generic stub if no types need to be tracked. | 1476 // -------------- Dictionary properties -------------- |
1524 HeapType* field_type = lookup->GetFieldType(); | 1477 DCHECK(lookup->property_kind() == LookupIterator::DATA); |
1525 HeapType::Iterator<Map> it = field_type->Classes(); | 1478 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { |
1526 use_stub = it.Done(); | 1479 if (holder->IsGlobalObject()) { |
1527 } | 1480 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
1528 if (use_stub) { | 1481 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
1529 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), | 1482 StoreGlobalStub stub(isolate(), union_type->IsConstant(), |
1530 lookup->representation()); | 1483 receiver->IsJSGlobalProxy()); |
1531 return stub.GetCode(); | 1484 Handle<Code> code = stub.GetCodeCopyFromTemplate( |
1532 } | 1485 Handle<GlobalObject>::cast(holder), cell); |
1533 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1486 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
1534 return compiler.CompileStoreField(lookup, name); | 1487 HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code); |
1535 } | 1488 return code; |
1536 case NORMAL: | |
1537 if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) { | |
1538 // The stub generated for the global object picks the value directly | |
1539 // from the property cell. So the property must be directly on the | |
1540 // global object. | |
1541 PrototypeIterator iter(isolate(), receiver); | |
1542 Handle<GlobalObject> global = | |
1543 receiver->IsJSGlobalProxy() | |
1544 ? Handle<GlobalObject>::cast( | |
1545 PrototypeIterator::GetCurrent(iter)) | |
1546 : Handle<GlobalObject>::cast(receiver); | |
1547 Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate()); | |
1548 Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); | |
1549 StoreGlobalStub stub( | |
1550 isolate(), union_type->IsConstant(), receiver->IsJSGlobalProxy()); | |
1551 Handle<Code> code = stub.GetCodeCopyFromTemplate(global, cell); | |
1552 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | |
1553 HeapObject::UpdateMapCodeCache(receiver, name, code); | |
1554 return code; | |
1555 } | |
1556 DCHECK(holder.is_identical_to(receiver)); | |
1557 return isolate()->builtins()->StoreIC_Normal(); | |
1558 case CALLBACKS: { | |
1559 if (!holder->HasFastProperties()) break; | |
1560 Handle<Object> callback(lookup->GetValueFromMap(holder->map()), | |
1561 isolate()); | |
1562 if (callback->IsExecutableAccessorInfo()) { | |
1563 Handle<ExecutableAccessorInfo> info = | |
1564 Handle<ExecutableAccessorInfo>::cast(callback); | |
1565 if (v8::ToCData<Address>(info->setter()) == 0) break; | |
1566 if (!ExecutableAccessorInfo::IsCompatibleReceiverType( | |
1567 isolate(), info, receiver_type())) { | |
1568 break; | |
1569 } | |
1570 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), | |
1571 holder); | |
1572 return compiler.CompileStoreCallback(receiver, name, info); | |
1573 } else if (callback->IsAccessorPair()) { | |
1574 Handle<Object> setter( | |
1575 Handle<AccessorPair>::cast(callback)->setter(), isolate()); | |
1576 if (!setter->IsJSFunction()) break; | |
1577 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | |
1578 CallOptimization call_optimization(function); | |
1579 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), | |
1580 holder); | |
1581 if (call_optimization.is_simple_api_call() && | |
1582 call_optimization.IsCompatibleReceiver(receiver, holder)) { | |
1583 return compiler.CompileStoreCallback(receiver, name, | |
1584 call_optimization); | |
1585 } | |
1586 return compiler.CompileStoreViaSetter( | |
1587 receiver, name, Handle<JSFunction>::cast(setter)); | |
1588 } | |
1589 // TODO(dcarney): Handle correctly. | |
1590 DCHECK(callback->IsDeclaredAccessorInfo()); | |
1591 break; | |
1592 } | |
1593 case INTERCEPTOR: { | |
1594 DCHECK(HasInterceptorSetter(*holder)); | |
1595 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | |
1596 return compiler.CompileStoreInterceptor(name); | |
1597 } | |
1598 case CONSTANT: | |
1599 break; | |
1600 case HANDLER: | |
1601 UNREACHABLE(); | |
1602 break; | |
1603 } | 1489 } |
| 1490 DCHECK(holder.is_identical_to(receiver)); |
| 1491 return isolate()->builtins()->StoreIC_Normal(); |
1604 } | 1492 } |
| 1493 |
| 1494 // -------------- Fields -------------- |
| 1495 DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR); |
| 1496 if (lookup->property_details().type() == FIELD) { |
| 1497 bool use_stub = true; |
| 1498 if (lookup->representation().IsHeapObject()) { |
| 1499 // Only use a generic stub if no types need to be tracked. |
| 1500 Handle<HeapType> field_type = lookup->GetFieldType(); |
| 1501 HeapType::Iterator<Map> it = field_type->Classes(); |
| 1502 use_stub = it.Done(); |
| 1503 } |
| 1504 if (use_stub) { |
| 1505 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), |
| 1506 lookup->representation()); |
| 1507 return stub.GetCode(); |
| 1508 } |
| 1509 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1510 return compiler.CompileStoreField(lookup); |
| 1511 } |
| 1512 |
| 1513 // -------------- Constant properties -------------- |
| 1514 DCHECK(lookup->property_details().type() == CONSTANT); |
1605 return slow_stub(); | 1515 return slow_stub(); |
1606 } | 1516 } |
1607 | 1517 |
1608 | 1518 |
1609 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1519 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
1610 KeyedAccessStoreMode store_mode) { | 1520 KeyedAccessStoreMode store_mode) { |
1611 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1521 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
1612 // via megamorphic stubs, since they don't have a map in their relocation info | 1522 // via megamorphic stubs, since they don't have a map in their relocation info |
1613 // and so the stubs can't be harvested for the object needed for a map check. | 1523 // and so the stubs can't be harvested for the object needed for a map check. |
1614 if (target()->type() != Code::NORMAL) { | 1524 if (target()->type() != Code::NORMAL) { |
(...skipping 1557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3172 #undef ADDR | 3082 #undef ADDR |
3173 }; | 3083 }; |
3174 | 3084 |
3175 | 3085 |
3176 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3086 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
3177 return IC_utilities[id]; | 3087 return IC_utilities[id]; |
3178 } | 3088 } |
3179 | 3089 |
3180 | 3090 |
3181 } } // namespace v8::internal | 3091 } } // namespace v8::internal |
OLD | NEW |