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 |