Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: src/ic.cc

Issue 478043006: Rewrite StoreIC handling using the LookupIterator. Continued from patch 494153002 (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ic.h ('k') | src/lookup.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/lookup.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698