| 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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 Code* IC::GetOriginalCode() const { | 183 Code* IC::GetOriginalCode() const { |
| 184 HandleScope scope(isolate()); | 184 HandleScope scope(isolate()); |
| 185 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); | 185 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); |
| 186 ASSERT(Debug::HasDebugInfo(shared)); | 186 ASSERT(Debug::HasDebugInfo(shared)); |
| 187 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); | 187 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); |
| 188 ASSERT(original_code->IsCode()); | 188 ASSERT(original_code->IsCode()); |
| 189 return original_code; | 189 return original_code; |
| 190 } | 190 } |
| 191 | 191 |
| 192 | 192 |
| 193 static bool HasInterceptorGetter(JSObject* object) { | |
| 194 return !object->GetNamedInterceptor()->getter()->IsUndefined(); | |
| 195 } | |
| 196 | |
| 197 | |
| 198 static bool HasInterceptorSetter(JSObject* object) { | 193 static bool HasInterceptorSetter(JSObject* object) { |
| 199 return !object->GetNamedInterceptor()->setter()->IsUndefined(); | 194 return !object->GetNamedInterceptor()->setter()->IsUndefined(); |
| 200 } | 195 } |
| 201 | 196 |
| 202 | 197 |
| 203 static void LookupForRead(Handle<Object> object, | 198 static void LookupForRead(LookupIterator* it) { |
| 204 Handle<String> name, | 199 for (; it->IsFound(); it->Next()) { |
| 205 LookupResult* lookup) { | 200 switch (it->state()) { |
| 206 // Skip all the objects with named interceptors, but | 201 case LookupIterator::NOT_FOUND: |
| 207 // without actual getter. | 202 UNREACHABLE(); |
| 208 while (true) { | 203 case LookupIterator::JSPROXY: |
| 209 object->Lookup(name, lookup); | 204 return; |
| 210 // Besides normal conditions (property not found or it's not | 205 case LookupIterator::INTERCEPTOR: { |
| 211 // an interceptor), bail out if lookup is not cacheable: we won't | 206 // If there is a getter, return; otherwise loop to perform the lookup. |
| 212 // be able to IC it anyway and regular lookup should work fine. | 207 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
| 213 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) { | 208 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { |
| 214 return; | 209 return; |
| 210 } |
| 211 break; |
| 212 } |
| 213 case LookupIterator::ACCESS_CHECK: |
| 214 return; |
| 215 case LookupIterator::PROPERTY: |
| 216 if (it->HasProperty()) return; // Yay! |
| 217 break; |
| 215 } | 218 } |
| 216 | |
| 217 Handle<JSObject> holder(lookup->holder(), lookup->isolate()); | |
| 218 if (HasInterceptorGetter(*holder)) { | |
| 219 return; | |
| 220 } | |
| 221 | |
| 222 holder->LookupOwnRealNamedProperty(name, lookup); | |
| 223 if (lookup->IsFound()) { | |
| 224 ASSERT(!lookup->IsInterceptor()); | |
| 225 return; | |
| 226 } | |
| 227 | |
| 228 PrototypeIterator iter(lookup->isolate(), holder); | |
| 229 if (iter.IsAtEnd()) { | |
| 230 ASSERT(!lookup->IsFound()); | |
| 231 return; | |
| 232 } | |
| 233 | |
| 234 object = PrototypeIterator::GetCurrent(iter); | |
| 235 } | 219 } |
| 236 } | 220 } |
| 237 | 221 |
| 238 | 222 |
| 239 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, | 223 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, |
| 240 Handle<String> name) { | 224 Handle<String> name) { |
| 241 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; | 225 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; |
| 242 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate()); | 226 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate()); |
| 243 maybe_handler_ = target()->FindHandlerForMap(*receiver_map); | 227 maybe_handler_ = target()->FindHandlerForMap(*receiver_map); |
| 244 | 228 |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 isolate(), | 551 isolate(), |
| 568 result, | 552 result, |
| 569 Runtime::GetElementOrCharAt(isolate(), object, index), | 553 Runtime::GetElementOrCharAt(isolate(), object, index), |
| 570 Object); | 554 Object); |
| 571 return result; | 555 return result; |
| 572 } | 556 } |
| 573 | 557 |
| 574 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; | 558 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; |
| 575 | 559 |
| 576 // Named lookup in the object. | 560 // Named lookup in the object. |
| 577 LookupResult lookup(isolate()); | 561 LookupIterator it(object, name); |
| 578 LookupForRead(object, name, &lookup); | 562 LookupForRead(&it); |
| 579 | 563 |
| 580 // If we did not find a property, check if we need to throw an exception. | 564 // If we did not find a property, check if we need to throw an exception. |
| 581 if (!lookup.IsFound()) { | 565 if (!it.IsFound()) { |
| 582 if (IsUndeclaredGlobal(object)) { | 566 if (IsUndeclaredGlobal(object)) { |
| 583 return ReferenceError("not_defined", name); | 567 return ReferenceError("not_defined", name); |
| 584 } | 568 } |
| 585 LOG(isolate(), SuspectReadEvent(*name, *object)); | 569 LOG(isolate(), SuspectReadEvent(*name, *object)); |
| 586 } | 570 } |
| 587 | 571 |
| 588 // Update inline cache and stub cache. | 572 // Update inline cache and stub cache. |
| 589 if (use_ic) UpdateCaches(&lookup, object, name); | 573 if (use_ic) UpdateCaches(&it, object, name); |
| 590 | 574 |
| 591 // Get the property. | 575 // Get the property. |
| 592 LookupIterator it(object, name); | |
| 593 Handle<Object> result; | 576 Handle<Object> result; |
| 594 ASSIGN_RETURN_ON_EXCEPTION( | 577 ASSIGN_RETURN_ON_EXCEPTION( |
| 595 isolate(), result, Object::GetProperty(&it), Object); | 578 isolate(), result, Object::GetProperty(&it), Object); |
| 596 // If the property is not present, check if we need to throw an exception. | 579 // If the property is not present, check if we need to throw an exception. |
| 597 if ((lookup.IsInterceptor() || lookup.IsHandler()) && | 580 if (!it.IsFound() && IsUndeclaredGlobal(object)) { |
| 598 !it.IsFound() && IsUndeclaredGlobal(object)) { | |
| 599 return ReferenceError("not_defined", name); | 581 return ReferenceError("not_defined", name); |
| 600 } | 582 } |
| 601 | 583 |
| 602 return result; | 584 return result; |
| 603 } | 585 } |
| 604 | 586 |
| 605 | 587 |
| 606 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, | 588 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| 607 Handle<Map> new_receiver_map) { | 589 Handle<Map> new_receiver_map) { |
| 608 ASSERT(!new_receiver_map.is_null()); | 590 ASSERT(!new_receiver_map.is_null()); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 } | 803 } |
| 822 } | 804 } |
| 823 | 805 |
| 824 | 806 |
| 825 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) { | 807 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) { |
| 826 LoadFieldStub stub(isolate(), index); | 808 LoadFieldStub stub(isolate(), index); |
| 827 return stub.GetCode(); | 809 return stub.GetCode(); |
| 828 } | 810 } |
| 829 | 811 |
| 830 | 812 |
| 831 void LoadIC::UpdateCaches(LookupResult* lookup, | 813 void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object, |
| 832 Handle<Object> object, | |
| 833 Handle<String> name) { | 814 Handle<String> name) { |
| 834 if (state() == UNINITIALIZED) { | 815 if (state() == UNINITIALIZED) { |
| 835 // This is the first time we execute this inline cache. | 816 // This is the first time we execute this inline cache. |
| 836 // Set the target to the pre monomorphic stub to delay | 817 // Set the target to the pre monomorphic stub to delay |
| 837 // setting the monomorphic state. | 818 // setting the monomorphic state. |
| 838 set_target(*pre_monomorphic_stub()); | 819 set_target(*pre_monomorphic_stub()); |
| 839 TRACE_IC("LoadIC", name); | 820 TRACE_IC("LoadIC", name); |
| 840 return; | 821 return; |
| 841 } | 822 } |
| 842 | 823 |
| 843 Handle<Code> code; | 824 Handle<Code> code; |
| 844 if (!lookup->IsCacheable()) { | 825 if (lookup->state() == LookupIterator::JSPROXY || |
| 845 // Bail out if the result is not cacheable. | 826 lookup->state() == LookupIterator::ACCESS_CHECK) { |
| 846 code = slow_stub(); | 827 code = slow_stub(); |
| 847 } else if (!lookup->IsProperty()) { | 828 } else if (!lookup->IsFound()) { |
| 848 if (kind() == Code::LOAD_IC) { | 829 if (kind() == Code::LOAD_IC) { |
| 849 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name, | 830 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name, |
| 850 receiver_type()); | 831 receiver_type()); |
| 851 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. | 832 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. |
| 852 if (code.is_null()) code = slow_stub(); | 833 if (code.is_null()) code = slow_stub(); |
| 853 } else { | 834 } else { |
| 854 code = slow_stub(); | 835 code = slow_stub(); |
| 855 } | 836 } |
| 856 } else { | 837 } else { |
| 857 code = ComputeHandler(lookup, object, name); | 838 code = ComputeHandler(lookup, object, name); |
| 858 } | 839 } |
| 859 | 840 |
| 860 PatchCache(name, code); | 841 PatchCache(name, code); |
| 861 TRACE_IC("LoadIC", name); | 842 TRACE_IC("LoadIC", name); |
| 862 } | 843 } |
| 863 | 844 |
| 864 | 845 |
| 865 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) { | 846 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) { |
| 866 if (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC) return; | 847 if (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC) return; |
| 867 Map* map = *TypeToMap(type, isolate()); | 848 Map* map = *TypeToMap(type, isolate()); |
| 868 isolate()->stub_cache()->Set(name, map, code); | 849 isolate()->stub_cache()->Set(name, map, code); |
| 869 } | 850 } |
| 870 | 851 |
| 871 | 852 |
| 872 Handle<Code> IC::ComputeHandler(LookupResult* lookup, | 853 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object, |
| 873 Handle<Object> object, | 854 Handle<String> name, Handle<Object> value) { |
| 874 Handle<String> name, | 855 bool receiver_is_holder = |
| 875 Handle<Object> value) { | 856 object.is_identical_to(lookup->GetHolder<JSObject>()); |
| 857 CacheHolderFlag flag; |
| 858 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( |
| 859 *receiver_type(), receiver_is_holder, isolate(), &flag); |
| 860 |
| 861 Handle<Code> code = PropertyHandlerCompiler::Find( |
| 862 name, stub_holder_map, kind(), flag, |
| 863 lookup->holder_map()->is_dictionary_map() ? Code::NORMAL : Code::FAST); |
| 864 // Use the cached value if it exists, and if it is different from the |
| 865 // handler that just missed. |
| 866 if (!code.is_null()) { |
| 867 if (!maybe_handler_.is_null() && |
| 868 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { |
| 869 return code; |
| 870 } |
| 871 if (maybe_handler_.is_null()) { |
| 872 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. |
| 873 // In MEGAMORPHIC case, check if the handler in the megamorphic stub |
| 874 // cache (which just missed) is different from the cached handler. |
| 875 if (state() == MEGAMORPHIC && object->IsHeapObject()) { |
| 876 Map* map = Handle<HeapObject>::cast(object)->map(); |
| 877 Code* megamorphic_cached_code = |
| 878 isolate()->stub_cache()->Get(*name, map, code->flags()); |
| 879 if (megamorphic_cached_code != *code) return code; |
| 880 } else { |
| 881 return code; |
| 882 } |
| 883 } |
| 884 } |
| 885 |
| 886 code = CompileHandler(lookup, object, name, value, flag); |
| 887 ASSERT(code->is_handler()); |
| 888 |
| 889 if (code->type() != Code::NORMAL) { |
| 890 Map::UpdateCodeCache(stub_holder_map, name, code); |
| 891 } |
| 892 |
| 893 return code; |
| 894 } |
| 895 |
| 896 |
| 897 Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup, |
| 898 Handle<Object> object, Handle<String> name, |
| 899 Handle<Object> value) { |
| 876 bool receiver_is_holder = lookup->ReceiverIsHolder(object); | 900 bool receiver_is_holder = lookup->ReceiverIsHolder(object); |
| 877 CacheHolderFlag flag; | 901 CacheHolderFlag flag; |
| 878 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( | 902 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( |
| 879 *receiver_type(), receiver_is_holder, isolate(), &flag); | 903 *receiver_type(), receiver_is_holder, isolate(), &flag); |
| 880 | 904 |
| 881 Handle<Code> code = PropertyHandlerCompiler::Find( | 905 Handle<Code> code = PropertyHandlerCompiler::Find( |
| 882 name, stub_holder_map, handler_kind(), flag, | 906 name, stub_holder_map, handler_kind(), flag, |
| 883 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL); | 907 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL); |
| 884 // Use the cached value if it exists, and if it is different from the | 908 // Use the cached value if it exists, and if it is different from the |
| 885 // handler that just missed. | 909 // handler that just missed. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 896 Map* map = Handle<HeapObject>::cast(object)->map(); | 920 Map* map = Handle<HeapObject>::cast(object)->map(); |
| 897 Code* megamorphic_cached_code = | 921 Code* megamorphic_cached_code = |
| 898 isolate()->stub_cache()->Get(*name, map, code->flags()); | 922 isolate()->stub_cache()->Get(*name, map, code->flags()); |
| 899 if (megamorphic_cached_code != *code) return code; | 923 if (megamorphic_cached_code != *code) return code; |
| 900 } else { | 924 } else { |
| 901 return code; | 925 return code; |
| 902 } | 926 } |
| 903 } | 927 } |
| 904 } | 928 } |
| 905 | 929 |
| 906 code = CompileHandler(lookup, object, name, value, flag); | 930 code = CompileStoreHandler(lookup, object, name, value, flag); |
| 907 ASSERT(code->is_handler()); | 931 ASSERT(code->is_handler()); |
| 908 | 932 |
| 909 if (code->type() != Code::NORMAL) { | 933 if (code->type() != Code::NORMAL) { |
| 910 Map::UpdateCodeCache(stub_holder_map, name, code); | 934 Map::UpdateCodeCache(stub_holder_map, name, code); |
| 911 } | 935 } |
| 912 | 936 |
| 913 return code; | 937 return code; |
| 914 } | 938 } |
| 915 | 939 |
| 916 | 940 |
| 917 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object, | 941 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, |
| 918 Handle<String> name, Handle<Object> unused, | 942 Handle<Object> object, Handle<String> name, |
| 943 Handle<Object> unused, |
| 919 CacheHolderFlag cache_holder) { | 944 CacheHolderFlag cache_holder) { |
| 920 if (object->IsString() && | 945 if (object->IsString() && |
| 921 String::Equals(isolate()->factory()->length_string(), name)) { | 946 String::Equals(isolate()->factory()->length_string(), name)) { |
| 922 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); | 947 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); |
| 923 return SimpleFieldLoad(index); | 948 return SimpleFieldLoad(index); |
| 924 } | 949 } |
| 925 | 950 |
| 926 if (object->IsStringWrapper() && | 951 if (object->IsStringWrapper() && |
| 927 String::Equals(isolate()->factory()->length_string(), name)) { | 952 String::Equals(isolate()->factory()->length_string(), name)) { |
| 928 StringLengthStub string_length_stub(isolate()); | 953 StringLengthStub string_length_stub(isolate()); |
| 929 return string_length_stub.GetCode(); | 954 return string_length_stub.GetCode(); |
| 930 } | 955 } |
| 931 | 956 |
| 932 // Use specialized code for getting prototype of functions. | 957 // Use specialized code for getting prototype of functions. |
| 933 if (object->IsJSFunction() && | 958 if (object->IsJSFunction() && |
| 934 String::Equals(isolate()->factory()->prototype_string(), name) && | 959 String::Equals(isolate()->factory()->prototype_string(), name) && |
| 935 Handle<JSFunction>::cast(object)->should_have_prototype() && | 960 Handle<JSFunction>::cast(object)->should_have_prototype() && |
| 936 !Handle<JSFunction>::cast(object)->map()->has_non_instance_prototype()) { | 961 !Handle<JSFunction>::cast(object)->map()->has_non_instance_prototype()) { |
| 937 Handle<Code> stub; | 962 Handle<Code> stub; |
| 938 FunctionPrototypeStub function_prototype_stub(isolate()); | 963 FunctionPrototypeStub function_prototype_stub(isolate()); |
| 939 return function_prototype_stub.GetCode(); | 964 return function_prototype_stub.GetCode(); |
| 940 } | 965 } |
| 941 | 966 |
| 942 Handle<HeapType> type = receiver_type(); | 967 Handle<HeapType> type = receiver_type(); |
| 943 Handle<JSObject> holder(lookup->holder()); | 968 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
| 944 bool receiver_is_holder = object.is_identical_to(holder); | 969 bool receiver_is_holder = object.is_identical_to(holder); |
| 945 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, | 970 NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
| 946 cache_holder); | 971 cache_holder); |
| 947 | 972 |
| 948 switch (lookup->type()) { | 973 // -------------- Interceptors -------------- |
| 949 case FIELD: { | 974 if (lookup->state() == LookupIterator::INTERCEPTOR) { |
| 950 FieldIndex field = lookup->GetFieldIndex(); | 975 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 951 if (receiver_is_holder) { | 976 return compiler.CompileLoadInterceptor(name); |
| 952 return SimpleFieldLoad(field); | 977 } |
| 978 ASSERT(lookup->state() == LookupIterator::PROPERTY); |
| 979 |
| 980 // -------------- Accessors -------------- |
| 981 if (lookup->property_kind() == LookupIterator::ACCESSOR) { |
| 982 // Use simple field loads for some well-known callback properties. |
| 983 if (receiver_is_holder) { |
| 984 ASSERT(object->IsJSObject()); |
| 985 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 986 int object_offset; |
| 987 if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name, |
| 988 &object_offset)) { |
| 989 FieldIndex index = |
| 990 FieldIndex::ForInObjectOffset(object_offset, receiver->map()); |
| 991 return SimpleFieldLoad(index); |
| 953 } | 992 } |
| 954 return compiler.CompileLoadField(name, field, lookup->representation()); | |
| 955 } | 993 } |
| 956 case CONSTANT: { | 994 |
| 957 Handle<Object> constant(lookup->GetConstant(), isolate()); | 995 Handle<Object> accessors = lookup->GetAccessors(); |
| 958 return compiler.CompileLoadConstant(name, constant); | 996 if (accessors->IsExecutableAccessorInfo()) { |
| 997 Handle<ExecutableAccessorInfo> info = |
| 998 Handle<ExecutableAccessorInfo>::cast(accessors); |
| 999 if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub(); |
| 1000 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
| 1001 type)) { |
| 1002 return slow_stub(); |
| 1003 } |
| 1004 if (holder->IsGlobalObject()) return slow_stub(); |
| 1005 return compiler.CompileLoadCallback(name, info); |
| 959 } | 1006 } |
| 960 case NORMAL: | 1007 if (accessors->IsAccessorPair()) { |
| 961 if (kind() != Code::LOAD_IC) break; | 1008 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), |
| 962 if (holder->IsGlobalObject()) { | 1009 isolate()); |
| 963 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1010 if (!getter->IsJSFunction()) return slow_stub(); |
| 964 Handle<PropertyCell> cell( | 1011 if (holder->IsGlobalObject()) return slow_stub(); |
| 965 global->GetPropertyCell(lookup), isolate()); | 1012 if (!holder->HasFastProperties()) return slow_stub(); |
| 966 Handle<Code> code = | 1013 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
| 967 compiler.CompileLoadGlobal(cell, name, lookup->IsDontDelete()); | 1014 if (!object->IsJSObject() && !function->IsBuiltin() && |
| 968 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. | 1015 function->shared()->strict_mode() == SLOPPY) { |
| 969 CacheHolderFlag flag; | 1016 // Calling sloppy non-builtins with a value as the receiver |
| 970 Handle<Map> stub_holder_map = | 1017 // requires boxing. |
| 971 GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag); | 1018 return slow_stub(); |
| 972 Map::UpdateCodeCache(stub_holder_map, name, code); | |
| 973 return code; | |
| 974 } | 1019 } |
| 975 // There is only one shared stub for loading normalized | 1020 CallOptimization call_optimization(function); |
| 976 // properties. It does not traverse the prototype chain, so the | 1021 if (call_optimization.is_simple_api_call() && |
| 977 // property must be found in the object for the stub to be | 1022 call_optimization.IsCompatibleReceiver(object, holder)) { |
| 978 // applicable. | 1023 return compiler.CompileLoadCallback(name, call_optimization); |
| 979 if (!receiver_is_holder) break; | |
| 980 return isolate()->builtins()->LoadIC_Normal(); | |
| 981 case CALLBACKS: { | |
| 982 // Use simple field loads for some well-known callback properties. | |
| 983 if (receiver_is_holder) { | |
| 984 ASSERT(object->IsJSObject()); | |
| 985 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 986 int object_offset; | |
| 987 if (Accessors::IsJSObjectFieldAccessor<HeapType>( | |
| 988 type, name, &object_offset)) { | |
| 989 FieldIndex index = FieldIndex::ForInObjectOffset( | |
| 990 object_offset, receiver->map()); | |
| 991 return SimpleFieldLoad(index); | |
| 992 } | |
| 993 } | 1024 } |
| 994 | 1025 return compiler.CompileLoadViaGetter(name, function); |
| 995 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | |
| 996 if (callback->IsExecutableAccessorInfo()) { | |
| 997 Handle<ExecutableAccessorInfo> info = | |
| 998 Handle<ExecutableAccessorInfo>::cast(callback); | |
| 999 if (v8::ToCData<Address>(info->getter()) == 0) break; | |
| 1000 if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, | |
| 1001 type)) { | |
| 1002 break; | |
| 1003 } | |
| 1004 if (holder->IsGlobalObject()) break; | |
| 1005 return compiler.CompileLoadCallback(name, info); | |
| 1006 } else if (callback->IsAccessorPair()) { | |
| 1007 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), | |
| 1008 isolate()); | |
| 1009 if (!getter->IsJSFunction()) break; | |
| 1010 if (holder->IsGlobalObject()) break; | |
| 1011 if (!holder->HasFastProperties()) break; | |
| 1012 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | |
| 1013 if (!object->IsJSObject() && | |
| 1014 !function->IsBuiltin() && | |
| 1015 function->shared()->strict_mode() == SLOPPY) { | |
| 1016 // Calling sloppy non-builtins with a value as the receiver | |
| 1017 // requires boxing. | |
| 1018 break; | |
| 1019 } | |
| 1020 CallOptimization call_optimization(function); | |
| 1021 if (call_optimization.is_simple_api_call() && | |
| 1022 call_optimization.IsCompatibleReceiver(object, holder)) { | |
| 1023 return compiler.CompileLoadCallback(name, call_optimization); | |
| 1024 } | |
| 1025 return compiler.CompileLoadViaGetter(name, function); | |
| 1026 } | |
| 1027 // TODO(dcarney): Handle correctly. | |
| 1028 ASSERT(callback->IsDeclaredAccessorInfo()); | |
| 1029 break; | |
| 1030 } | 1026 } |
| 1031 case INTERCEPTOR: | 1027 // TODO(dcarney): Handle correctly. |
| 1032 ASSERT(HasInterceptorGetter(*holder)); | 1028 ASSERT(accessors->IsDeclaredAccessorInfo()); |
| 1033 return compiler.CompileLoadInterceptor(name); | 1029 return slow_stub(); |
| 1034 default: | |
| 1035 break; | |
| 1036 } | 1030 } |
| 1037 | 1031 |
| 1038 return slow_stub(); | 1032 // -------------- Dictionary properties -------------- |
| 1033 ASSERT(lookup->property_kind() == LookupIterator::DATA); |
| 1034 if (lookup->property_encoding() == LookupIterator::DICTIONARY) { |
| 1035 if (kind() != Code::LOAD_IC) return slow_stub(); |
| 1036 if (holder->IsGlobalObject()) { |
| 1037 Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
| 1038 Handle<Code> code = |
| 1039 compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable()); |
| 1040 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
| 1041 CacheHolderFlag flag; |
| 1042 Handle<Map> stub_holder_map = |
| 1043 GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag); |
| 1044 Map::UpdateCodeCache(stub_holder_map, name, code); |
| 1045 return code; |
| 1046 } |
| 1047 // There is only one shared stub for loading normalized |
| 1048 // properties. It does not traverse the prototype chain, so the |
| 1049 // property must be found in the object for the stub to be |
| 1050 // applicable. |
| 1051 if (!receiver_is_holder) return slow_stub(); |
| 1052 return isolate()->builtins()->LoadIC_Normal(); |
| 1053 } |
| 1054 |
| 1055 // -------------- Fields -------------- |
| 1056 ASSERT(lookup->property_encoding() == LookupIterator::DESCRIPTOR); |
| 1057 if (lookup->property_details().type() == FIELD) { |
| 1058 FieldIndex field = lookup->GetFieldIndex(); |
| 1059 if (receiver_is_holder) { |
| 1060 return SimpleFieldLoad(field); |
| 1061 } |
| 1062 return compiler.CompileLoadField(name, field, lookup->representation()); |
| 1063 } |
| 1064 |
| 1065 // -------------- Constant properties -------------- |
| 1066 ASSERT(lookup->property_details().type() == CONSTANT); |
| 1067 Handle<Object> constant = lookup->GetDataValue(); |
| 1068 return compiler.CompileLoadConstant(name, constant); |
| 1039 } | 1069 } |
| 1040 | 1070 |
| 1041 | 1071 |
| 1042 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1072 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
| 1043 // This helper implements a few common fast cases for converting | 1073 // This helper implements a few common fast cases for converting |
| 1044 // non-smi keys of keyed loads/stores to a smi or a string. | 1074 // non-smi keys of keyed loads/stores to a smi or a string. |
| 1045 if (key->IsHeapNumber()) { | 1075 if (key->IsHeapNumber()) { |
| 1046 double value = Handle<HeapNumber>::cast(key)->value(); | 1076 double value = Handle<HeapNumber>::cast(key)->value(); |
| 1047 if (std::isnan(value)) { | 1077 if (std::isnan(value)) { |
| 1048 key = isolate->factory()->nan_string(); | 1078 key = isolate->factory()->nan_string(); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 | 1400 |
| 1371 void StoreIC::UpdateCaches(LookupResult* lookup, | 1401 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1372 Handle<JSObject> receiver, | 1402 Handle<JSObject> receiver, |
| 1373 Handle<String> name, | 1403 Handle<String> name, |
| 1374 Handle<Object> value) { | 1404 Handle<Object> value) { |
| 1375 ASSERT(lookup->IsFound()); | 1405 ASSERT(lookup->IsFound()); |
| 1376 | 1406 |
| 1377 // These are not cacheable, so we never see such LookupResults here. | 1407 // These are not cacheable, so we never see such LookupResults here. |
| 1378 ASSERT(!lookup->IsHandler()); | 1408 ASSERT(!lookup->IsHandler()); |
| 1379 | 1409 |
| 1380 Handle<Code> code = ComputeHandler(lookup, receiver, name, value); | 1410 Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value); |
| 1381 | 1411 |
| 1382 PatchCache(name, code); | 1412 PatchCache(name, code); |
| 1383 TRACE_IC("StoreIC", name); | 1413 TRACE_IC("StoreIC", name); |
| 1384 } | 1414 } |
| 1385 | 1415 |
| 1386 | 1416 |
| 1387 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, | 1417 Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup, |
| 1388 Handle<Object> object, Handle<String> name, | 1418 Handle<Object> object, |
| 1389 Handle<Object> value, | 1419 Handle<String> name, |
| 1390 CacheHolderFlag cache_holder) { | 1420 Handle<Object> value, |
| 1421 CacheHolderFlag cache_holder) { |
| 1391 if (object->IsAccessCheckNeeded()) return slow_stub(); | 1422 if (object->IsAccessCheckNeeded()) return slow_stub(); |
| 1392 ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS || | 1423 ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS || |
| 1393 (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject())); | 1424 (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject())); |
| 1394 // This is currently guaranteed by checks in StoreIC::Store. | 1425 // This is currently guaranteed by checks in StoreIC::Store. |
| 1395 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1426 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1396 | 1427 |
| 1397 Handle<JSObject> holder(lookup->holder()); | 1428 Handle<JSObject> holder(lookup->holder()); |
| 1398 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); | 1429 NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
| 1399 | 1430 |
| 1400 if (lookup->IsTransition()) { | 1431 if (lookup->IsTransition()) { |
| (...skipping 1652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3053 #undef ADDR | 3084 #undef ADDR |
| 3054 }; | 3085 }; |
| 3055 | 3086 |
| 3056 | 3087 |
| 3057 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 3088 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 3058 return IC_utilities[id]; | 3089 return IC_utilities[id]; |
| 3059 } | 3090 } |
| 3060 | 3091 |
| 3061 | 3092 |
| 3062 } } // namespace v8::internal | 3093 } } // namespace v8::internal |
| OLD | NEW |