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