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

Side by Side Diff: src/ic.cc

Issue 400523007: Cache IC handlers on the prototype's map if possible (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: addressed comment Created 6 years, 5 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/ic-inl.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"
11 #include "src/conversions.h" 11 #include "src/conversions.h"
12 #include "src/execution.h" 12 #include "src/execution.h"
13 #include "src/ic-inl.h" 13 #include "src/ic-inl.h"
14 #include "src/prototype.h" 14 #include "src/prototype.h"
15 #include "src/runtime.h" 15 #include "src/runtime.h"
16 #include "src/stub-cache.h" 16 #include "src/stub-cache.h"
17 17
18 namespace v8 { 18 namespace v8 {
19 namespace internal { 19 namespace internal {
20 20
21 char IC::TransitionMarkFromState(IC::State state) { 21 char IC::TransitionMarkFromState(IC::State state) {
22 switch (state) { 22 switch (state) {
23 case UNINITIALIZED: return '0'; 23 case UNINITIALIZED: return '0';
24 case PREMONOMORPHIC: return '.'; 24 case PREMONOMORPHIC: return '.';
25 case MONOMORPHIC: return '1'; 25 case MONOMORPHIC: return '1';
26 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; 26 case PROTOTYPE_FAILURE:
27 return '^';
27 case POLYMORPHIC: return 'P'; 28 case POLYMORPHIC: return 'P';
28 case MEGAMORPHIC: return 'N'; 29 case MEGAMORPHIC: return 'N';
29 case GENERIC: return 'G'; 30 case GENERIC: return 'G';
30 31
31 // We never see the debugger states here, because the state is 32 // We never see the debugger states here, because the state is
32 // computed from the original code - not the patched code. Let 33 // computed from the original code - not the patched code. Let
33 // these cases fall through to the unreachable code below. 34 // these cases fall through to the unreachable code below.
34 case DEBUG_STUB: break; 35 case DEBUG_STUB: break;
35 } 36 }
36 UNREACHABLE(); 37 UNREACHABLE();
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 return; 230 return;
230 } 231 }
231 232
232 object = PrototypeIterator::GetCurrent(iter); 233 object = PrototypeIterator::GetCurrent(iter);
233 } 234 }
234 } 235 }
235 236
236 237
237 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, 238 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
238 Handle<String> name) { 239 Handle<String> name) {
239 if (!IsNameCompatibleWithMonomorphicPrototypeFailure(name)) return false; 240 if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
241 Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
242 maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
240 243
241 InlineCacheHolderFlag cache_holder = 244 // The current map wasn't handled yet. There's no reason to stay monomorphic,
242 Code::ExtractCacheHolderFromFlags(target()->flags()); 245 // *unless* we're moving from a deprecated map to its replacement, or
243 246 // to a more general elements kind.
244 switch (cache_holder) { 247 // TODO(verwaest): Check if the current map is actually what the old map
245 case OWN_MAP: 248 // would transition to.
246 // The stub was generated for JSObject but called for non-JSObject. 249 if (maybe_handler_.is_null()) {
247 // IC::GetCodeCacheHolder is not applicable. 250 if (!receiver_map->IsJSObjectMap()) return false;
248 if (!receiver->IsJSObject()) return false; 251 Map* first_map = FirstTargetMap();
249 break; 252 if (first_map == NULL) return false;
250 case PROTOTYPE_MAP: 253 Handle<Map> old_map(first_map);
251 // IC::GetCodeCacheHolder is not applicable. 254 if (old_map->is_deprecated()) return true;
252 PrototypeIterator iter(isolate(), receiver); 255 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
253 if (iter.IsAtEnd()) return false; 256 receiver_map->elements_kind())) {
254 break; 257 return true;
258 }
259 return false;
255 } 260 }
256 261
257 Handle<Map> map( 262 CacheHolderFlag flag;
258 IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map()); 263 Handle<Map> ic_holder_map(
264 GetICCacheHolder(*receiver_type(), isolate(), &flag));
259 265
260 // Decide whether the inline cache failed because of changes to the 266 ASSERT(flag != kCacheOnReceiver || receiver->IsJSObject());
261 // receiver itself or changes to one of its prototypes. 267 ASSERT(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
262 // 268 ASSERT(flag != kCacheOnPrototypeReceiverIsDictionary);
263 // If there are changes to the receiver itself, the map of the
264 // receiver will have changed and the current target will not be in
265 // the receiver map's code cache. Therefore, if the current target
266 // is in the receiver map's code cache, the inline cache failed due
267 // to prototype check failure.
268 int index = map->IndexInCodeCache(*name, *target());
269 if (index >= 0) {
270 map->RemoveFromCodeCache(*name, *target(), index);
271 // Handlers are stored in addition to the ICs on the map. Remove those, too.
272 TryRemoveInvalidHandlers(map, name);
273 return true;
274 }
275 269
276 // The stub is not in the cache. We've ruled out all other kinds of failure 270 if (state() == MONOMORPHIC) {
277 // except for proptotype chain changes, a deprecated map, a map that's 271 int index = ic_holder_map->IndexInCodeCache(*name, *target());
278 // different from the one that the stub expects, elements kind changes, or a 272 if (index >= 0) {
279 // constant global property that will become mutable. Threat all those 273 ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
280 // situations as prototype failures (stay monomorphic if possible).
281
282 // If the IC is shared between multiple receivers (slow dictionary mode), then
283 // the map cannot be deprecated and the stub invalidated.
284 if (cache_holder == OWN_MAP) {
285 Map* old_map = FirstTargetMap();
286 if (old_map == *map) return true;
287 if (old_map != NULL) {
288 if (old_map->is_deprecated()) return true;
289 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
290 map->elements_kind())) {
291 return true;
292 }
293 } 274 }
294 } 275 }
295 276
296 if (receiver->IsGlobalObject()) { 277 if (receiver->IsGlobalObject()) {
297 LookupResult lookup(isolate()); 278 LookupResult lookup(isolate());
298 GlobalObject* global = GlobalObject::cast(*receiver); 279 GlobalObject* global = GlobalObject::cast(*receiver);
299 global->LookupOwnRealNamedProperty(name, &lookup); 280 global->LookupOwnRealNamedProperty(name, &lookup);
300 if (!lookup.IsFound()) return false; 281 if (!lookup.IsFound()) return false;
301 PropertyCell* cell = global->GetPropertyCell(&lookup); 282 PropertyCell* cell = global->GetPropertyCell(&lookup);
302 return cell->type()->IsConstant(); 283 return cell->type()->IsConstant();
303 } 284 }
304 285
305 return false; 286 return true;
306 } 287 }
307 288
308 289
309 void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) { 290 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
310 CodeHandleList handlers;
311 target()->FindHandlers(&handlers);
312 for (int i = 0; i < handlers.length(); i++) {
313 Handle<Code> handler = handlers.at(i);
314 int index = map->IndexInCodeCache(*name, *handler);
315 if (index >= 0) {
316 map->RemoveFromCodeCache(*name, *handler, index);
317 return;
318 }
319 }
320 }
321
322
323 bool IC::IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name) {
324 if (target()->is_keyed_stub()) { 291 if (target()->is_keyed_stub()) {
325 // Determine whether the failure is due to a name failure. 292 // Determine whether the failure is due to a name failure.
326 if (!name->IsName()) return false; 293 if (!name->IsName()) return false;
327 Name* stub_name = target()->FindFirstName(); 294 Name* stub_name = target()->FindFirstName();
328 if (*name != stub_name) return false; 295 if (*name != stub_name) return false;
329 } 296 }
330 297
331 return true; 298 return true;
332 } 299 }
333 300
334 301
335 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { 302 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
303 receiver_type_ = CurrentTypeOf(receiver, isolate());
336 if (!name->IsString()) return; 304 if (!name->IsString()) return;
337 if (state() != MONOMORPHIC) { 305 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
338 if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
339 TryRemoveInvalidHandlers(
340 handle(Handle<HeapObject>::cast(receiver)->map()),
341 Handle<String>::cast(name));
342 }
343 return;
344 }
345 if (receiver->IsUndefined() || receiver->IsNull()) return; 306 if (receiver->IsUndefined() || receiver->IsNull()) return;
346 307
347 // Remove the target from the code cache if it became invalid 308 // Remove the target from the code cache if it became invalid
348 // because of changes in the prototype chain to avoid hitting it 309 // because of changes in the prototype chain to avoid hitting it
349 // again. 310 // again.
350 if (TryRemoveInvalidPrototypeDependentStub( 311 if (TryRemoveInvalidPrototypeDependentStub(receiver,
351 receiver, Handle<String>::cast(name)) && 312 Handle<String>::cast(name))) {
352 TryMarkMonomorphicPrototypeFailure(name)) { 313 MarkPrototypeFailure(name);
353 return; 314 return;
354 } 315 }
355 316
356 // The builtins object is special. It only changes when JavaScript 317 // The builtins object is special. It only changes when JavaScript
357 // builtins are loaded lazily. It is important to keep inline 318 // builtins are loaded lazily. It is important to keep inline
358 // caches for the builtins object monomorphic. Therefore, if we get 319 // caches for the builtins object monomorphic. Therefore, if we get
359 // an inline cache miss for the builtins object after lazily loading 320 // an inline cache miss for the builtins object after lazily loading
360 // JavaScript builtins, we return uninitialized as the state to 321 // JavaScript builtins, we return uninitialized as the state to
361 // force the inline cache back to monomorphic state. 322 // force the inline cache back to monomorphic state.
362 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED; 323 if (receiver->IsJSBuiltinsObject()) state_ = UNINITIALIZED;
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 if (!receiver_maps->at(current).is_null() && 642 if (!receiver_maps->at(current).is_null() &&
682 receiver_maps->at(current).is_identical_to(new_receiver_map)) { 643 receiver_maps->at(current).is_identical_to(new_receiver_map)) {
683 return false; 644 return false;
684 } 645 }
685 } 646 }
686 receiver_maps->Add(new_receiver_map); 647 receiver_maps->Add(new_receiver_map);
687 return true; 648 return true;
688 } 649 }
689 650
690 651
691 bool IC::UpdatePolymorphicIC(Handle<HeapType> type, 652 bool IC::UpdatePolymorphicIC(Handle<String> name, Handle<Code> code) {
692 Handle<String> name,
693 Handle<Code> code) {
694 if (!code->is_handler()) return false; 653 if (!code->is_handler()) return false;
654 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
655 Handle<HeapType> type = receiver_type();
695 TypeHandleList types; 656 TypeHandleList types;
696 CodeHandleList handlers; 657 CodeHandleList handlers;
697 658
698 TargetTypes(&types); 659 TargetTypes(&types);
699 int number_of_types = types.length(); 660 int number_of_types = types.length();
700 int deprecated_types = 0; 661 int deprecated_types = 0;
701 int handler_to_overwrite = -1; 662 int handler_to_overwrite = -1;
702 663
703 for (int i = 0; i < number_of_types; i++) { 664 for (int i = 0; i < number_of_types; i++) {
704 Handle<HeapType> current_type = types.at(i); 665 Handle<HeapType> current_type = types.at(i);
(...skipping 16 matching lines...) Expand all
721 } 682 }
722 683
723 int number_of_valid_types = 684 int number_of_valid_types =
724 number_of_types - deprecated_types - (handler_to_overwrite != -1); 685 number_of_types - deprecated_types - (handler_to_overwrite != -1);
725 686
726 if (number_of_valid_types >= 4) return false; 687 if (number_of_valid_types >= 4) return false;
727 if (number_of_types == 0) return false; 688 if (number_of_types == 0) return false;
728 if (!target()->FindHandlers(&handlers, types.length())) return false; 689 if (!target()->FindHandlers(&handlers, types.length())) return false;
729 690
730 number_of_valid_types++; 691 number_of_valid_types++;
731 if (handler_to_overwrite >= 0) { 692 if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
732 handlers.Set(handler_to_overwrite, code); 693 Handle<Code> ic;
733 if (!type->NowIs(types.at(handler_to_overwrite))) { 694 if (number_of_valid_types == 1) {
734 types.Set(handler_to_overwrite, type); 695 ic = isolate()->stub_cache()->ComputeMonomorphicIC(kind(), name, type, code,
696 extra_ic_state());
697 } else {
698 if (handler_to_overwrite >= 0) {
699 handlers.Set(handler_to_overwrite, code);
700 if (!type->NowIs(types.at(handler_to_overwrite))) {
701 types.Set(handler_to_overwrite, type);
702 }
703 } else {
704 types.Add(type);
705 handlers.Add(code);
735 } 706 }
736 } else { 707 ic = isolate()->stub_cache()->ComputePolymorphicIC(
737 types.Add(type); 708 kind(), &types, &handlers, number_of_valid_types, name,
738 handlers.Add(code); 709 extra_ic_state());
739 } 710 }
740
741 Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
742 kind(), &types, &handlers, number_of_valid_types, name, extra_ic_state());
743 set_target(*ic); 711 set_target(*ic);
744 return true; 712 return true;
745 } 713 }
746 714
747 715
748 Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) { 716 Handle<HeapType> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) {
749 return object->IsJSGlobalObject() 717 return object->IsJSGlobalObject()
750 ? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate) 718 ? HeapType::Constant(Handle<JSGlobalObject>::cast(object), isolate)
751 : HeapType::NowOf(object, isolate); 719 : HeapType::NowOf(object, isolate);
752 } 720 }
(...skipping 27 matching lines...) Expand all
780 748
781 749
782 template 750 template
783 Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone); 751 Type* IC::MapToType<Type>(Handle<Map> map, Zone* zone);
784 752
785 753
786 template 754 template
787 Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, Isolate* region); 755 Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, Isolate* region);
788 756
789 757
790 void IC::UpdateMonomorphicIC(Handle<HeapType> type, 758 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name) {
791 Handle<Code> handler,
792 Handle<String> name) {
793 if (!handler->is_handler()) return set_target(*handler); 759 if (!handler->is_handler()) return set_target(*handler);
794 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( 760 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
795 kind(), name, type, handler, extra_ic_state()); 761 kind(), name, receiver_type(), handler, extra_ic_state());
796 set_target(*ic); 762 set_target(*ic);
797 } 763 }
798 764
799 765
800 void IC::CopyICToMegamorphicCache(Handle<String> name) { 766 void IC::CopyICToMegamorphicCache(Handle<String> name) {
801 TypeHandleList types; 767 TypeHandleList types;
802 CodeHandleList handlers; 768 CodeHandleList handlers;
803 TargetTypes(&types); 769 TargetTypes(&types);
804 if (!target()->FindHandlers(&handlers, types.length())) return; 770 if (!target()->FindHandlers(&handlers, types.length())) return;
805 for (int i = 0; i < types.length(); i++) { 771 for (int i = 0; i < types.length(); i++) {
(...skipping 10 matching lines...) Expand all
816 IsMoreGeneralElementsKindTransition( 782 IsMoreGeneralElementsKindTransition(
817 source_map->elements_kind(), target_elements_kind); 783 source_map->elements_kind(), target_elements_kind);
818 Map* transitioned_map = more_general_transition 784 Map* transitioned_map = more_general_transition
819 ? source_map->LookupElementsTransitionMap(target_elements_kind) 785 ? source_map->LookupElementsTransitionMap(target_elements_kind)
820 : NULL; 786 : NULL;
821 787
822 return transitioned_map == target_map; 788 return transitioned_map == target_map;
823 } 789 }
824 790
825 791
826 void IC::PatchCache(Handle<HeapType> type, 792 void IC::PatchCache(Handle<String> name, Handle<Code> code) {
827 Handle<String> name,
828 Handle<Code> code) {
829 switch (state()) { 793 switch (state()) {
830 case UNINITIALIZED: 794 case UNINITIALIZED:
831 case PREMONOMORPHIC: 795 case PREMONOMORPHIC:
832 case MONOMORPHIC_PROTOTYPE_FAILURE: 796 UpdateMonomorphicIC(code, name);
833 UpdateMonomorphicIC(type, code, name);
834 break; 797 break;
835 case MONOMORPHIC: // Fall through. 798 case PROTOTYPE_FAILURE:
799 case MONOMORPHIC:
836 case POLYMORPHIC: 800 case POLYMORPHIC:
837 if (!target()->is_keyed_stub()) { 801 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
838 if (UpdatePolymorphicIC(type, name, code)) break; 802 if (UpdatePolymorphicIC(name, code)) break;
839 CopyICToMegamorphicCache(name); 803 CopyICToMegamorphicCache(name);
840 } 804 }
841 if (FLAG_compiled_keyed_generic_loads && (kind() == Code::LOAD_IC)) { 805 if (FLAG_compiled_keyed_generic_loads && (kind() == Code::LOAD_IC)) {
842 set_target(*generic_stub()); 806 set_target(*generic_stub());
843 break; 807 break;
844 } 808 }
845 set_target(*megamorphic_stub()); 809 set_target(*megamorphic_stub());
846 // Fall through. 810 // Fall through.
847 case MEGAMORPHIC: 811 case MEGAMORPHIC:
848 UpdateMegamorphicCache(*type, *name, *code); 812 UpdateMegamorphicCache(*receiver_type(), *name, *code);
849 break; 813 break;
850 case DEBUG_STUB: 814 case DEBUG_STUB:
851 break; 815 break;
852 case GENERIC: 816 case GENERIC:
853 UNREACHABLE(); 817 UNREACHABLE();
854 break; 818 break;
855 } 819 }
856 } 820 }
857 821
858 822
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
894 Handle<String> name) { 858 Handle<String> name) {
895 if (state() == UNINITIALIZED) { 859 if (state() == UNINITIALIZED) {
896 // This is the first time we execute this inline cache. 860 // This is the first time we execute this inline cache.
897 // Set the target to the pre monomorphic stub to delay 861 // Set the target to the pre monomorphic stub to delay
898 // setting the monomorphic state. 862 // setting the monomorphic state.
899 set_target(*pre_monomorphic_stub()); 863 set_target(*pre_monomorphic_stub());
900 TRACE_IC("LoadIC", name); 864 TRACE_IC("LoadIC", name);
901 return; 865 return;
902 } 866 }
903 867
904 Handle<HeapType> type = CurrentTypeOf(object, isolate());
905 Handle<Code> code; 868 Handle<Code> code;
906 if (!lookup->IsCacheable()) { 869 if (!lookup->IsCacheable()) {
907 // Bail out if the result is not cacheable. 870 // Bail out if the result is not cacheable.
908 code = slow_stub(); 871 code = slow_stub();
909 } else if (!lookup->IsProperty()) { 872 } else if (!lookup->IsProperty()) {
910 if (kind() == Code::LOAD_IC) { 873 if (kind() == Code::LOAD_IC) {
911 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, type); 874 code = isolate()->stub_cache()->ComputeLoadNonexistent(name,
875 receiver_type());
876 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
877 if (code.is_null()) code = slow_stub();
912 } else { 878 } else {
913 code = slow_stub(); 879 code = slow_stub();
914 } 880 }
915 } else { 881 } else {
916 code = ComputeHandler(lookup, object, name); 882 code = ComputeHandler(lookup, object, name);
917 } 883 }
918 884
919 PatchCache(type, name, code); 885 PatchCache(name, code);
920 TRACE_IC("LoadIC", name); 886 TRACE_IC("LoadIC", name);
921 } 887 }
922 888
923 889
924 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) { 890 void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
925 // Cache code holding map should be consistent with 891 // Cache code holding map should be consistent with
926 // GenerateMonomorphicCacheProbe. 892 // GenerateMonomorphicCacheProbe.
927 Map* map = *TypeToMap(type, isolate()); 893 Map* map = *TypeToMap(type, isolate());
928 isolate()->stub_cache()->Set(name, map, code); 894 isolate()->stub_cache()->Set(name, map, code);
929 } 895 }
930 896
931 897
932 Handle<Code> IC::ComputeHandler(LookupResult* lookup, 898 Handle<Code> IC::ComputeHandler(LookupResult* lookup,
933 Handle<Object> object, 899 Handle<Object> object,
934 Handle<String> name, 900 Handle<String> name,
935 Handle<Object> value) { 901 Handle<Object> value) {
936 InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object); 902 bool receiver_is_holder = lookup->ReceiverIsHolder(object);
937 Handle<HeapObject> stub_holder(GetCodeCacheHolder( 903 CacheHolderFlag flag;
938 isolate(), *object, cache_holder)); 904 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
905 *receiver_type(), receiver_is_holder, isolate(), &flag);
939 906
940 Handle<Code> code = isolate()->stub_cache()->FindHandler( 907 Handle<Code> code = isolate()->stub_cache()->FindHandler(
941 name, handle(stub_holder->map()), kind(), cache_holder, 908 name, stub_holder_map, kind(), flag,
942 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL); 909 lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
910 // Use the cached value if it exists, and if it is different from the
911 // handler that just missed.
943 if (!code.is_null()) { 912 if (!code.is_null()) {
944 return code; 913 if (!maybe_handler_.is_null() &&
914 !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
915 return code;
916 }
917 if (maybe_handler_.is_null()) {
918 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
919 // In MEGAMORPHIC case, check if the handler in the megamorphic stub
920 // cache (which just missed) is different from the cached handler.
921 if (state() == MEGAMORPHIC && object->IsHeapObject()) {
922 Map* map = Handle<HeapObject>::cast(object)->map();
923 Code* megamorphic_cached_code =
924 isolate()->stub_cache()->Get(*name, map, code->flags());
925 if (megamorphic_cached_code != *code) return code;
926 } else {
927 return code;
928 }
929 }
945 } 930 }
946 931
947 code = CompileHandler(lookup, object, name, value, cache_holder); 932 code = CompileHandler(lookup, object, name, value, flag);
948 ASSERT(code->is_handler()); 933 ASSERT(code->is_handler());
949 934
950 if (code->type() != Code::NORMAL) { 935 if (code->type() != Code::NORMAL) {
951 HeapObject::UpdateMapCodeCache(stub_holder, name, code); 936 Map::UpdateCodeCache(stub_holder_map, name, code);
952 } 937 }
953 938
954 return code; 939 return code;
955 } 940 }
956 941
957 942
958 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, 943 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
959 Handle<Object> object, 944 Handle<String> name, Handle<Object> unused,
960 Handle<String> name, 945 CacheHolderFlag cache_holder) {
961 Handle<Object> unused,
962 InlineCacheHolderFlag cache_holder) {
963 if (object->IsString() && 946 if (object->IsString() &&
964 String::Equals(isolate()->factory()->length_string(), name)) { 947 String::Equals(isolate()->factory()->length_string(), name)) {
965 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); 948 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
966 return SimpleFieldLoad(index); 949 return SimpleFieldLoad(index);
967 } 950 }
968 951
969 if (object->IsStringWrapper() && 952 if (object->IsStringWrapper() &&
970 String::Equals(isolate()->factory()->length_string(), name)) { 953 String::Equals(isolate()->factory()->length_string(), name)) {
971 if (kind() == Code::LOAD_IC) { 954 if (kind() == Code::LOAD_IC) {
972 StringLengthStub string_length_stub(isolate()); 955 StringLengthStub string_length_stub(isolate());
973 return string_length_stub.GetCode(); 956 return string_length_stub.GetCode();
974 } else { 957 } else {
975 KeyedStringLengthStub string_length_stub(isolate()); 958 KeyedStringLengthStub string_length_stub(isolate());
976 return string_length_stub.GetCode(); 959 return string_length_stub.GetCode();
977 } 960 }
978 } 961 }
979 962
980 Handle<HeapType> type = CurrentTypeOf(object, isolate()); 963 Handle<HeapType> type = receiver_type();
981 Handle<JSObject> holder(lookup->holder()); 964 Handle<JSObject> holder(lookup->holder());
965 bool receiver_is_holder = object.is_identical_to(holder);
982 LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind()); 966 LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
983 967
984 switch (lookup->type()) { 968 switch (lookup->type()) {
985 case FIELD: { 969 case FIELD: {
986 FieldIndex field = lookup->GetFieldIndex(); 970 FieldIndex field = lookup->GetFieldIndex();
987 if (object.is_identical_to(holder)) { 971 if (receiver_is_holder) {
988 return SimpleFieldLoad(field); 972 return SimpleFieldLoad(field);
989 } 973 }
990 return compiler.CompileLoadField( 974 return compiler.CompileLoadField(
991 type, holder, name, field, lookup->representation()); 975 type, holder, name, field, lookup->representation());
992 } 976 }
993 case CONSTANT: { 977 case CONSTANT: {
994 Handle<Object> constant(lookup->GetConstant(), isolate()); 978 Handle<Object> constant(lookup->GetConstant(), isolate());
995 return compiler.CompileLoadConstant(type, holder, name, constant); 979 return compiler.CompileLoadConstant(type, holder, name, constant);
996 } 980 }
997 case NORMAL: 981 case NORMAL:
998 if (kind() != Code::LOAD_IC) break; 982 if (kind() != Code::LOAD_IC) break;
999 if (holder->IsGlobalObject()) { 983 if (holder->IsGlobalObject()) {
1000 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 984 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
1001 Handle<PropertyCell> cell( 985 Handle<PropertyCell> cell(
1002 global->GetPropertyCell(lookup), isolate()); 986 global->GetPropertyCell(lookup), isolate());
1003 Handle<Code> code = compiler.CompileLoadGlobal( 987 Handle<Code> code = compiler.CompileLoadGlobal(
1004 type, global, cell, name, lookup->IsDontDelete()); 988 type, global, cell, name, lookup->IsDontDelete());
1005 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. 989 // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
1006 Handle<HeapObject> stub_holder(GetCodeCacheHolder( 990 CacheHolderFlag flag;
1007 isolate(), *object, cache_holder)); 991 Handle<Map> stub_holder_map =
1008 HeapObject::UpdateMapCodeCache(stub_holder, name, code); 992 GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
993 Map::UpdateCodeCache(stub_holder_map, name, code);
1009 return code; 994 return code;
1010 } 995 }
1011 // There is only one shared stub for loading normalized 996 // There is only one shared stub for loading normalized
1012 // properties. It does not traverse the prototype chain, so the 997 // properties. It does not traverse the prototype chain, so the
1013 // property must be found in the object for the stub to be 998 // property must be found in the object for the stub to be
1014 // applicable. 999 // applicable.
1015 if (!object.is_identical_to(holder)) break; 1000 if (!receiver_is_holder) break;
1016 return isolate()->builtins()->LoadIC_Normal(); 1001 return isolate()->builtins()->LoadIC_Normal();
1017 case CALLBACKS: { 1002 case CALLBACKS: {
1018 // Use simple field loads for some well-known callback properties. 1003 // Use simple field loads for some well-known callback properties.
1019 if (object->IsJSObject()) { 1004 if (receiver_is_holder) {
1005 ASSERT(object->IsJSObject());
1020 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1006 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1021 Handle<Map> map(receiver->map());
1022 Handle<HeapType> type = IC::MapToType<HeapType>(
1023 handle(receiver->map()), isolate());
1024 int object_offset; 1007 int object_offset;
1025 if (Accessors::IsJSObjectFieldAccessor<HeapType>( 1008 if (Accessors::IsJSObjectFieldAccessor<HeapType>(
1026 type, name, &object_offset)) { 1009 type, name, &object_offset)) {
1027 FieldIndex index = FieldIndex::ForInObjectOffset( 1010 FieldIndex index = FieldIndex::ForInObjectOffset(
1028 object_offset, receiver->map()); 1011 object_offset, receiver->map());
1029 return SimpleFieldLoad(index); 1012 return SimpleFieldLoad(index);
1030 } 1013 }
1031 } 1014 }
1032 1015
1033 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); 1016 Handle<Object> callback(lookup->GetCallbackObject(), isolate());
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
1263 Representation field_representation = value->OptimalRepresentation(); 1246 Representation field_representation = value->OptimalRepresentation();
1264 Handle<HeapType> field_type = value->OptimalType( 1247 Handle<HeapType> field_type = value->OptimalType(
1265 lookup->isolate(), field_representation); 1248 lookup->isolate(), field_representation);
1266 Map::GeneralizeRepresentation( 1249 Map::GeneralizeRepresentation(
1267 target, target->LastAdded(), 1250 target, target->LastAdded(),
1268 field_representation, field_type, FORCE_FIELD); 1251 field_representation, field_type, FORCE_FIELD);
1269 // Lookup the transition again since the transition tree may have changed 1252 // Lookup the transition again since the transition tree may have changed
1270 // entirely by the migration above. 1253 // entirely by the migration above.
1271 receiver->map()->LookupTransition(*holder, *name, lookup); 1254 receiver->map()->LookupTransition(*holder, *name, lookup);
1272 if (!lookup->IsTransition()) return false; 1255 if (!lookup->IsTransition()) return false;
1273 return ic->TryMarkMonomorphicPrototypeFailure(name); 1256 if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
1257 ic->MarkPrototypeFailure(name);
1258 return true;
1274 } 1259 }
1275 1260
1276 return true; 1261 return true;
1277 } 1262 }
1278 1263
1279 1264
1280 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, 1265 MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
1281 Handle<String> name, 1266 Handle<String> name,
1282 Handle<Object> value, 1267 Handle<Object> value,
1283 JSReceiver::StoreFromKeyed store_mode) { 1268 JSReceiver::StoreFromKeyed store_mode) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 Handle<JSObject> receiver, 1394 Handle<JSObject> receiver,
1410 Handle<String> name, 1395 Handle<String> name,
1411 Handle<Object> value) { 1396 Handle<Object> value) {
1412 ASSERT(lookup->IsFound()); 1397 ASSERT(lookup->IsFound());
1413 1398
1414 // These are not cacheable, so we never see such LookupResults here. 1399 // These are not cacheable, so we never see such LookupResults here.
1415 ASSERT(!lookup->IsHandler()); 1400 ASSERT(!lookup->IsHandler());
1416 1401
1417 Handle<Code> code = ComputeHandler(lookup, receiver, name, value); 1402 Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
1418 1403
1419 PatchCache(CurrentTypeOf(receiver, isolate()), name, code); 1404 PatchCache(name, code);
1420 TRACE_IC("StoreIC", name); 1405 TRACE_IC("StoreIC", name);
1421 } 1406 }
1422 1407
1423 1408
1424 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, 1409 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
1425 Handle<Object> object, 1410 Handle<Object> object, Handle<String> name,
1426 Handle<String> name,
1427 Handle<Object> value, 1411 Handle<Object> value,
1428 InlineCacheHolderFlag cache_holder) { 1412 CacheHolderFlag cache_holder) {
1429 if (object->IsAccessCheckNeeded()) return slow_stub(); 1413 if (object->IsAccessCheckNeeded()) return slow_stub();
1430 ASSERT(cache_holder == OWN_MAP); 1414 ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
1415 (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
1431 // This is currently guaranteed by checks in StoreIC::Store. 1416 // This is currently guaranteed by checks in StoreIC::Store.
1432 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1417 Handle<JSObject> receiver = Handle<JSObject>::cast(object);
1433 1418
1434 Handle<JSObject> holder(lookup->holder()); 1419 Handle<JSObject> holder(lookup->holder());
1435 // Handlers do not use strict mode. 1420 // Handlers do not use strict mode.
1436 StoreStubCompiler compiler(isolate(), SLOPPY, kind()); 1421 StoreStubCompiler compiler(isolate(), SLOPPY, kind());
1437 if (lookup->IsTransition()) { 1422 if (lookup->IsTransition()) {
1438 // Explicitly pass in the receiver map since LookupForWrite may have 1423 // Explicitly pass in the receiver map since LookupForWrite may have
1439 // stored something else than the receiver in the holder. 1424 // stored something else than the receiver in the holder.
1440 Handle<Map> transition(lookup->GetTransitionTarget()); 1425 Handle<Map> transition(lookup->GetTransitionTarget());
(...skipping 1636 matching lines...) Expand 10 before | Expand all | Expand 10 after
3077 #undef ADDR 3062 #undef ADDR
3078 }; 3063 };
3079 3064
3080 3065
3081 Address IC::AddressFromUtilityId(IC::UtilityId id) { 3066 Address IC::AddressFromUtilityId(IC::UtilityId id) {
3082 return IC_utilities[id]; 3067 return IC_utilities[id];
3083 } 3068 }
3084 3069
3085 3070
3086 } } // namespace v8::internal 3071 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/ic.h ('k') | src/ic-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698