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/ic/ic.h" | 5 #include "src/ic/ic.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/api-arguments.h" | 9 #include "src/api-arguments.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 namespace internal { | 31 namespace internal { |
32 | 32 |
33 char IC::TransitionMarkFromState(IC::State state) { | 33 char IC::TransitionMarkFromState(IC::State state) { |
34 switch (state) { | 34 switch (state) { |
35 case UNINITIALIZED: | 35 case UNINITIALIZED: |
36 return '0'; | 36 return '0'; |
37 case PREMONOMORPHIC: | 37 case PREMONOMORPHIC: |
38 return '.'; | 38 return '.'; |
39 case MONOMORPHIC: | 39 case MONOMORPHIC: |
40 return '1'; | 40 return '1'; |
41 case PROTOTYPE_FAILURE: | 41 case RECOMPUTE_HANDLER: |
42 return '^'; | 42 return '^'; |
43 case POLYMORPHIC: | 43 case POLYMORPHIC: |
44 return 'P'; | 44 return 'P'; |
45 case MEGAMORPHIC: | 45 case MEGAMORPHIC: |
46 return 'N'; | 46 return 'N'; |
47 case GENERIC: | 47 case GENERIC: |
48 return 'G'; | 48 return 'G'; |
49 | 49 |
50 // We never see the debugger states here, because the state is | 50 // We never see the debugger states here, because the state is |
51 // computed from the original code - not the patched code. Let | 51 // computed from the original code - not the patched code. Let |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 } | 251 } |
252 return; | 252 return; |
253 case LookupIterator::ACCESSOR: | 253 case LookupIterator::ACCESSOR: |
254 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 254 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
255 case LookupIterator::DATA: | 255 case LookupIterator::DATA: |
256 return; | 256 return; |
257 } | 257 } |
258 } | 258 } |
259 } | 259 } |
260 | 260 |
261 | 261 bool IC::ShouldRecomputeHandler(Handle<Object> receiver, Handle<String> name) { |
262 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, | 262 if (!RecomputeHandlerForName(name)) return false; |
263 Handle<String> name) { | |
264 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; | |
265 if (UseVector()) { | 263 if (UseVector()) { |
266 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map()); | 264 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map()); |
267 } else { | 265 } else { |
268 maybe_handler_ = target()->FindHandlerForMap(*receiver_map()); | 266 maybe_handler_ = target()->FindHandlerForMap(*receiver_map()); |
269 } | 267 } |
270 | 268 |
271 // The current map wasn't handled yet. There's no reason to stay monomorphic, | 269 // The current map wasn't handled yet. There's no reason to stay monomorphic, |
272 // *unless* we're moving from a deprecated map to its replacement, or | 270 // *unless* we're moving from a deprecated map to its replacement, or |
273 // to a more general elements kind. | 271 // to a more general elements kind. |
274 // TODO(verwaest): Check if the current map is actually what the old map | 272 // TODO(verwaest): Check if the current map is actually what the old map |
275 // would transition to. | 273 // would transition to. |
276 if (maybe_handler_.is_null()) { | 274 if (maybe_handler_.is_null()) { |
277 if (!receiver_map()->IsJSObjectMap()) return false; | 275 if (!receiver_map()->IsJSObjectMap()) return false; |
278 Map* first_map = FirstTargetMap(); | 276 Map* first_map = FirstTargetMap(); |
279 if (first_map == NULL) return false; | 277 if (first_map == NULL) return false; |
280 Handle<Map> old_map(first_map); | 278 Handle<Map> old_map(first_map); |
281 if (old_map->is_deprecated()) return true; | 279 if (old_map->is_deprecated()) return true; |
282 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(), | 280 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(), |
283 receiver_map()->elements_kind()); | 281 receiver_map()->elements_kind()); |
284 } | 282 } |
285 | 283 |
286 CacheHolderFlag flag; | |
287 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag)); | |
288 | |
289 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject()); | |
290 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver()); | |
291 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary); | |
292 | |
293 if (state() == MONOMORPHIC) { | |
294 int index = ic_holder_map->IndexInCodeCache(*name, *target()); | |
295 if (index >= 0) { | |
296 ic_holder_map->RemoveFromCodeCache(*name, *target(), index); | |
297 } | |
298 } | |
299 | |
300 if (receiver->IsJSGlobalObject()) { | 284 if (receiver->IsJSGlobalObject()) { |
301 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver); | 285 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver); |
302 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 286 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
303 if (it.state() == LookupIterator::ACCESS_CHECK) return false; | 287 if (it.state() == LookupIterator::ACCESS_CHECK) return false; |
304 if (!it.IsFound()) return false; | 288 if (!it.IsFound()) return false; |
305 return it.property_details().cell_type() == PropertyCellType::kConstant; | 289 return it.property_details().cell_type() == PropertyCellType::kConstant; |
306 } | 290 } |
307 | 291 |
308 return true; | 292 return true; |
309 } | 293 } |
310 | 294 |
311 | 295 bool IC::RecomputeHandlerForName(Handle<Object> name) { |
312 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) { | |
313 if (target()->is_keyed_stub()) { | 296 if (target()->is_keyed_stub()) { |
314 // Determine whether the failure is due to a name failure. | 297 // Determine whether the failure is due to a name failure. |
315 if (!name->IsName()) return false; | 298 if (!name->IsName()) return false; |
316 Name* stub_name = | 299 Name* stub_name = |
317 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName(); | 300 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName(); |
318 if (*name != stub_name) return false; | 301 if (*name != stub_name) return false; |
319 } | 302 } |
320 | 303 |
321 return true; | 304 return true; |
322 } | 305 } |
323 | 306 |
324 | 307 |
325 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { | 308 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { |
326 update_receiver_map(receiver); | 309 update_receiver_map(receiver); |
327 if (!name->IsString()) return; | 310 if (!name->IsString()) return; |
328 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; | 311 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; |
329 if (receiver->IsUndefined() || receiver->IsNull()) return; | 312 if (receiver->IsUndefined() || receiver->IsNull()) return; |
330 | 313 |
331 // Remove the target from the code cache if it became invalid | 314 // Remove the target from the code cache if it became invalid |
332 // because of changes in the prototype chain to avoid hitting it | 315 // because of changes in the prototype chain to avoid hitting it |
333 // again. | 316 // again. |
334 if (TryRemoveInvalidPrototypeDependentStub(receiver, | 317 if (ShouldRecomputeHandler(receiver, Handle<String>::cast(name))) { |
335 Handle<String>::cast(name))) { | 318 MarkRecomputeHandler(name); |
336 MarkPrototypeFailure(name); | |
337 return; | |
338 } | 319 } |
339 } | 320 } |
340 | 321 |
341 | 322 |
342 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index, | 323 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index, |
343 Handle<Object> object, Handle<Object> key) { | 324 Handle<Object> object, Handle<Object> key) { |
344 HandleScope scope(isolate()); | 325 HandleScope scope(isolate()); |
345 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object); | 326 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object); |
346 } | 327 } |
347 | 328 |
(...skipping 27 matching lines...) Expand all Loading... |
375 } | 356 } |
376 break; | 357 break; |
377 case MEGAMORPHIC: | 358 case MEGAMORPHIC: |
378 case GENERIC: | 359 case GENERIC: |
379 if (new_state == MEGAMORPHIC || new_state == GENERIC) break; | 360 if (new_state == MEGAMORPHIC || new_state == GENERIC) break; |
380 *generic_delta = -1; | 361 *generic_delta = -1; |
381 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) { | 362 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) { |
382 *polymorphic_delta = 1; | 363 *polymorphic_delta = 1; |
383 } | 364 } |
384 break; | 365 break; |
385 case PROTOTYPE_FAILURE: | 366 case RECOMPUTE_HANDLER: |
386 case DEBUG_STUB: | 367 case DEBUG_STUB: |
387 UNREACHABLE(); | 368 UNREACHABLE(); |
388 } | 369 } |
389 } | 370 } |
390 | 371 |
391 | 372 |
392 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, | 373 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, |
393 State old_state, State new_state, | 374 State old_state, State new_state, |
394 bool target_remains_ic_stub) { | 375 bool target_remains_ic_stub) { |
395 Code* host = | 376 Code* host = |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 } | 434 } |
454 | 435 |
455 | 436 |
456 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) { | 437 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) { |
457 Code* target = GetTargetAtAddress(address, constant_pool); | 438 Code* target = GetTargetAtAddress(address, constant_pool); |
458 | 439 |
459 // Don't clear debug break inline cache as it will remove the break point. | 440 // Don't clear debug break inline cache as it will remove the break point. |
460 if (target->is_debug_stub()) return; | 441 if (target->is_debug_stub()) return; |
461 | 442 |
462 switch (target->kind()) { | 443 switch (target->kind()) { |
463 case Code::LOAD_IC: | |
464 case Code::KEYED_LOAD_IC: | |
465 case Code::STORE_IC: | |
466 case Code::KEYED_STORE_IC: | |
467 return; | |
468 case Code::COMPARE_IC: | 444 case Code::COMPARE_IC: |
469 return CompareIC::Clear(isolate, address, target, constant_pool); | 445 return CompareIC::Clear(isolate, address, target, constant_pool); |
| 446 case Code::BINARY_OP_IC: |
470 case Code::CALL_IC: // CallICs are vector-based and cleared differently. | 447 case Code::CALL_IC: // CallICs are vector-based and cleared differently. |
471 case Code::BINARY_OP_IC: | 448 case Code::KEYED_LOAD_IC: |
| 449 case Code::KEYED_STORE_IC: |
| 450 case Code::LOAD_IC: |
| 451 case Code::STORE_IC: |
472 case Code::TO_BOOLEAN_IC: | 452 case Code::TO_BOOLEAN_IC: |
473 // Clearing these is tricky and does not | 453 // Clearing these is tricky and does not |
474 // make any performance difference. | 454 // make any performance difference. |
475 return; | 455 return; |
476 default: | 456 default: |
477 UNREACHABLE(); | 457 UNREACHABLE(); |
478 } | 458 } |
479 } | 459 } |
480 | 460 |
481 | 461 |
(...skipping 20 matching lines...) Expand all Loading... |
502 } | 482 } |
503 | 483 |
504 | 484 |
505 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) { | 485 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) { |
506 if (IsCleared(nexus)) return; | 486 if (IsCleared(nexus)) return; |
507 nexus->ConfigurePremonomorphic(); | 487 nexus->ConfigurePremonomorphic(); |
508 OnTypeFeedbackChanged(isolate, host); | 488 OnTypeFeedbackChanged(isolate, host); |
509 } | 489 } |
510 | 490 |
511 | 491 |
512 void StoreIC::Clear(Isolate* isolate, Address address, Code* target, | |
513 Address constant_pool) { | |
514 if (IsCleared(target)) return; | |
515 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC, | |
516 target->extra_ic_state()); | |
517 SetTargetAtAddress(address, code, constant_pool); | |
518 } | |
519 | |
520 | |
521 void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) { | 492 void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) { |
522 if (IsCleared(nexus)) return; | 493 if (IsCleared(nexus)) return; |
523 nexus->ConfigurePremonomorphic(); | 494 nexus->ConfigurePremonomorphic(); |
524 OnTypeFeedbackChanged(isolate, host); | 495 OnTypeFeedbackChanged(isolate, host); |
525 } | 496 } |
526 | 497 |
527 | 498 |
528 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target, | |
529 Address constant_pool) { | |
530 if (IsCleared(target)) return; | |
531 Handle<Code> code = pre_monomorphic_stub( | |
532 isolate, StoreICState::GetLanguageMode(target->extra_ic_state())); | |
533 SetTargetAtAddress(address, *code, constant_pool); | |
534 } | |
535 | |
536 | |
537 void KeyedStoreIC::Clear(Isolate* isolate, Code* host, | 499 void KeyedStoreIC::Clear(Isolate* isolate, Code* host, |
538 KeyedStoreICNexus* nexus) { | 500 KeyedStoreICNexus* nexus) { |
539 if (IsCleared(nexus)) return; | 501 if (IsCleared(nexus)) return; |
540 nexus->ConfigurePremonomorphic(); | 502 nexus->ConfigurePremonomorphic(); |
541 OnTypeFeedbackChanged(isolate, host); | 503 OnTypeFeedbackChanged(isolate, host); |
542 } | 504 } |
543 | 505 |
544 | 506 |
545 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, | 507 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, |
546 Address constant_pool) { | 508 Address constant_pool) { |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 return false; | 697 return false; |
736 } | 698 } |
737 } | 699 } |
738 receiver_maps->Add(new_receiver_map); | 700 receiver_maps->Add(new_receiver_map); |
739 return true; | 701 return true; |
740 } | 702 } |
741 | 703 |
742 | 704 |
743 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) { | 705 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) { |
744 if (!code->is_handler()) return false; | 706 if (!code->is_handler()) return false; |
745 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false; | 707 if (target()->is_keyed_stub() && state() != RECOMPUTE_HANDLER) return false; |
746 Handle<Map> map = receiver_map(); | 708 Handle<Map> map = receiver_map(); |
747 MapHandleList maps; | 709 MapHandleList maps; |
748 CodeHandleList handlers; | 710 CodeHandleList handlers; |
749 | 711 |
750 TargetMaps(&maps); | 712 TargetMaps(&maps); |
751 int number_of_maps = maps.length(); | 713 int number_of_maps = maps.length(); |
752 int deprecated_maps = 0; | 714 int deprecated_maps = 0; |
753 int handler_to_overwrite = -1; | 715 int handler_to_overwrite = -1; |
754 | 716 |
755 for (int i = 0; i < number_of_maps; i++) { | 717 for (int i = 0; i < number_of_maps; i++) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
836 return transitioned_map == target_map; | 798 return transitioned_map == target_map; |
837 } | 799 } |
838 | 800 |
839 | 801 |
840 void IC::PatchCache(Handle<Name> name, Handle<Code> code) { | 802 void IC::PatchCache(Handle<Name> name, Handle<Code> code) { |
841 switch (state()) { | 803 switch (state()) { |
842 case UNINITIALIZED: | 804 case UNINITIALIZED: |
843 case PREMONOMORPHIC: | 805 case PREMONOMORPHIC: |
844 UpdateMonomorphicIC(code, name); | 806 UpdateMonomorphicIC(code, name); |
845 break; | 807 break; |
846 case PROTOTYPE_FAILURE: | 808 case RECOMPUTE_HANDLER: |
847 case MONOMORPHIC: | 809 case MONOMORPHIC: |
848 case POLYMORPHIC: | 810 case POLYMORPHIC: |
849 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) { | 811 if (!target()->is_keyed_stub() || state() == RECOMPUTE_HANDLER) { |
850 if (UpdatePolymorphicIC(name, code)) break; | 812 if (UpdatePolymorphicIC(name, code)) break; |
851 // For keyed stubs, we can't know whether old handlers were for the | 813 // For keyed stubs, we can't know whether old handlers were for the |
852 // same key. | 814 // same key. |
853 CopyICToMegamorphicCache(name); | 815 CopyICToMegamorphicCache(name); |
854 } | 816 } |
855 if (UseVector()) { | 817 if (UseVector()) { |
856 ConfigureVectorState(MEGAMORPHIC); | 818 ConfigureVectorState(MEGAMORPHIC); |
857 } else { | 819 } else { |
858 set_target(*megamorphic_stub()); | 820 set_target(*megamorphic_stub()); |
859 } | 821 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
900 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode(); | 862 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode(); |
901 } | 863 } |
902 return isolate->builtins()->KeyedLoadIC_Megamorphic(); | 864 return isolate->builtins()->KeyedLoadIC_Megamorphic(); |
903 } | 865 } |
904 | 866 |
905 | 867 |
906 static Handle<Code> KeyedStoreICInitializeStubHelper( | 868 static Handle<Code> KeyedStoreICInitializeStubHelper( |
907 Isolate* isolate, LanguageMode language_mode, | 869 Isolate* isolate, LanguageMode language_mode, |
908 InlineCacheState initialization_state) { | 870 InlineCacheState initialization_state) { |
909 switch (initialization_state) { | 871 switch (initialization_state) { |
910 case UNINITIALIZED: | |
911 return is_strict(language_mode) | |
912 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict() | |
913 : isolate->builtins()->KeyedStoreIC_Initialize(); | |
914 case PREMONOMORPHIC: | |
915 return is_strict(language_mode) | |
916 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict() | |
917 : isolate->builtins()->KeyedStoreIC_PreMonomorphic(); | |
918 case MEGAMORPHIC: | 872 case MEGAMORPHIC: |
919 return is_strict(language_mode) | 873 return is_strict(language_mode) |
920 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict() | 874 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict() |
921 : isolate->builtins()->KeyedStoreIC_Megamorphic(); | 875 : isolate->builtins()->KeyedStoreIC_Megamorphic(); |
922 default: | 876 default: |
923 UNREACHABLE(); | 877 UNREACHABLE(); |
924 } | 878 } |
925 return Handle<Code>(); | 879 return Handle<Code>(); |
926 } | 880 } |
927 | 881 |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1062 | 1016 |
1063 | 1017 |
1064 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) { | 1018 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) { |
1065 bool receiver_is_holder = | 1019 bool receiver_is_holder = |
1066 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); | 1020 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); |
1067 CacheHolderFlag flag; | 1021 CacheHolderFlag flag; |
1068 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( | 1022 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( |
1069 receiver_map(), receiver_is_holder, isolate(), &flag); | 1023 receiver_map(), receiver_is_holder, isolate(), &flag); |
1070 | 1024 |
1071 Handle<Code> code = PropertyHandlerCompiler::Find( | 1025 Handle<Code> code = PropertyHandlerCompiler::Find( |
1072 lookup->name(), stub_holder_map, kind(), flag, | 1026 lookup->name(), stub_holder_map, kind(), flag); |
1073 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST); | |
1074 // Use the cached value if it exists, and if it is different from the | 1027 // Use the cached value if it exists, and if it is different from the |
1075 // handler that just missed. | 1028 // handler that just missed. |
1076 if (!code.is_null()) { | 1029 if (!code.is_null()) { |
1077 if (!maybe_handler_.is_null() && | 1030 Handle<Code> handler; |
1078 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { | 1031 if (maybe_handler_.ToHandle(&handler)) { |
1079 return code; | 1032 if (!handler.is_identical_to(code)) return code; |
1080 } | 1033 } else { |
1081 if (maybe_handler_.is_null()) { | |
1082 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. | 1034 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. |
1083 // In MEGAMORPHIC case, check if the handler in the megamorphic stub | 1035 // In MEGAMORPHIC case, check if the handler in the megamorphic stub |
1084 // cache (which just missed) is different from the cached handler. | 1036 // cache (which just missed) is different from the cached handler. |
1085 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { | 1037 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { |
1086 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); | 1038 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); |
1087 Code* megamorphic_cached_code = | 1039 Code* megamorphic_cached_code = |
1088 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags()); | 1040 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags()); |
1089 if (megamorphic_cached_code != *code) return code; | 1041 if (megamorphic_cached_code != *code) return code; |
1090 } else { | 1042 } else { |
1091 return code; | 1043 return code; |
1092 } | 1044 } |
1093 } | 1045 } |
1094 } | 1046 } |
1095 | 1047 |
1096 code = CompileHandler(lookup, value, flag); | 1048 code = CompileHandler(lookup, value, flag); |
1097 DCHECK(code->is_handler()); | 1049 DCHECK(code->is_handler()); |
1098 | 1050 |
1099 // TODO(mvstanton): we'd only like to cache code on the map when it's custom | 1051 // TODO(mvstanton): we'd only like to cache code on the map when it's custom |
1100 // code compiled for this map, otherwise it's already cached in the global | 1052 // code compiled for this map, otherwise it's already cached in the global |
1101 // code cache. We are also guarding against installing code with flags that | 1053 // code cache. We are also guarding against installing code with flags that |
1102 // don't match the desired CacheHolderFlag computed above, which would lead to | 1054 // don't match the desired CacheHolderFlag computed above, which would lead to |
1103 // invalid lookups later. | 1055 // invalid lookups later. |
1104 if (code->type() != Code::NORMAL && | 1056 bool is_normal = receiver_is_holder && |
1105 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) { | 1057 !lookup->GetHolder<JSReceiver>()->HasFastProperties(); |
| 1058 if (!is_normal && Code::ExtractCacheHolderFromFlags(code->flags()) == flag) { |
1106 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); | 1059 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); |
1107 } | 1060 } |
1108 | 1061 |
1109 return code; | 1062 return code; |
1110 } | 1063 } |
1111 | 1064 |
1112 | 1065 |
1113 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, | 1066 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, |
1114 Handle<Object> unused, | 1067 Handle<Object> unused, |
1115 CacheHolderFlag cache_holder) { | 1068 CacheHolderFlag cache_holder) { |
(...skipping 518 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1634 Handle<Code> StoreIC::slow_stub() const { | 1587 Handle<Code> StoreIC::slow_stub() const { |
1635 if (kind() == Code::STORE_IC) { | 1588 if (kind() == Code::STORE_IC) { |
1636 return isolate()->builtins()->StoreIC_Slow(); | 1589 return isolate()->builtins()->StoreIC_Slow(); |
1637 } else { | 1590 } else { |
1638 DCHECK(kind() == Code::KEYED_STORE_IC); | 1591 DCHECK(kind() == Code::KEYED_STORE_IC); |
1639 return isolate()->builtins()->KeyedStoreIC_Slow(); | 1592 return isolate()->builtins()->KeyedStoreIC_Slow(); |
1640 } | 1593 } |
1641 } | 1594 } |
1642 | 1595 |
1643 | 1596 |
1644 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate, | |
1645 LanguageMode language_mode) { | |
1646 ExtraICState state = ComputeExtraICState(language_mode); | |
1647 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state); | |
1648 } | |
1649 | |
1650 | |
1651 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, | 1597 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, |
1652 JSReceiver::StoreFromKeyed store_mode) { | 1598 JSReceiver::StoreFromKeyed store_mode) { |
1653 if (state() == UNINITIALIZED) { | 1599 if (state() == UNINITIALIZED) { |
1654 // This is the first time we execute this inline cache. Set the target to | 1600 // This is the first time we execute this inline cache. Set the target to |
1655 // the pre monomorphic stub to delay setting the monomorphic state. | 1601 // the pre monomorphic stub to delay setting the monomorphic state. |
1656 ConfigureVectorState(PREMONOMORPHIC); | 1602 ConfigureVectorState(PREMONOMORPHIC); |
1657 TRACE_IC("StoreIC", lookup->name()); | 1603 TRACE_IC("StoreIC", lookup->name()); |
1658 return; | 1604 return; |
1659 } | 1605 } |
1660 | 1606 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1821 case LookupIterator::JSPROXY: | 1767 case LookupIterator::JSPROXY: |
1822 case LookupIterator::NOT_FOUND: | 1768 case LookupIterator::NOT_FOUND: |
1823 UNREACHABLE(); | 1769 UNREACHABLE(); |
1824 } | 1770 } |
1825 return slow_stub(); | 1771 return slow_stub(); |
1826 } | 1772 } |
1827 | 1773 |
1828 | 1774 |
1829 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map, | 1775 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map, |
1830 KeyedAccessStoreMode store_mode) { | 1776 KeyedAccessStoreMode store_mode) { |
1831 Handle<Code> null_handle; | |
1832 // Don't handle megamorphic property accesses for INTERCEPTORS or | |
1833 // ACCESSOR_CONSTANT | |
1834 // via megamorphic stubs, since they don't have a map in their relocation info | |
1835 // and so the stubs can't be harvested for the object needed for a map check. | |
1836 if (target()->type() != Code::NORMAL) { | |
1837 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type"); | |
1838 return megamorphic_stub(); | |
1839 } | |
1840 | |
1841 MapHandleList target_receiver_maps; | 1777 MapHandleList target_receiver_maps; |
1842 TargetMaps(&target_receiver_maps); | 1778 TargetMaps(&target_receiver_maps); |
1843 if (target_receiver_maps.length() == 0) { | 1779 if (target_receiver_maps.length() == 0) { |
1844 Handle<Map> monomorphic_map = | 1780 Handle<Map> monomorphic_map = |
1845 ComputeTransitionedMap(receiver_map, store_mode); | 1781 ComputeTransitionedMap(receiver_map, store_mode); |
1846 store_mode = GetNonTransitioningStoreMode(store_mode); | 1782 store_mode = GetNonTransitioningStoreMode(store_mode); |
1847 Handle<Code> handler = | 1783 Handle<Code> handler = |
1848 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( | 1784 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( |
1849 monomorphic_map, language_mode(), store_mode); | 1785 monomorphic_map, language_mode(), store_mode); |
1850 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler); | 1786 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler); |
1851 return null_handle; | 1787 return Handle<Code>(); |
1852 } | 1788 } |
1853 | 1789 |
1854 // There are several special cases where an IC that is MONOMORPHIC can still | 1790 // There are several special cases where an IC that is MONOMORPHIC can still |
1855 // transition to a different GetNonTransitioningStoreMode IC that handles a | 1791 // transition to a different GetNonTransitioningStoreMode IC that handles a |
1856 // superset of the original IC. Handle those here if the receiver map hasn't | 1792 // superset of the original IC. Handle those here if the receiver map hasn't |
1857 // changed or it has transitioned to a more general kind. | 1793 // changed or it has transitioned to a more general kind. |
1858 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode(); | 1794 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode(); |
1859 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); | 1795 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); |
1860 if (state() == MONOMORPHIC) { | 1796 if (state() == MONOMORPHIC) { |
1861 Handle<Map> transitioned_receiver_map = receiver_map; | 1797 Handle<Map> transitioned_receiver_map = receiver_map; |
1862 if (IsTransitionStoreMode(store_mode)) { | 1798 if (IsTransitionStoreMode(store_mode)) { |
1863 transitioned_receiver_map = | 1799 transitioned_receiver_map = |
1864 ComputeTransitionedMap(receiver_map, store_mode); | 1800 ComputeTransitionedMap(receiver_map, store_mode); |
1865 } | 1801 } |
1866 if ((receiver_map.is_identical_to(previous_receiver_map) && | 1802 if ((receiver_map.is_identical_to(previous_receiver_map) && |
1867 IsTransitionStoreMode(store_mode)) || | 1803 IsTransitionStoreMode(store_mode)) || |
1868 IsTransitionOfMonomorphicTarget(*previous_receiver_map, | 1804 IsTransitionOfMonomorphicTarget(*previous_receiver_map, |
1869 *transitioned_receiver_map)) { | 1805 *transitioned_receiver_map)) { |
1870 // If the "old" and "new" maps are in the same elements map family, or | 1806 // If the "old" and "new" maps are in the same elements map family, or |
1871 // if they at least come from the same origin for a transitioning store, | 1807 // if they at least come from the same origin for a transitioning store, |
1872 // stay MONOMORPHIC and use the map for the most generic ElementsKind. | 1808 // stay MONOMORPHIC and use the map for the most generic ElementsKind. |
1873 store_mode = GetNonTransitioningStoreMode(store_mode); | 1809 store_mode = GetNonTransitioningStoreMode(store_mode); |
1874 Handle<Code> handler = | 1810 Handle<Code> handler = |
1875 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( | 1811 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( |
1876 transitioned_receiver_map, language_mode(), store_mode); | 1812 transitioned_receiver_map, language_mode(), store_mode); |
1877 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map, | 1813 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map, |
1878 handler); | 1814 handler); |
1879 return null_handle; | 1815 return Handle<Code>(); |
1880 } else if (receiver_map.is_identical_to(previous_receiver_map) && | 1816 } else if (receiver_map.is_identical_to(previous_receiver_map) && |
1881 old_store_mode == STANDARD_STORE && | 1817 old_store_mode == STANDARD_STORE && |
1882 (store_mode == STORE_AND_GROW_NO_TRANSITION || | 1818 (store_mode == STORE_AND_GROW_NO_TRANSITION || |
1883 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || | 1819 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || |
1884 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { | 1820 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { |
1885 // A "normal" IC that handles stores can switch to a version that can | 1821 // A "normal" IC that handles stores can switch to a version that can |
1886 // grow at the end of the array, handle OOB accesses or copy COW arrays | 1822 // grow at the end of the array, handle OOB accesses or copy COW arrays |
1887 // and still stay MONOMORPHIC. | 1823 // and still stay MONOMORPHIC. |
1888 Handle<Code> handler = | 1824 Handle<Code> handler = |
1889 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( | 1825 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( |
1890 receiver_map, language_mode(), store_mode); | 1826 receiver_map, language_mode(), store_mode); |
1891 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler); | 1827 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler); |
1892 return null_handle; | 1828 return Handle<Code>(); |
1893 } | 1829 } |
1894 } | 1830 } |
1895 | 1831 |
1896 DCHECK(state() != GENERIC); | 1832 DCHECK(state() != GENERIC); |
1897 | 1833 |
1898 bool map_added = | 1834 bool map_added = |
1899 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); | 1835 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); |
1900 | 1836 |
1901 if (IsTransitionStoreMode(store_mode)) { | 1837 if (IsTransitionStoreMode(store_mode)) { |
1902 Handle<Map> transitioned_receiver_map = | 1838 Handle<Map> transitioned_receiver_map = |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1947 return megamorphic_stub(); | 1883 return megamorphic_stub(); |
1948 } | 1884 } |
1949 } | 1885 } |
1950 | 1886 |
1951 MapHandleList transitioned_maps(target_receiver_maps.length()); | 1887 MapHandleList transitioned_maps(target_receiver_maps.length()); |
1952 CodeHandleList handlers(target_receiver_maps.length()); | 1888 CodeHandleList handlers(target_receiver_maps.length()); |
1953 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( | 1889 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( |
1954 &target_receiver_maps, &transitioned_maps, &handlers, store_mode, | 1890 &target_receiver_maps, &transitioned_maps, &handlers, store_mode, |
1955 language_mode()); | 1891 language_mode()); |
1956 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); | 1892 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); |
1957 return null_handle; | 1893 return Handle<Code>(); |
1958 } | 1894 } |
1959 | 1895 |
1960 | 1896 |
1961 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( | 1897 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( |
1962 Handle<Map> map, KeyedAccessStoreMode store_mode) { | 1898 Handle<Map> map, KeyedAccessStoreMode store_mode) { |
1963 switch (store_mode) { | 1899 switch (store_mode) { |
1964 case STORE_TRANSITION_TO_OBJECT: | 1900 case STORE_TRANSITION_TO_OBJECT: |
1965 case STORE_AND_GROW_TRANSITION_TO_OBJECT: { | 1901 case STORE_AND_GROW_TRANSITION_TO_OBJECT: { |
1966 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind()) | 1902 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind()) |
1967 ? FAST_HOLEY_ELEMENTS | 1903 ? FAST_HOLEY_ELEMENTS |
(...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2958 KeyedLoadICNexus nexus(vector, vector_slot); | 2894 KeyedLoadICNexus nexus(vector, vector_slot); |
2959 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); | 2895 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); |
2960 ic.UpdateState(receiver, key); | 2896 ic.UpdateState(receiver, key); |
2961 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); | 2897 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); |
2962 } | 2898 } |
2963 | 2899 |
2964 return *result; | 2900 return *result; |
2965 } | 2901 } |
2966 } // namespace internal | 2902 } // namespace internal |
2967 } // namespace v8 | 2903 } // namespace v8 |
OLD | NEW |