| 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 |