| 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" |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |