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 3 // found in the LICENSE file. 4 5 #include "src/ic/ic.h" 6 7 #include "src/accessors.h" 8 #include "src/api-arguments-inl.h" 9 #include "src/api.h" 10 #include "src/arguments-inl.h" 11 #include "src/ast/ast.h" 12 #include "src/base/bits.h" 13 #include "src/conversions.h" 14 #include "src/execution.h" 15 #include "src/field-type.h" 16 #include "src/frames-inl.h" 17 #include "src/handles-inl.h" 18 #include "src/ic/call-optimization.h" 19 #include "src/ic/handler-configuration-inl.h" 20 #include "src/ic/ic-inl.h" 21 #include "src/ic/ic-stats.h" 22 #include "src/ic/stub-cache.h" 23 #include "src/isolate-inl.h" 24 #include "src/macro-assembler.h" 25 #include "src/objects/api-callbacks.h" 26 #include "src/objects/data-handler-inl.h" 27 #include "src/objects/hash-table-inl.h" 28 #include "src/objects/js-array-inl.h" 29 #include "src/objects/module-inl.h" 30 #include "src/prototype.h" 31 #include "src/runtime-profiler.h" 32 #include "src/runtime/runtime-utils.h" 33 #include "src/runtime/runtime.h" 34 #include "src/tracing/trace-event.h" 35 #include "src/tracing/tracing-category-observer.h" 36 37 namespace v8 { 38 namespace internal { 39 40 char IC::TransitionMarkFromState(IC::State state) { 41 switch (state) { 42 case UNINITIALIZED: 43 return '0'; 44 case PREMONOMORPHIC: 45 return '.'; 46 case MONOMORPHIC: 47 return '1'; 48 case RECOMPUTE_HANDLER: 49 return '^'; 50 case POLYMORPHIC: 51 return 'P'; 52 case MEGAMORPHIC: 53 return 'N'; 54 case GENERIC: 55 return 'G'; 56 } 57 UNREACHABLE(); 58 } 59 60 namespace { 61 62 const char* GetModifier(KeyedAccessLoadMode mode) { 63 if (mode == LOAD_IGNORE_OUT_OF_BOUNDS) return ".IGNORE_OOB"; 64 return ""; 65 } 66 67 const char* GetModifier(KeyedAccessStoreMode mode) { 68 switch (mode) { 69 case STORE_NO_TRANSITION_HANDLE_COW: 70 return ".COW"; 71 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW: 72 return ".STORE+COW"; 73 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: 74 return ".IGNORE_OOB"; 75 default: 76 break; 77 } 78 DCHECK(!IsCOWHandlingStoreMode(mode)); 79 return IsGrowStoreMode(mode) ? ".GROW" : ""; 80 } 81 82 } // namespace 83 84 void IC::TraceIC(const char* type, Handle<Object> name) { 85 if (FLAG_ic_stats) { 86 if (AddressIsDeoptimizedCode()) return; 87 State new_state = nexus()->StateFromFeedback(); 88 TraceIC(type, name, state(), new_state); 89 } 90 } 91 92 void IC::TraceIC(const char* type, Handle<Object> name, State old_state, 93 State new_state) { 94 if (V8_LIKELY(!FLAG_ic_stats)) return; 95 96 Map* map = nullptr; 97 if (!receiver_map().is_null()) { 98 map = *receiver_map(); 99 } 100 101 const char* modifier = ""; 102 if (IsKeyedLoadIC()) { 103 KeyedAccessLoadMode mode = nexus()->GetKeyedAccessLoadMode(); 104 modifier = GetModifier(mode); 105 } else if (IsKeyedStoreIC() || IsStoreInArrayLiteralICKind(kind())) { 106 KeyedAccessStoreMode mode = nexus()->GetKeyedAccessStoreMode(); 107 modifier = GetModifier(mode); 108 } 109 110 bool keyed_prefix = is_keyed() && !IsStoreInArrayLiteralICKind(kind()); 111 112 if (!(FLAG_ic_stats & 113 v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { 114 LOG(isolate(), ICEvent(type, keyed_prefix, map, *name, 115 TransitionMarkFromState(old_state), 116 TransitionMarkFromState(new_state), modifier, 117 slow_stub_reason_)); 118 return; 119 } 120 121 ICStats::instance()->Begin(); 122 ICInfo& ic_info = ICStats::instance()->Current(); 123 ic_info.type = keyed_prefix ? "Keyed" : ""; 124 ic_info.type += type; 125 126 Object* maybe_function = 127 Memory<Object*>(fp_ + JavaScriptFrameConstants::kFunctionOffset); 128 DCHECK(maybe_function->IsJSFunction()); 129 JSFunction* function = JSFunction::cast(maybe_function); 130 int code_offset = 0; 131 if (function->IsInterpreted()) { 132 code_offset = InterpretedFrame::GetBytecodeOffset(fp()); 133 } else { 134 code_offset = static_cast<int>(pc() - function->code()->InstructionStart()); 135 } 136 JavaScriptFrame::CollectFunctionAndOffsetForICStats( 137 function, function->abstract_code(), code_offset); 138 139 // Reserve enough space for IC transition state, the longest length is 17. 140 ic_info.state.reserve(17); 141 ic_info.state = "("; 142 ic_info.state += TransitionMarkFromState(old_state); 143 ic_info.state += "->"; 144 ic_info.state += TransitionMarkFromState(new_state); 145 ic_info.state += modifier; 146 ic_info.state += ")"; 147 ic_info.map = reinterpret_cast<void*>(map); 148 if (map != nullptr) { 149 ic_info.is_dictionary_map = map->is_dictionary_map(); 150 ic_info.number_of_own_descriptors = map->NumberOfOwnDescriptors(); 151 ic_info.instance_type = std::to_string(map->instance_type()); 152 } 153 // TODO(lpy) Add name as key field in ICStats. 154 ICStats::instance()->End(); 155 } 156 157 IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot) 158 : isolate_(isolate), 159 vector_set_(false), 160 kind_(FeedbackSlotKind::kInvalid), 161 target_maps_set_(false), 162 slow_stub_reason_(nullptr), 163 nexus_(vector, slot) { 164 // To improve the performance of the (much used) IC code, we unfold a few 165 // levels of the stack frame iteration code. This yields a ~35% speedup when 166 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. 167 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top()); 168 Address* constant_pool = nullptr; 169 if (FLAG_enable_embedded_constant_pool) { 170 constant_pool = reinterpret_cast<Address*>( 171 entry + ExitFrameConstants::kConstantPoolOffset); 172 } 173 Address* pc_address = 174 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); 175 Address fp = Memory<Address>(entry + ExitFrameConstants::kCallerFPOffset); 176 #ifdef DEBUG 177 StackFrameIterator it(isolate); 178 for (int i = 0; i < 1; i++) it.Advance(); 179 StackFrame* frame = it.frame(); 180 DCHECK(fp == frame->fp() && pc_address == frame->pc_address()); 181 #endif 182 // For interpreted functions, some bytecode handlers construct a 183 // frame. We have to skip the constructed frame to find the interpreted 184 // function's frame. Check if the there is an additional frame, and if there 185 // is skip this frame. However, the pc should not be updated. The call to 186 // ICs happen from bytecode handlers. 187 intptr_t frame_marker = 188 Memory<intptr_t>(fp + TypedFrameConstants::kFrameTypeOffset); 189 if (frame_marker == StackFrame::TypeToMarker(StackFrame::STUB)) { 190 fp = Memory<Address>(fp + TypedFrameConstants::kCallerFPOffset); 191 } 192 fp_ = fp; 193 if (FLAG_enable_embedded_constant_pool) { 194 constant_pool_address_ = constant_pool; 195 } 196 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); 197 kind_ = nexus_.kind(); 198 state_ = nexus_.StateFromFeedback(); 199 old_state_ = state_; 200 } 201 202 JSFunction* IC::GetHostFunction() const { 203 // Compute the JavaScript frame for the frame pointer of this IC 204 // structure. We need this to be able to find the function 205 // corresponding to the frame. 206 StackFrameIterator it(isolate()); 207 while (it.frame()->fp() != this->fp()) it.Advance(); 208 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 209 // Find the function on the stack and both the active code for the 210 // function and the original code. 211 return frame->function(); 212 } 213 214 static void LookupForRead(Isolate* isolate, LookupIterator* it) { 215 for (; it->IsFound(); it->Next()) { 216 switch (it->state()) { 217 case LookupIterator::NOT_FOUND: 218 case LookupIterator::TRANSITION: 219 UNREACHABLE(); 220 case LookupIterator::JSPROXY: 221 return; 222 case LookupIterator::INTERCEPTOR: { 223 // If there is a getter, return; otherwise loop to perform the lookup. 224 Handle<JSObject> holder = it->GetHolder<JSObject>(); 225 if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) { 226 return; 227 } 228 break; 229 } 230 case LookupIterator::ACCESS_CHECK: 231 // ICs know how to perform access checks on global proxies. 232 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) { 233 break; 234 } 235 return; 236 case LookupIterator::ACCESSOR: 237 case LookupIterator::INTEGER_INDEXED_EXOTIC: 238 case LookupIterator::DATA: 239 return; 240 } 241 } 242 } 243 244 bool IC::ShouldRecomputeHandler(Handle<String> name) { 245 if (!RecomputeHandlerForName(name)) return false; 246 247 // This is a contextual access, always just update the handler and stay 248 // monomorphic. 249 if (IsGlobalIC()) return true; 250 251 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map()); 252 253 // The current map wasn't handled yet. There's no reason to stay monomorphic, 254 // *unless* we're moving from a deprecated map to its replacement, or 255 // to a more general elements kind. 256 // TODO(verwaest): Check if the current map is actually what the old map 257 // would transition to. 258 if (maybe_handler_.is_null()) { 259 if (!receiver_map()->IsJSObjectMap()) return false; 260 Map* first_map = FirstTargetMap(); 261 if (first_map == nullptr) return false; 262 Handle<Map> old_map(first_map, isolate()); 263 if (old_map->is_deprecated()) return true; 264 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(), 265 receiver_map()->elements_kind()); 266 } 267 268 return true; 269 } 270 271 bool IC::RecomputeHandlerForName(Handle<Object> name) { 272 if (is_keyed()) { 273 // Determine whether the failure is due to a name failure. 274 if (!name->IsName()) return false; 275 Name* stub_name = nexus()->FindFirstName(); 276 if (*name != stub_name) return false; 277 } 278 279 return true; 280 } 281 282 283 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { 284 update_receiver_map(receiver); 285 if (!name->IsString()) return; 286 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; 287 if (receiver->IsNullOrUndefined(isolate())) return; 288 289 // Remove the target from the code cache if it became invalid 290 // because of changes in the prototype chain to avoid hitting it 291 // again. 292 if (ShouldRecomputeHandler(Handle<String>::cast(name))) { 293 MarkRecomputeHandler(name); 294 } 295 } 296 297 298 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index, 299 Handle<Object> object, Handle<Object> key) { 300 HandleScope scope(isolate()); 301 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object); 302 } 303 304 305 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) { 306 HandleScope scope(isolate()); 307 THROW_NEW_ERROR( 308 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object); 309 } 310 311 // static 312 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackNexus* nexus, 313 JSFunction* host_function, const char* reason) { 314 FeedbackVector* vector = nexus->vector(); 315 FeedbackSlot slot = nexus->slot(); 316 OnFeedbackChanged(isolate, vector, slot, host_function, reason); 317 } 318 319 // static 320 void IC::OnFeedbackChanged(Isolate* isolate, FeedbackVector* vector, 321 FeedbackSlot slot, JSFunction* host_function, 322 const char* reason) { 323 if (FLAG_trace_opt_verbose) { 324 // TODO(leszeks): The host function is only needed for this print, we could 325 // remove it as a parameter if we're of with removing this trace (or only 326 // tracing the feedback vector, not the function name). 327 if (vector->profiler_ticks() != 0) { 328 PrintF("[resetting ticks for "); 329 host_function->ShortPrint(); 330 PrintF(" due from %d due to IC change: %s]\n", vector->profiler_ticks(), 331 reason); 332 } 333 } 334 vector->set_profiler_ticks(0); 335 336 #ifdef V8_TRACE_FEEDBACK_UPDATES 337 if (FLAG_trace_feedback_updates) { 338 int slot_count = vector->metadata()->slot_count(); 339 340 StdoutStream os; 341 if (slot.IsInvalid()) { 342 os << "[Feedback slots in "; 343 } else { 344 os << "[Feedback slot " << slot.ToInt() << "/" << slot_count << " in "; 345 } 346 vector->shared_function_info()->ShortPrint(os); 347 if (slot.IsInvalid()) { 348 os << " updated - "; 349 } else { 350 os << " updated to "; 351 vector->FeedbackSlotPrint(os, slot); 352 os << " - "; 353 } 354 os << reason << "]" << std::endl; 355 } 356 #endif 357 358 isolate->runtime_profiler()->NotifyICChanged(); 359 // TODO(2029): When an optimized function is patched, it would 360 // be nice to propagate the corresponding type information to its 361 // unoptimized version for the benefit of later inlining. 362 } 363 364 static bool MigrateDeprecated(Handle<Object> object) { 365 if (!object->IsJSObject()) return false; 366 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 367 if (!receiver->map()->is_deprecated()) return false; 368 JSObject::MigrateInstance(Handle<JSObject>::cast(object)); 369 return true; 370 } 371 372 bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) { 373 DCHECK_EQ(MEGAMORPHIC, new_state); 374 DCHECK_IMPLIES(!is_keyed(), key->IsName()); 375 // Even though we don't change the feedback data, we still want to reset the 376 // profiler ticks. Real-world observations suggest that optimizing these 377 // functions doesn't improve performance. 378 bool changed = 379 nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT); 380 vector_set_ = true; 381 OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Megamorphic"); 382 return changed; 383 } 384 385 void IC::ConfigureVectorState(Handle<Map> map) { 386 nexus()->ConfigurePremonomorphic(map); 387 vector_set_ = true; 388 OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Premonomorphic"); 389 } 390 391 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, 392 Handle<Object> handler) { 393 ConfigureVectorState(name, map, MaybeObjectHandle(handler)); 394 } 395 396 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, 397 const MaybeObjectHandle& handler) { 398 if (IsGlobalIC()) { 399 nexus()->ConfigureHandlerMode(handler); 400 } else { 401 // Non-keyed ICs don't track the name explicitly. 402 if (!is_keyed()) name = Handle<Name>::null(); 403 nexus()->ConfigureMonomorphic(name, map, handler); 404 } 405 406 vector_set_ = true; 407 OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), 408 IsLoadGlobalIC() ? "LoadGlobal" : "Monomorphic"); 409 } 410 411 void IC::ConfigureVectorState(Handle<Name> name, MapHandles const& maps, 412 MaybeObjectHandles* handlers) { 413 DCHECK(!IsGlobalIC()); 414 // Non-keyed ICs don't track the name explicitly. 415 if (!is_keyed()) name = Handle<Name>::null(); 416 nexus()->ConfigurePolymorphic(name, maps, handlers); 417 418 vector_set_ = true; 419 OnFeedbackChanged(isolate(), nexus(), GetHostFunction(), "Polymorphic"); 420 } 421 422 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { 423 // If the object is undefined or null it's illegal to try to get any 424 // of its properties; throw a TypeError in that case. 425 if (object->IsNullOrUndefined(isolate())) { 426 if (FLAG_use_ic && state() != PREMONOMORPHIC) { 427 // Ensure the IC state progresses. 428 TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); 429 update_receiver_map(object); 430 PatchCache(name, slow_stub()); 431 TraceIC("LoadIC", name); 432 } 433 434 if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) { 435 return Runtime::ThrowIteratorError(isolate(), object); 436 } 437 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name); 438 } 439 440 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; 441 442 if (state() != UNINITIALIZED) { 443 JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate()); 444 update_receiver_map(object); 445 } 446 // Named lookup in the object. 447 LookupIterator it(isolate(), object, name); 448 LookupForRead(isolate(), &it); 449 450 if (name->IsPrivate()) { 451 if (name->IsPrivateField() && !it.IsFound()) { 452 return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object, 453 name); 454 } 455 456 // IC handling of private symbols/fields lookup on JSProxy is not 457 // supported. 458 if (object->IsJSProxy()) { 459 use_ic = false; 460 } 461 } 462 463 if (it.IsFound() || !ShouldThrowReferenceError()) { 464 // Update inline cache and stub cache. 465 if (use_ic) UpdateCaches(&it); 466 467 // Get the property. 468 Handle<Object> result; 469 470 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it), 471 Object); 472 if (it.IsFound()) { 473 return result; 474 } else if (!ShouldThrowReferenceError()) { 475 LOG(isolate(), SuspectReadEvent(*name, *object)); 476 return result; 477 } 478 } 479 return ReferenceError(name); 480 } 481 482 MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { 483 Handle<JSGlobalObject> global = isolate()->global_object(); 484 485 if (name->IsString()) { 486 // Look up in script context table. 487 Handle<String> str_name = Handle<String>::cast(name); 488 Handle<ScriptContextTable> script_contexts( 489 global->native_context()->script_context_table(), isolate()); 490 491 ScriptContextTable::LookupResult lookup_result; 492 if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name, 493 &lookup_result)) { 494 Handle<Object> result = FixedArray::get( 495 *ScriptContextTable::GetContext(isolate(), script_contexts, 496 lookup_result.context_index), 497 lookup_result.slot_index, isolate()); 498 if (result->IsTheHole(isolate())) { 499 // Do not install stubs and stay pre-monomorphic for 500 // uninitialized accesses. 501 return ReferenceError(name); 502 } 503 504 if (FLAG_use_ic) { 505 if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index, 506 lookup_result.slot_index)) { 507 TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField); 508 } else { 509 // Given combination of indices can't be encoded, so use slow stub. 510 TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub); 511 PatchCache(name, slow_stub()); 512 } 513 TraceIC("LoadGlobalIC", name); 514 } 515 return result; 516 } 517 } 518 return LoadIC::Load(global, name); 519 } 520 521 static bool AddOneReceiverMapIfMissing(MapHandles* receiver_maps, 522 Handle<Map> new_receiver_map) { 523 DCHECK(!new_receiver_map.is_null()); 524 for (Handle<Map> map : *receiver_maps) { 525 if (!map.is_null() && map.is_identical_to(new_receiver_map)) { 526 return false; 527 } 528 } 529 receiver_maps->push_back(new_receiver_map); 530 return true; 531 } 532 533 bool IC::UpdatePolymorphicIC(Handle<Name> name, 534 const MaybeObjectHandle& handler) { 535 DCHECK(IsHandler(*handler)); 536 if (is_keyed() && state() != RECOMPUTE_HANDLER) { 537 if (nexus()->FindFirstName() != *name) return false; 538 } 539 Handle<Map> map = receiver_map(); 540 MapHandles maps; 541 MaybeObjectHandles handlers; 542 543 TargetMaps(&maps); 544 int number_of_maps = static_cast<int>(maps.size()); 545 int deprecated_maps = 0; 546 int handler_to_overwrite = -1; 547 if (!nexus()->FindHandlers(&handlers, number_of_maps)) return false; 548 549 for (int i = 0; i < number_of_maps; i++) { 550 Handle<Map> current_map = maps.at(i); 551 if (current_map->is_deprecated()) { 552 // Filter out deprecated maps to ensure their instances get migrated. 553 ++deprecated_maps; 554 } else if (map.is_identical_to(current_map)) { 555 // If both map and handler stayed the same (and the name is also the 556 // same as checked above, for keyed accesses), we're not progressing 557 // in the lattice and need to go MEGAMORPHIC instead. There's one 558 // exception to this rule, which is when we're in RECOMPUTE_HANDLER 559 // state, there we allow to migrate to a new handler. 560 if (handler.is_identical_to(handlers[i]) && 561 state() != RECOMPUTE_HANDLER) { 562 return false; 563 } 564 // If the receiver type is already in the polymorphic IC, this indicates 565 // there was a prototoype chain failure. In that case, just overwrite the 566 // handler. 567 handler_to_overwrite = i; 568 } else if (handler_to_overwrite == -1 && 569 IsTransitionOfMonomorphicTarget(*current_map, *map)) { 570 handler_to_overwrite = i; 571 } 572 } 573 574 int number_of_valid_maps = 575 number_of_maps - deprecated_maps - (handler_to_overwrite != -1); 576 577 if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false; 578 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { 579 return false; 580 } 581 582 number_of_valid_maps++; 583 if (number_of_valid_maps == 1) { 584 ConfigureVectorState(name, receiver_map(), handler); 585 } else { 586 if (is_keyed() && nexus()->FindFirstName() != *name) return false; 587 if (handler_to_overwrite >= 0) { 588 handlers[handler_to_overwrite] = handler; 589 if (!map.is_identical_to(maps.at(handler_to_overwrite))) { 590 maps[handler_to_overwrite] = map; 591 } 592 } else { 593 maps.push_back(map); 594 handlers.push_back(handler); 595 } 596 597 ConfigureVectorState(name, maps, &handlers); 598 } 599 600 return true; 601 } 602 603 void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler, 604 Handle<Name> name) { 605 DCHECK(IsHandler(*handler)); 606 ConfigureVectorState(name, receiver_map(), handler); 607 } 608 609 610 void IC::CopyICToMegamorphicCache(Handle<Name> name) { 611 MapHandles maps; 612 MaybeObjectHandles handlers; 613 TargetMaps(&maps); 614 if (!nexus()->FindHandlers(&handlers, static_cast<int>(maps.size()))) return; 615 for (int i = 0; i < static_cast<int>(maps.size()); i++) { 616 UpdateMegamorphicCache(maps.at(i), name, handlers.at(i)); 617 } 618 } 619 620 621 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { 622 if (source_map == nullptr) return true; 623 if (target_map == nullptr) return false; 624 if (source_map->is_abandoned_prototype_map()) return false; 625 ElementsKind target_elements_kind = target_map->elements_kind(); 626 bool more_general_transition = IsMoreGeneralElementsKindTransition( 627 source_map->elements_kind(), target_elements_kind); 628 Map* transitioned_map = nullptr; 629 if (more_general_transition) { 630 MapHandles map_list; 631 map_list.push_back(handle(target_map, isolate_)); 632 transitioned_map = 633 source_map->FindElementsKindTransitionedMap(isolate(), map_list); 634 } 635 return transitioned_map == target_map; 636 } 637 638 void IC::PatchCache(Handle<Name> name, Handle<Object> handler) { 639 PatchCache(name, MaybeObjectHandle(handler)); 640 } 641 642 void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) { 643 DCHECK(IsHandler(*handler)); 644 // Currently only load and store ICs support non-code handlers. 645 DCHECK(IsAnyLoad() || IsAnyStore()); 646 switch (state()) { 647 case UNINITIALIZED: 648 case PREMONOMORPHIC: 649 UpdateMonomorphicIC(handler, name); 650 break; 651 case RECOMPUTE_HANDLER: 652 case MONOMORPHIC: 653 if (IsGlobalIC()) { 654 UpdateMonomorphicIC(handler, name); 655 break; 656 } 657 V8_FALLTHROUGH; 658 case POLYMORPHIC: 659 if (UpdatePolymorphicIC(name, handler)) break; 660 if (!is_keyed() || state() == RECOMPUTE_HANDLER) { 661 CopyICToMegamorphicCache(name); 662 } 663 ConfigureVectorState(MEGAMORPHIC, name); 664 V8_FALLTHROUGH; 665 case MEGAMORPHIC: 666 UpdateMegamorphicCache(receiver_map(), name, handler); 667 // Indicate that we've handled this case. 668 vector_set_ = true; 669 break; 670 case GENERIC: 671 UNREACHABLE(); 672 break; 673 } 674 } 675 676 void LoadIC::UpdateCaches(LookupIterator* lookup) { 677 if (state() == UNINITIALIZED && !IsLoadGlobalIC()) { 678 // This is the first time we execute this inline cache. Set the target to 679 // the pre monomorphic stub to delay setting the monomorphic state. 680 TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic); 681 ConfigureVectorState(receiver_map()); 682 TraceIC("LoadIC", lookup->name()); 683 return; 684 } 685 686 Handle<Object> code; 687 if (lookup->state() == LookupIterator::ACCESS_CHECK) { 688 code = slow_stub(); 689 } else if (!lookup->IsFound()) { 690 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); 691 Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate()); 692 code = LoadHandler::LoadFullChain( 693 isolate(), receiver_map(), 694 MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler); 695 } else { 696 if (IsLoadGlobalIC()) { 697 if (lookup->TryLookupCachedProperty()) { 698 DCHECK_EQ(LookupIterator::DATA, lookup->state()); 699 } 700 if (lookup->state() == LookupIterator::DATA && 701 lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { 702 DCHECK(lookup->GetReceiver()->IsJSGlobalObject()); 703 // Now update the cell in the feedback vector. 704 nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell()); 705 TraceIC("LoadGlobalIC", lookup->name()); 706 return; 707 } 708 } 709 code = ComputeHandler(lookup); 710 } 711 712 PatchCache(lookup->name(), code); 713 TraceIC("LoadIC", lookup->name()); 714 } 715 716 StubCache* IC::stub_cache() { 717 if (IsAnyLoad()) { 718 return isolate()->load_stub_cache(); 719 } else { 720 DCHECK(IsAnyStore()); 721 return isolate()->store_stub_cache(); 722 } 723 } 724 725 void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, 726 const MaybeObjectHandle& handler) { 727 stub_cache()->Set(*name, *map, *handler); 728 } 729 730 void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) { 731 DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state()); 732 if (V8_LIKELY(!FLAG_runtime_stats)) return; 733 if (IsAnyLoad()) { 734 TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor); 735 } else { 736 DCHECK(IsAnyStore()); 737 TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor); 738 } 739 } 740 741 Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { 742 Handle<Object> receiver = lookup->GetReceiver(); 743 ReadOnlyRoots roots(isolate()); 744 if (receiver->IsString() && *lookup->name() == roots.length_string()) { 745 TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength); 746 return BUILTIN_CODE(isolate(), LoadIC_StringLength); 747 } 748 749 if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) { 750 TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength); 751 return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength); 752 } 753 754 // Use specialized code for getting prototype of functions. 755 if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() && 756 !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) { 757 Handle<Code> stub; 758 TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub); 759 return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype); 760 } 761 762 Handle<Map> map = receiver_map(); 763 Handle<JSObject> holder; 764 bool receiver_is_holder; 765 if (lookup->state() != LookupIterator::JSPROXY) { 766 holder = lookup->GetHolder<JSObject>(); 767 receiver_is_holder = receiver.is_identical_to(holder); 768 } 769 770 switch (lookup->state()) { 771 case LookupIterator::INTERCEPTOR: { 772 Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate()); 773 774 if (holder->GetNamedInterceptor()->non_masking()) { 775 MaybeObjectHandle holder_ref(isolate()->factory()->null_value()); 776 if (!receiver_is_holder || IsLoadGlobalIC()) { 777 holder_ref = MaybeObjectHandle::Weak(holder); 778 } 779 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH); 780 return LoadHandler::LoadFullChain(isolate(), map, holder_ref, 781 smi_handler); 782 } 783 784 if (receiver_is_holder) { 785 DCHECK(map->has_named_interceptor()); 786 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH); 787 return smi_handler; 788 } 789 790 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH); 791 return LoadHandler::LoadFromPrototype(isolate(), map, holder, 792 smi_handler); 793 } 794 795 case LookupIterator::ACCESSOR: { 796 // Use simple field loads for some well-known callback properties. 797 // The method will only return true for absolute truths based on the 798 // receiver maps. 799 FieldIndex index; 800 if (Accessors::IsJSObjectFieldAccessor(isolate(), map, lookup->name(), 801 &index)) { 802 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); 803 return LoadHandler::LoadField(isolate(), index); 804 } 805 if (holder->IsJSModuleNamespace()) { 806 Handle<ObjectHashTable> exports( 807 Handle<JSModuleNamespace>::cast(holder)->module()->exports(), 808 isolate()); 809 int entry = exports->FindEntry(roots, lookup->name(), 810 Smi::ToInt(lookup->name()->GetHash())); 811 // We found the accessor, so the entry must exist. 812 DCHECK_NE(entry, ObjectHashTable::kNotFound); 813 int index = ObjectHashTable::EntryToValueIndex(entry); 814 return LoadHandler::LoadModuleExport(isolate(), index); 815 } 816 817 Handle<Object> accessors = lookup->GetAccessors(); 818 if (accessors->IsAccessorPair()) { 819 if (lookup->TryLookupCachedProperty()) { 820 DCHECK_EQ(LookupIterator::DATA, lookup->state()); 821 return ComputeHandler(lookup); 822 } 823 824 Handle<Object> getter(AccessorPair::cast(*accessors)->getter(), 825 isolate()); 826 if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) { 827 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); 828 return slow_stub(); 829 } 830 831 if (getter->IsFunctionTemplateInfo() && 832 FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) { 833 // Do not install an IC if the api function has a breakpoint. 834 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); 835 return slow_stub(); 836 } 837 838 Handle<Smi> smi_handler; 839 840 CallOptimization call_optimization(isolate(), getter); 841 if (call_optimization.is_simple_api_call()) { 842 if (!call_optimization.IsCompatibleReceiverMap(map, holder) || 843 !holder->HasFastProperties()) { 844 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); 845 return slow_stub(); 846 } 847 848 CallOptimization::HolderLookup holder_lookup; 849 call_optimization.LookupHolderOfExpectedType(map, &holder_lookup); 850 851 smi_handler = LoadHandler::LoadApiGetter( 852 isolate(), holder_lookup == CallOptimization::kHolderIsReceiver); 853 854 Handle<Context> context( 855 call_optimization.GetAccessorContext(holder->map()), isolate()); 856 857 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH); 858 return LoadHandler::LoadFromPrototype( 859 isolate(), map, holder, smi_handler, 860 MaybeObjectHandle::Weak(call_optimization.api_call_info()), 861 MaybeObjectHandle::Weak(context)); 862 } 863 864 if (holder->HasFastProperties()) { 865 smi_handler = 866 LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex()); 867 868 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH); 869 if (receiver_is_holder) return smi_handler; 870 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH); 871 } else if (holder->IsJSGlobalObject()) { 872 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH); 873 smi_handler = LoadHandler::LoadGlobal(isolate()); 874 return LoadHandler::LoadFromPrototype( 875 isolate(), map, holder, smi_handler, 876 MaybeObjectHandle::Weak(lookup->GetPropertyCell())); 877 } else { 878 smi_handler = LoadHandler::LoadNormal(isolate()); 879 880 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); 881 if (receiver_is_holder) return smi_handler; 882 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); 883 } 884 885 return LoadHandler::LoadFromPrototype(isolate(), map, holder, 886 smi_handler); 887 } 888 889 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); 890 891 if (v8::ToCData<Address>(info->getter()) == kNullAddress || 892 !AccessorInfo::IsCompatibleReceiverMap(info, map) || 893 !holder->HasFastProperties() || 894 (info->is_sloppy() && !receiver->IsJSReceiver())) { 895 TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); 896 return slow_stub(); 897 } 898 899 Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty( 900 isolate(), lookup->GetAccessorIndex()); 901 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNativeDataPropertyDH); 902 if (receiver_is_holder) return smi_handler; 903 TRACE_HANDLER_STATS(isolate(), 904 LoadIC_LoadNativeDataPropertyFromPrototypeDH); 905 return LoadHandler::LoadFromPrototype(isolate(), map, holder, 906 smi_handler); 907 } 908 909 case LookupIterator::DATA: { 910 DCHECK_EQ(kData, lookup->property_details().kind()); 911 Handle<Smi> smi_handler; 912 if (lookup->is_dictionary_holder()) { 913 if (holder->IsJSGlobalObject()) { 914 // TODO(verwaest): Also supporting the global object as receiver is a 915 // workaround for code that leaks the global object. 916 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH); 917 smi_handler = LoadHandler::LoadGlobal(isolate()); 918 return LoadHandler::LoadFromPrototype( 919 isolate(), map, holder, smi_handler, 920 MaybeObjectHandle::Weak(lookup->GetPropertyCell())); 921 } 922 923 smi_handler = LoadHandler::LoadNormal(isolate()); 924 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH); 925 if (receiver_is_holder) return smi_handler; 926 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); 927 928 } else if (lookup->property_details().location() == kField) { 929 FieldIndex field = lookup->GetFieldIndex(); 930 smi_handler = LoadHandler::LoadField(isolate(), field); 931 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); 932 if (receiver_is_holder) return smi_handler; 933 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH); 934 } else { 935 DCHECK_EQ(kDescriptor, lookup->property_details().location()); 936 smi_handler = 937 LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex()); 938 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH); 939 if (receiver_is_holder) return smi_handler; 940 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH); 941 } 942 return LoadHandler::LoadFromPrototype(isolate(), map, holder, 943 smi_handler); 944 } 945 case LookupIterator::INTEGER_INDEXED_EXOTIC: 946 TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH); 947 return LoadHandler::LoadNonExistent(isolate()); 948 case LookupIterator::JSPROXY: { 949 Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>(); 950 bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy); 951 Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate()); 952 if (receiver_is_holder_proxy) { 953 return smi_handler; 954 } 955 return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy, 956 smi_handler); 957 } 958 case LookupIterator::ACCESS_CHECK: 959 case LookupIterator::NOT_FOUND: 960 case LookupIterator::TRANSITION: 961 UNREACHABLE(); 962 } 963 964 return Handle<Code>::null(); 965 } 966 967 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { 968 // This helper implements a few common fast cases for converting 969 // non-smi keys of keyed loads/stores to a smi or a string. 970 if (key->IsHeapNumber()) { 971 double value = Handle<HeapNumber>::cast(key)->value(); 972 if (std::isnan(value)) { 973 key = isolate->factory()->NaN_string(); 974 } else { 975 // Check bounds first to avoid undefined behavior in the conversion 976 // to int. 977 if (value <= Smi::kMaxValue && value >= Smi::kMinValue) { 978 int int_value = FastD2I(value); 979 if (value == int_value) { 980 key = handle(Smi::FromInt(int_value), isolate); 981 } 982 } 983 } 984 } else if (key->IsString()) { 985 key = isolate->factory()->InternalizeString(Handle<String>::cast(key)); 986 } 987 return key; 988 } 989 990 bool KeyedLoadIC::CanChangeToAllowOutOfBounds(Handle<Map> receiver_map) { 991 const MaybeObjectHandle& handler = nexus()->FindHandlerForMap(receiver_map); 992 if (handler.is_null()) return false; 993 return LoadHandler::GetKeyedAccessLoadMode(*handler) == STANDARD_LOAD; 994 } 995 996 void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver, 997 KeyedAccessLoadMode load_mode) { 998 Handle<Map> receiver_map(receiver->map(), isolate()); 999 DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller. 1000 MapHandles target_receiver_maps; 1001 TargetMaps(&target_receiver_maps); 1002 1003 if (target_receiver_maps.empty()) { 1004 Handle<Object> handler = LoadElementHandler(receiver_map, load_mode); 1005 return ConfigureVectorState(Handle<Name>(), receiver_map, handler); 1006 } 1007 1008 for (Handle<Map> map : target_receiver_maps) { 1009 if (map.is_null()) continue; 1010 if (map->instance_type() == JS_VALUE_TYPE) { 1011 set_slow_stub_reason("JSValue"); 1012 return; 1013 } 1014 if (map->instance_type() == JS_PROXY_TYPE) { 1015 set_slow_stub_reason("JSProxy"); 1016 return; 1017 } 1018 } 1019 1020 // The first time a receiver is seen that is a transitioned version of the 1021 // previous monomorphic receiver type, assume the new ElementsKind is the 1022 // monomorphic type. This benefits global arrays that only transition 1023 // once, and all call sites accessing them are faster if they remain 1024 // monomorphic. If this optimistic assumption is not true, the IC will 1025 // miss again and it will become polymorphic and support both the 1026 // untransitioned and transitioned maps. 1027 if (state() == MONOMORPHIC && !receiver->IsString() && 1028 !receiver->IsJSProxy() && 1029 IsMoreGeneralElementsKindTransition( 1030 target_receiver_maps.at(0)->elements_kind(), 1031 Handle<JSObject>::cast(receiver)->GetElementsKind())) { 1032 Handle<Object> handler = LoadElementHandler(receiver_map, load_mode); 1033 return ConfigureVectorState(Handle<Name>(), receiver_map, handler); 1034 } 1035 1036 DCHECK(state() != GENERIC); 1037 1038 // Determine the list of receiver maps that this call site has seen, 1039 // adding the map that was just encountered. 1040 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { 1041 // If the {receiver_map} previously had a handler that didn't handle 1042 // out-of-bounds access, but can generally handle it, we can just go 1043 // on and update the handler appropriately below. 1044 if (load_mode != LOAD_IGNORE_OUT_OF_BOUNDS || 1045 !CanChangeToAllowOutOfBounds(receiver_map)) { 1046 // If the miss wasn't due to an unseen map, a polymorphic stub 1047 // won't help, use the generic stub. 1048 set_slow_stub_reason("same map added twice"); 1049 return; 1050 } 1051 } 1052 1053 // If the maximum number of receiver maps has been exceeded, use the generic 1054 // version of the IC. 1055 if (target_receiver_maps.size() > kMaxKeyedPolymorphism) { 1056 set_slow_stub_reason("max polymorph exceeded"); 1057 return; 1058 } 1059 1060 MaybeObjectHandles handlers; 1061 handlers.reserve(target_receiver_maps.size()); 1062 LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers, load_mode); 1063 DCHECK_LE(1, target_receiver_maps.size()); 1064 if (target_receiver_maps.size() == 1) { 1065 ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]); 1066 } else { 1067 ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers); 1068 } 1069 } 1070 1071 Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map, 1072 KeyedAccessLoadMode load_mode) { 1073 if (receiver_map->has_indexed_interceptor() && 1074 !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined( 1075 isolate()) && 1076 !receiver_map->GetIndexedInterceptor()->non_masking()) { 1077 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub); 1078 return LoadIndexedInterceptorStub(isolate()).GetCode(); 1079 } 1080 InstanceType instance_type = receiver_map->instance_type(); 1081 if (instance_type < FIRST_NONSTRING_TYPE) { 1082 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH); 1083 return LoadHandler::LoadIndexedString(isolate(), load_mode); 1084 } 1085 if (instance_type < FIRST_JS_RECEIVER_TYPE) { 1086 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub); 1087 return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow); 1088 } 1089 if (instance_type == JS_PROXY_TYPE) { 1090 return LoadHandler::LoadProxy(isolate()); 1091 } 1092 1093 ElementsKind elements_kind = receiver_map->elements_kind(); 1094 if (IsSloppyArgumentsElementsKind(elements_kind)) { 1095 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub); 1096 return KeyedLoadSloppyArgumentsStub(isolate()).GetCode(); 1097 } 1098 bool is_js_array = instance_type == JS_ARRAY_TYPE; 1099 if (elements_kind == DICTIONARY_ELEMENTS) { 1100 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH); 1101 return LoadHandler::LoadElement(isolate(), elements_kind, false, 1102 is_js_array, load_mode); 1103 } 1104 DCHECK(IsFastElementsKind(elements_kind) || 1105 IsFixedTypedArrayElementsKind(elements_kind)); 1106 // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind). 1107 bool convert_hole_to_undefined = 1108 is_js_array && elements_kind == HOLEY_ELEMENTS && 1109 *receiver_map == 1110 isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind); 1111 TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH); 1112 return LoadHandler::LoadElement(isolate(), elements_kind, 1113 convert_hole_to_undefined, is_js_array, 1114 load_mode); 1115 } 1116 1117 void KeyedLoadIC::LoadElementPolymorphicHandlers( 1118 MapHandles* receiver_maps, MaybeObjectHandles* handlers, 1119 KeyedAccessLoadMode load_mode) { 1120 // Filter out deprecated maps to ensure their instances get migrated. 1121 receiver_maps->erase( 1122 std::remove_if( 1123 receiver_maps->begin(), receiver_maps->end(), 1124 [](const Handle<Map>& map) { return map->is_deprecated(); }), 1125 receiver_maps->end()); 1126 1127 for (Handle<Map> receiver_map : *receiver_maps) { 1128 // Mark all stable receiver maps that have elements kind transition map 1129 // among receiver_maps as unstable because the optimizing compilers may 1130 // generate an elements kind transition for this kind of receivers. 1131 if (receiver_map->is_stable()) { 1132 Map* tmap = receiver_map->FindElementsKindTransitionedMap(isolate(), 1133 *receiver_maps); 1134 if (tmap != nullptr) { 1135 receiver_map->NotifyLeafMapLayoutChange(isolate()); 1136 } 1137 } 1138 handlers->push_back( 1139 MaybeObjectHandle(LoadElementHandler(receiver_map, load_mode))); 1140 } 1141 } 1142 1143 namespace { 1144 1145 bool ConvertKeyToIndex(Handle<Object> receiver, Handle<Object> key, 1146 uint32_t* index) { 1147 if (!FLAG_use_ic) return false; 1148 if (receiver->IsAccessCheckNeeded() || receiver->IsJSValue()) return false; 1149 1150 // For regular JSReceiver or String receivers, the {key} must be a positive 1151 // array index. 1152 if (receiver->IsJSReceiver() || receiver->IsString()) { 1153 if (key->ToArrayIndex(index)) return true; 1154 } 1155 // For JSTypedArray receivers, we can also support negative keys, which we 1156 // just map into the [2**31, 2**32 - 1] range via a bit_cast. This is valid 1157 // because JSTypedArray::length is always a Smi, so such keys will always 1158 // be detected as OOB. 1159 if (receiver->IsJSTypedArray()) { 1160 int32_t signed_index; 1161 if (key->ToInt32(&signed_index)) { 1162 *index = bit_cast<uint32_t>(signed_index); 1163 return true; 1164 } 1165 } 1166 return false; 1167 } 1168 1169 bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) { 1170 uint32_t length = 0; 1171 if (receiver->IsJSArray()) { 1172 JSArray::cast(*receiver)->length()->ToArrayLength(&length); 1173 } else if (receiver->IsString()) { 1174 length = String::cast(*receiver)->length(); 1175 } else if (receiver->IsJSObject()) { 1176 length = JSObject::cast(*receiver)->elements()->length(); 1177 } else { 1178 return false; 1179 } 1180 return index >= length; 1181 } 1182 1183 KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver, 1184 uint32_t index) { 1185 if (IsOutOfBoundsAccess(receiver, index)) { 1186 if (receiver->IsJSTypedArray()) { 1187 // For JSTypedArray we never lookup elements in the prototype chain. 1188 return LOAD_IGNORE_OUT_OF_BOUNDS; 1189 } 1190 1191 // For other {receiver}s we need to check the "no elements" protector. 1192 if (isolate->IsNoElementsProtectorIntact()) { 1193 if (receiver->IsString()) { 1194 // ToObject(receiver) will have the initial String.prototype. 1195 return LOAD_IGNORE_OUT_OF_BOUNDS; 1196 } 1197 if (receiver->IsJSObject()) { 1198 // For other JSObjects (including JSArrays) we can only continue if 1199 // the {receiver}s prototype is either the initial Object.prototype 1200 // or the initial Array.prototype, which are both guarded by the 1201 // "no elements" protector checked above. 1202 Handle<Object> receiver_prototype( 1203 JSObject::cast(*receiver)->map()->prototype(), isolate); 1204 if (isolate->IsInAnyContext(*receiver_prototype, 1205 Context::INITIAL_ARRAY_PROTOTYPE_INDEX) || 1206 isolate->IsInAnyContext(*receiver_prototype, 1207 Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) { 1208 return LOAD_IGNORE_OUT_OF_BOUNDS; 1209 } 1210 } 1211 } 1212 } 1213 return STANDARD_LOAD; 1214 } 1215 1216 } // namespace 1217 1218 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, 1219 Handle<Object> key) { 1220 if (MigrateDeprecated(object)) { 1221 Handle<Object> result; 1222 ASSIGN_RETURN_ON_EXCEPTION( 1223 isolate(), result, Runtime::GetObjectProperty(isolate(), object, key), 1224 Object); 1225 return result; 1226 } 1227 1228 Handle<Object> load_handle; 1229 1230 // Check for non-string values that can be converted into an 1231 // internalized string directly or is representable as a smi. 1232 key = TryConvertKey(key, isolate()); 1233 1234 uint32_t index; 1235 if ((key->IsInternalizedString() && 1236 !String::cast(*key)->AsArrayIndex(&index)) || 1237 key->IsSymbol()) { 1238 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle, 1239 LoadIC::Load(object, Handle<Name>::cast(key)), 1240 Object); 1241 } else if (ConvertKeyToIndex(object, key, &index)) { 1242 KeyedAccessLoadMode load_mode = GetLoadMode(isolate(), object, index); 1243 UpdateLoadElement(Handle<HeapObject>::cast(object), load_mode); 1244 if (is_vector_set()) { 1245 TraceIC("LoadIC", key); 1246 } 1247 } 1248 1249 if (vector_needs_update()) { 1250 ConfigureVectorState(MEGAMORPHIC, key); 1251 TraceIC("LoadIC", key); 1252 } 1253 1254 if (!load_handle.is_null()) return load_handle; 1255 1256 Handle<Object> result; 1257 ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, 1258 Runtime::GetObjectProperty(isolate(), object, key), 1259 Object); 1260 return result; 1261 } 1262 1263 1264 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, 1265 JSReceiver::StoreFromKeyed store_mode) { 1266 // Disable ICs for non-JSObjects for now. 1267 Handle<Object> object = it->GetReceiver(); 1268 if (object->IsJSProxy()) return true; 1269 if (!object->IsJSObject()) return false; 1270 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1271 DCHECK(!receiver->map()->is_deprecated()); 1272 1273 if (it->state() != LookupIterator::TRANSITION) { 1274 for (; it->IsFound(); it->Next()) { 1275 switch (it->state()) { 1276 case LookupIterator::NOT_FOUND: 1277 case LookupIterator::TRANSITION: 1278 UNREACHABLE(); 1279 case LookupIterator::JSPROXY: 1280 return true; 1281 case LookupIterator::INTERCEPTOR: { 1282 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1283 InterceptorInfo* info = holder->GetNamedInterceptor(); 1284 if (it->HolderIsReceiverOrHiddenPrototype()) { 1285 return !info->non_masking() && receiver.is_identical_to(holder) && 1286 !info->setter()->IsUndefined(isolate()); 1287 } else if (!info->getter()->IsUndefined(isolate()) || 1288 !info->query()->IsUndefined(isolate())) { 1289 return false; 1290 } 1291 break; 1292 } 1293 case LookupIterator::ACCESS_CHECK: 1294 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false; 1295 break; 1296 case LookupIterator::ACCESSOR: 1297 return !it->IsReadOnly(); 1298 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1299 return false; 1300 case LookupIterator::DATA: { 1301 if (it->IsReadOnly()) return false; 1302 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1303 if (receiver.is_identical_to(holder)) { 1304 it->PrepareForDataProperty(value); 1305 // The previous receiver map might just have been deprecated, 1306 // so reload it. 1307 update_receiver_map(receiver); 1308 return true; 1309 } 1310 1311 // Receiver != holder. 1312 if (receiver->IsJSGlobalProxy()) { 1313 PrototypeIterator iter(isolate(), receiver); 1314 return it->GetHolder<Object>().is_identical_to( 1315 PrototypeIterator::GetCurrent(iter)); 1316 } 1317 1318 if (it->HolderIsReceiverOrHiddenPrototype()) return false; 1319 1320 if (it->ExtendingNonExtensible(receiver)) return false; 1321 it->PrepareTransitionToDataProperty(receiver, value, NONE, 1322 store_mode); 1323 return it->IsCacheableTransition(); 1324 } 1325 } 1326 } 1327 } 1328 1329 receiver = it->GetStoreTarget<JSObject>(); 1330 if (it->ExtendingNonExtensible(receiver)) return false; 1331 it->PrepareTransitionToDataProperty(receiver, value, NONE, store_mode); 1332 return it->IsCacheableTransition(); 1333 } 1334 1335 MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name, 1336 Handle<Object> value) { 1337 DCHECK(name->IsString()); 1338 1339 // Look up in script context table. 1340 Handle<String> str_name = Handle<String>::cast(name); 1341 Handle<JSGlobalObject> global = isolate()->global_object(); 1342 Handle<ScriptContextTable> script_contexts( 1343 global->native_context()->script_context_table(), isolate()); 1344 1345 ScriptContextTable::LookupResult lookup_result; 1346 if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name, 1347 &lookup_result)) { 1348 Handle<Context> script_context = ScriptContextTable::GetContext( 1349 isolate(), script_contexts, lookup_result.context_index); 1350 if (lookup_result.mode == VariableMode::kConst) { 1351 return TypeError(MessageTemplate::kConstAssign, global, name); 1352 } 1353 1354 Handle<Object> previous_value = 1355 FixedArray::get(*script_context, lookup_result.slot_index, isolate()); 1356 1357 if (previous_value->IsTheHole(isolate())) { 1358 // Do not install stubs and stay pre-monomorphic for 1359 // uninitialized accesses. 1360 return ReferenceError(name); 1361 } 1362 1363 if (FLAG_use_ic) { 1364 if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index, 1365 lookup_result.slot_index)) { 1366 TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField); 1367 } else { 1368 // Given combination of indices can't be encoded, so use slow stub. 1369 TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub); 1370 PatchCache(name, slow_stub()); 1371 } 1372 TraceIC("StoreGlobalIC", name); 1373 } 1374 1375 script_context->set(lookup_result.slot_index, *value); 1376 return value; 1377 } 1378 1379 return StoreIC::Store(global, name, value); 1380 } 1381 1382 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, 1383 Handle<Object> value, 1384 JSReceiver::StoreFromKeyed store_mode) { 1385 // TODO(verwaest): Let SetProperty do the migration, since storing a property 1386 // might deprecate the current map again, if value does not fit. 1387 if (MigrateDeprecated(object)) { 1388 Handle<Object> result; 1389 ASSIGN_RETURN_ON_EXCEPTION( 1390 isolate(), result, 1391 Object::SetProperty(isolate(), object, name, value, language_mode()), 1392 Object); 1393 return result; 1394 } 1395 1396 // If the object is undefined or null it's illegal to try to set any 1397 // properties on it; throw a TypeError in that case. 1398 if (object->IsNullOrUndefined(isolate())) { 1399 if (FLAG_use_ic && state() != PREMONOMORPHIC) { 1400 // Ensure the IC state progresses. 1401 TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver); 1402 update_receiver_map(object); 1403 PatchCache(name, slow_stub()); 1404 TraceIC("StoreIC", name); 1405 } 1406 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name); 1407 } 1408 1409 if (state() != UNINITIALIZED) { 1410 JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate()); 1411 } 1412 LookupIterator it(isolate(), object, name); 1413 bool use_ic = FLAG_use_ic; 1414 1415 if (name->IsPrivate()) { 1416 if (name->IsPrivateField() && !it.IsFound()) { 1417 return TypeError(MessageTemplate::kInvalidPrivateFieldAccess, object, 1418 name); 1419 } 1420 1421 // IC handling of private fields/symbols stores on JSProxy is not 1422 // supported. 1423 if (object->IsJSProxy()) { 1424 use_ic = false; 1425 } 1426 } 1427 if (use_ic) UpdateCaches(&it, value, store_mode); 1428 1429 MAYBE_RETURN_NULL( 1430 Object::SetProperty(&it, value, language_mode(), store_mode)); 1431 return value; 1432 } 1433 1434 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, 1435 JSReceiver::StoreFromKeyed store_mode) { 1436 if (state() == UNINITIALIZED && !IsStoreGlobalIC()) { 1437 // This is the first time we execute this inline cache. Transition 1438 // to premonomorphic state to delay setting the monomorphic state. 1439 TRACE_HANDLER_STATS(isolate(), StoreIC_Premonomorphic); 1440 ConfigureVectorState(receiver_map()); 1441 TraceIC("StoreIC", lookup->name()); 1442 return; 1443 } 1444 1445 MaybeObjectHandle handler; 1446 if (LookupForWrite(lookup, value, store_mode)) { 1447 if (IsStoreGlobalIC()) { 1448 if (lookup->state() == LookupIterator::DATA && 1449 lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) { 1450 DCHECK(lookup->GetReceiver()->IsJSGlobalObject()); 1451 // Now update the cell in the feedback vector. 1452 nexus()->ConfigurePropertyCellMode(lookup->GetPropertyCell()); 1453 TraceIC("StoreGlobalIC", lookup->name()); 1454 return; 1455 } 1456 } 1457 handler = ComputeHandler(lookup); 1458 } else { 1459 set_slow_stub_reason("LookupForWrite said 'false'"); 1460 // TODO(marja): change slow_stub to return MaybeObjectHandle. 1461 handler = MaybeObjectHandle(slow_stub()); 1462 } 1463 1464 PatchCache(lookup->name(), handler); 1465 TraceIC("StoreIC", lookup->name()); 1466 } 1467 1468 MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { 1469 switch (lookup->state()) { 1470 case LookupIterator::TRANSITION: { 1471 Handle<JSObject> store_target = lookup->GetStoreTarget<JSObject>(); 1472 if (store_target->IsJSGlobalObject()) { 1473 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH); 1474 1475 if (receiver_map()->IsJSGlobalObject()) { 1476 DCHECK(IsStoreGlobalIC()); 1477 #ifdef DEBUG 1478 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1479 DCHECK_EQ(*lookup->GetReceiver(), *holder); 1480 DCHECK_EQ(*store_target, *holder); 1481 #endif 1482 return StoreHandler::StoreGlobal(lookup->transition_cell()); 1483 } 1484 1485 Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate()); 1486 Handle<Object> handler = StoreHandler::StoreThroughPrototype( 1487 isolate(), receiver_map(), store_target, smi_handler, 1488 MaybeObjectHandle::Weak(lookup->transition_cell())); 1489 return MaybeObjectHandle(handler); 1490 } 1491 // Dictionary-to-fast transitions are not expected and not supported. 1492 DCHECK_IMPLIES(!lookup->transition_map()->is_dictionary_map(), 1493 !receiver_map()->is_dictionary_map()); 1494 1495 DCHECK(lookup->IsCacheableTransition()); 1496 1497 return StoreHandler::StoreTransition(isolate(), lookup->transition_map()); 1498 } 1499 1500 case LookupIterator::INTERCEPTOR: { 1501 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1502 USE(holder); 1503 1504 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate())); 1505 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub); 1506 StoreInterceptorStub stub(isolate()); 1507 return MaybeObjectHandle(stub.GetCode()); 1508 } 1509 1510 case LookupIterator::ACCESSOR: { 1511 // This is currently guaranteed by checks in StoreIC::Store. 1512 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); 1513 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1514 DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate()); 1515 1516 if (!holder->HasFastProperties()) { 1517 set_slow_stub_reason("accessor on slow map"); 1518 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1519 return MaybeObjectHandle(slow_stub()); 1520 } 1521 Handle<Object> accessors = lookup->GetAccessors(); 1522 if (accessors->IsAccessorInfo()) { 1523 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors); 1524 if (v8::ToCData<Address>(info->setter()) == kNullAddress) { 1525 set_slow_stub_reason("setter == kNullAddress"); 1526 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1527 return MaybeObjectHandle(slow_stub()); 1528 } 1529 if (AccessorInfo::cast(*accessors)->is_special_data_property() && 1530 !lookup->HolderIsReceiverOrHiddenPrototype()) { 1531 set_slow_stub_reason("special data property in prototype chain"); 1532 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1533 return MaybeObjectHandle(slow_stub()); 1534 } 1535 if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) { 1536 set_slow_stub_reason("incompatible receiver type"); 1537 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1538 return MaybeObjectHandle(slow_stub()); 1539 } 1540 1541 Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty( 1542 isolate(), lookup->GetAccessorIndex()); 1543 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNativeDataPropertyDH); 1544 if (receiver.is_identical_to(holder)) { 1545 return MaybeObjectHandle(smi_handler); 1546 } 1547 TRACE_HANDLER_STATS(isolate(), 1548 StoreIC_StoreNativeDataPropertyOnPrototypeDH); 1549 return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( 1550 isolate(), receiver_map(), holder, smi_handler)); 1551 1552 } else if (accessors->IsAccessorPair()) { 1553 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), 1554 isolate()); 1555 if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) { 1556 set_slow_stub_reason("setter not a function"); 1557 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1558 return MaybeObjectHandle(slow_stub()); 1559 } 1560 1561 if (setter->IsFunctionTemplateInfo() && 1562 FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) { 1563 // Do not install an IC if the api function has a breakpoint. 1564 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1565 return MaybeObjectHandle(slow_stub()); 1566 } 1567 1568 CallOptimization call_optimization(isolate(), setter); 1569 if (call_optimization.is_simple_api_call()) { 1570 if (call_optimization.IsCompatibleReceiver(receiver, holder)) { 1571 CallOptimization::HolderLookup holder_lookup; 1572 call_optimization.LookupHolderOfExpectedType(receiver_map(), 1573 &holder_lookup); 1574 1575 Handle<Smi> smi_handler = StoreHandler::StoreApiSetter( 1576 isolate(), 1577 holder_lookup == CallOptimization::kHolderIsReceiver); 1578 1579 Handle<Context> context( 1580 call_optimization.GetAccessorContext(holder->map()), isolate()); 1581 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH); 1582 return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( 1583 isolate(), receiver_map(), holder, smi_handler, 1584 MaybeObjectHandle::Weak(call_optimization.api_call_info()), 1585 MaybeObjectHandle::Weak(context))); 1586 } 1587 set_slow_stub_reason("incompatible receiver"); 1588 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1589 return MaybeObjectHandle(slow_stub()); 1590 } else if (setter->IsFunctionTemplateInfo()) { 1591 set_slow_stub_reason("setter non-simple template"); 1592 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1593 return MaybeObjectHandle(slow_stub()); 1594 } 1595 1596 Handle<Smi> smi_handler = 1597 StoreHandler::StoreAccessor(isolate(), lookup->GetAccessorIndex()); 1598 1599 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorDH); 1600 if (receiver.is_identical_to(holder)) { 1601 return MaybeObjectHandle(smi_handler); 1602 } 1603 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreAccessorOnPrototypeDH); 1604 1605 return MaybeObjectHandle(StoreHandler::StoreThroughPrototype( 1606 isolate(), receiver_map(), holder, smi_handler)); 1607 } 1608 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1609 return MaybeObjectHandle(slow_stub()); 1610 } 1611 1612 case LookupIterator::DATA: { 1613 // This is currently guaranteed by checks in StoreIC::Store. 1614 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); 1615 USE(receiver); 1616 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1617 DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate()); 1618 1619 DCHECK_EQ(kData, lookup->property_details().kind()); 1620 if (lookup->is_dictionary_holder()) { 1621 if (holder->IsJSGlobalObject()) { 1622 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH); 1623 return MaybeObjectHandle( 1624 StoreHandler::StoreGlobal(lookup->GetPropertyCell())); 1625 } 1626 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH); 1627 DCHECK(holder.is_identical_to(receiver)); 1628 return MaybeObjectHandle(StoreHandler::StoreNormal(isolate())); 1629 } 1630 1631 // -------------- Fields -------------- 1632 if (lookup->property_details().location() == kField) { 1633 TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH); 1634 int descriptor = lookup->GetFieldDescriptorIndex(); 1635 FieldIndex index = lookup->GetFieldIndex(); 1636 PropertyConstness constness = lookup->constness(); 1637 if (constness == PropertyConstness::kConst && 1638 IsStoreOwnICKind(nexus()->kind())) { 1639 // StoreOwnICs are used for initializing object literals therefore 1640 // we must store the value unconditionally even to 1641 // VariableMode::kConst fields. 1642 constness = PropertyConstness::kMutable; 1643 } 1644 return MaybeObjectHandle(StoreHandler::StoreField( 1645 isolate(), descriptor, index, constness, lookup->representation())); 1646 } 1647 1648 // -------------- Constant properties -------------- 1649 DCHECK_EQ(kDescriptor, lookup->property_details().location()); 1650 set_slow_stub_reason("constant property"); 1651 TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub); 1652 return MaybeObjectHandle(slow_stub()); 1653 } 1654 case LookupIterator::JSPROXY: { 1655 Handle<JSReceiver> receiver = 1656 Handle<JSReceiver>::cast(lookup->GetReceiver()); 1657 Handle<JSProxy> holder = lookup->GetHolder<JSProxy>(); 1658 return MaybeObjectHandle(StoreHandler::StoreProxy( 1659 isolate(), receiver_map(), holder, receiver)); 1660 } 1661 1662 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1663 case LookupIterator::ACCESS_CHECK: 1664 case LookupIterator::NOT_FOUND: 1665 UNREACHABLE(); 1666 } 1667 return MaybeObjectHandle(); 1668 } 1669 1670 void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map, 1671 KeyedAccessStoreMode store_mode, 1672 bool receiver_was_cow) { 1673 MapHandles target_receiver_maps; 1674 TargetMaps(&target_receiver_maps); 1675 if (target_receiver_maps.empty()) { 1676 Handle<Map> monomorphic_map = 1677 ComputeTransitionedMap(receiver_map, store_mode); 1678 store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow); 1679 Handle<Object> handler = StoreElementHandler(monomorphic_map, store_mode); 1680 return ConfigureVectorState(Handle<Name>(), monomorphic_map, handler); 1681 } 1682 1683 for (Handle<Map> map : target_receiver_maps) { 1684 if (!map.is_null() && map->instance_type() == JS_VALUE_TYPE) { 1685 DCHECK(!IsStoreInArrayLiteralICKind(kind())); 1686 set_slow_stub_reason("JSValue"); 1687 return; 1688 } 1689 } 1690 1691 // There are several special cases where an IC that is MONOMORPHIC can still 1692 // transition to a different GetNonTransitioningStoreMode IC that handles a 1693 // superset of the original IC. Handle those here if the receiver map hasn't 1694 // changed or it has transitioned to a more general kind. 1695 KeyedAccessStoreMode old_store_mode; 1696 old_store_mode = GetKeyedAccessStoreMode(); 1697 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); 1698 if (state() == MONOMORPHIC) { 1699 Handle<Map> transitioned_receiver_map = receiver_map; 1700 if (IsTransitionStoreMode(store_mode)) { 1701 transitioned_receiver_map = 1702 ComputeTransitionedMap(receiver_map, store_mode); 1703 } 1704 if ((receiver_map.is_identical_to(previous_receiver_map) && 1705 IsTransitionStoreMode(store_mode)) || 1706 IsTransitionOfMonomorphicTarget(*previous_receiver_map, 1707 *transitioned_receiver_map)) { 1708 // If the "old" and "new" maps are in the same elements map family, or 1709 // if they at least come from the same origin for a transitioning store, 1710 // stay MONOMORPHIC and use the map for the most generic ElementsKind. 1711 store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow); 1712 Handle<Object> handler = 1713 StoreElementHandler(transitioned_receiver_map, store_mode); 1714 ConfigureVectorState(Handle<Name>(), transitioned_receiver_map, handler); 1715 return; 1716 } 1717 if (receiver_map.is_identical_to(previous_receiver_map) && 1718 old_store_mode == STANDARD_STORE && 1719 (store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || 1720 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1721 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { 1722 // A "normal" IC that handles stores can switch to a version that can 1723 // grow at the end of the array, handle OOB accesses or copy COW arrays 1724 // and still stay MONOMORPHIC. 1725 Handle<Object> handler = StoreElementHandler(receiver_map, store_mode); 1726 return ConfigureVectorState(Handle<Name>(), receiver_map, handler); 1727 } 1728 } 1729 1730 DCHECK(state() != GENERIC); 1731 1732 bool map_added = 1733 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); 1734 1735 if (IsTransitionStoreMode(store_mode)) { 1736 Handle<Map> transitioned_receiver_map = 1737 ComputeTransitionedMap(receiver_map, store_mode); 1738 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, 1739 transitioned_receiver_map); 1740 } 1741 1742 if (!map_added) { 1743 // If the miss wasn't due to an unseen map, a polymorphic stub 1744 // won't help, use the megamorphic stub which can handle everything. 1745 set_slow_stub_reason("same map added twice"); 1746 return; 1747 } 1748 1749 // If the maximum number of receiver maps has been exceeded, use the 1750 // megamorphic version of the IC. 1751 if (target_receiver_maps.size() > kMaxKeyedPolymorphism) return; 1752 1753 // Make sure all polymorphic handlers have the same store mode, otherwise the 1754 // megamorphic stub must be used. 1755 store_mode = GetNonTransitioningStoreMode(store_mode, receiver_was_cow); 1756 if (old_store_mode != STANDARD_STORE) { 1757 if (store_mode == STANDARD_STORE) { 1758 store_mode = old_store_mode; 1759 } else if (store_mode != old_store_mode) { 1760 set_slow_stub_reason("store mode mismatch"); 1761 return; 1762 } 1763 } 1764 1765 // If the store mode isn't the standard mode, make sure that all polymorphic 1766 // receivers are either external arrays, or all "normal" arrays. Otherwise, 1767 // use the megamorphic stub. 1768 if (store_mode != STANDARD_STORE) { 1769 size_t external_arrays = 0; 1770 for (Handle<Map> map : target_receiver_maps) { 1771 if (map->has_fixed_typed_array_elements()) { 1772 DCHECK(!IsStoreInArrayLiteralICKind(kind())); 1773 external_arrays++; 1774 } 1775 } 1776 if (external_arrays != 0 && 1777 external_arrays != target_receiver_maps.size()) { 1778 DCHECK(!IsStoreInArrayLiteralICKind(kind())); 1779 set_slow_stub_reason( 1780 "unsupported combination of external and normal arrays"); 1781 return; 1782 } 1783 } 1784 1785 MaybeObjectHandles handlers; 1786 handlers.reserve(target_receiver_maps.size()); 1787 StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode); 1788 if (target_receiver_maps.size() == 0) { 1789 // Transition to PREMONOMORPHIC state here and remember a weak-reference 1790 // to the {receiver_map} in case TurboFan sees this function before the 1791 // IC can transition further. 1792 ConfigureVectorState(receiver_map); 1793 } else if (target_receiver_maps.size() == 1) { 1794 ConfigureVectorState(Handle<Name>(), target_receiver_maps[0], handlers[0]); 1795 } else { 1796 ConfigureVectorState(Handle<Name>(), target_receiver_maps, &handlers); 1797 } 1798 } 1799 1800 1801 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( 1802 Handle<Map> map, KeyedAccessStoreMode store_mode) { 1803 switch (store_mode) { 1804 case STORE_TRANSITION_TO_OBJECT: 1805 case STORE_AND_GROW_TRANSITION_TO_OBJECT: { 1806 ElementsKind kind = IsHoleyElementsKind(map->elements_kind()) 1807 ? HOLEY_ELEMENTS 1808 : PACKED_ELEMENTS; 1809 return Map::TransitionElementsTo(isolate(), map, kind); 1810 } 1811 case STORE_TRANSITION_TO_DOUBLE: 1812 case STORE_AND_GROW_TRANSITION_TO_DOUBLE: { 1813 ElementsKind kind = IsHoleyElementsKind(map->elements_kind()) 1814 ? HOLEY_DOUBLE_ELEMENTS 1815 : PACKED_DOUBLE_ELEMENTS; 1816 return Map::TransitionElementsTo(isolate(), map, kind); 1817 } 1818 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: 1819 DCHECK(map->has_fixed_typed_array_elements()); 1820 V8_FALLTHROUGH; 1821 case STORE_NO_TRANSITION_HANDLE_COW: 1822 case STANDARD_STORE: 1823 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW: 1824 return map; 1825 } 1826 UNREACHABLE(); 1827 } 1828 1829 Handle<Object> KeyedStoreIC::StoreElementHandler( 1830 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { 1831 DCHECK(store_mode == STANDARD_STORE || 1832 store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || 1833 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1834 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 1835 DCHECK_IMPLIES( 1836 receiver_map->DictionaryElementsInPrototypeChainOnly(isolate()), 1837 IsStoreInArrayLiteralICKind(kind())); 1838 1839 if (receiver_map->IsJSProxyMap()) { 1840 return StoreHandler::StoreProxy(isolate()); 1841 } 1842 1843 // TODO(ishell): move to StoreHandler::StoreElement(). 1844 ElementsKind elements_kind = receiver_map->elements_kind(); 1845 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; 1846 Handle<Code> stub; 1847 if (receiver_map->has_sloppy_arguments_elements()) { 1848 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub); 1849 stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode(); 1850 } else if (receiver_map->has_fast_elements() || 1851 receiver_map->has_fixed_typed_array_elements()) { 1852 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub); 1853 stub = 1854 StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode) 1855 .GetCode(); 1856 if (receiver_map->has_fixed_typed_array_elements()) return stub; 1857 } else if (IsStoreInArrayLiteralICKind(kind())) { 1858 TRACE_HANDLER_STATS(isolate(), StoreInArrayLiteralIC_SlowStub); 1859 stub = StoreInArrayLiteralSlowStub(isolate(), store_mode).GetCode(); 1860 } else { 1861 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub); 1862 DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind); 1863 stub = StoreSlowElementStub(isolate(), store_mode).GetCode(); 1864 } 1865 1866 if (IsStoreInArrayLiteralICKind(kind())) return stub; 1867 1868 Handle<Object> validity_cell = 1869 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); 1870 if (validity_cell->IsSmi()) { 1871 // There's no prototype validity cell to check, so we can just use the stub. 1872 return stub; 1873 } 1874 Handle<StoreHandler> handler = isolate()->factory()->NewStoreHandler(0); 1875 handler->set_validity_cell(*validity_cell); 1876 handler->set_smi_handler(*stub); 1877 return handler; 1878 } 1879 1880 void KeyedStoreIC::StoreElementPolymorphicHandlers( 1881 MapHandles* receiver_maps, MaybeObjectHandles* handlers, 1882 KeyedAccessStoreMode store_mode) { 1883 DCHECK(store_mode == STANDARD_STORE || 1884 store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW || 1885 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1886 store_mode == STORE_NO_TRANSITION_HANDLE_COW); 1887 1888 // Filter out deprecated maps to ensure their instances get migrated. 1889 receiver_maps->erase( 1890 std::remove_if( 1891 receiver_maps->begin(), receiver_maps->end(), 1892 [](const Handle<Map>& map) { return map->is_deprecated(); }), 1893 receiver_maps->end()); 1894 1895 for (Handle<Map> receiver_map : *receiver_maps) { 1896 Handle<Object> handler; 1897 Handle<Map> transition; 1898 1899 if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE || 1900 receiver_map->DictionaryElementsInPrototypeChainOnly(isolate())) { 1901 // TODO(mvstanton): Consider embedding store_mode in the state of the slow 1902 // keyed store ic for uniformity. 1903 TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub); 1904 handler = slow_stub(); 1905 1906 } else { 1907 { 1908 Map* tmap = receiver_map->FindElementsKindTransitionedMap( 1909 isolate(), *receiver_maps); 1910 if (tmap != nullptr) { 1911 if (receiver_map->is_stable()) { 1912 receiver_map->NotifyLeafMapLayoutChange(isolate()); 1913 } 1914 transition = handle(tmap, isolate()); 1915 } 1916 } 1917 1918 // TODO(mvstanton): The code below is doing pessimistic elements 1919 // transitions. I would like to stop doing that and rely on Allocation 1920 // Site Tracking to do a better job of ensuring the data types are what 1921 // they need to be. Not all the elements are in place yet, pessimistic 1922 // elements transitions are still important for performance. 1923 if (!transition.is_null()) { 1924 TRACE_HANDLER_STATS(isolate(), 1925 KeyedStoreIC_ElementsTransitionAndStoreStub); 1926 handler = StoreHandler::StoreElementTransition(isolate(), receiver_map, 1927 transition, store_mode); 1928 } else { 1929 handler = StoreElementHandler(receiver_map, store_mode); 1930 } 1931 } 1932 DCHECK(!handler.is_null()); 1933 handlers->push_back(MaybeObjectHandle(handler)); 1934 } 1935 } 1936 1937 1938 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, 1939 uint32_t index, Handle<Object> value) { 1940 bool oob_access = IsOutOfBoundsAccess(receiver, index); 1941 // Don't consider this a growing store if the store would send the receiver to 1942 // dictionary mode. 1943 bool allow_growth = receiver->IsJSArray() && oob_access && 1944 !receiver->WouldConvertToSlowElements(index); 1945 if (allow_growth) { 1946 // Handle growing array in stub if necessary. 1947 if (receiver->HasSmiElements()) { 1948 if (value->IsHeapNumber()) { 1949 return STORE_AND_GROW_TRANSITION_TO_DOUBLE; 1950 } 1951 if (value->IsHeapObject()) { 1952 return STORE_AND_GROW_TRANSITION_TO_OBJECT; 1953 } 1954 } else if (receiver->HasDoubleElements()) { 1955 if (!value->IsSmi() && !value->IsHeapNumber()) { 1956 return STORE_AND_GROW_TRANSITION_TO_OBJECT; 1957 } 1958 } 1959 return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW; 1960 } else { 1961 // Handle only in-bounds elements accesses. 1962 if (receiver->HasSmiElements()) { 1963 if (value->IsHeapNumber()) { 1964 return STORE_TRANSITION_TO_DOUBLE; 1965 } else if (value->IsHeapObject()) { 1966 return STORE_TRANSITION_TO_OBJECT; 1967 } 1968 } else if (receiver->HasDoubleElements()) { 1969 if (!value->IsSmi() && !value->IsHeapNumber()) { 1970 return STORE_TRANSITION_TO_OBJECT; 1971 } 1972 } 1973 if (!FLAG_trace_external_array_abuse && 1974 receiver->map()->has_fixed_typed_array_elements() && oob_access) { 1975 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS; 1976 } 1977 return receiver->elements()->IsCowArray() ? STORE_NO_TRANSITION_HANDLE_COW 1978 : STANDARD_STORE; 1979 } 1980 } 1981 1982 1983 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, 1984 Handle<Object> key, 1985 Handle<Object> value) { 1986 // TODO(verwaest): Let SetProperty do the migration, since storing a property 1987 // might deprecate the current map again, if value does not fit. 1988 if (MigrateDeprecated(object)) { 1989 Handle<Object> result; 1990 ASSIGN_RETURN_ON_EXCEPTION( 1991 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key, 1992 value, language_mode()), 1993 Object); 1994 return result; 1995 } 1996 1997 // Check for non-string values that can be converted into an 1998 // internalized string directly or is representable as a smi. 1999 key = TryConvertKey(key, isolate()); 2000 2001 Handle<Object> store_handle; 2002 2003 uint32_t index; 2004 if ((key->IsInternalizedString() && 2005 !String::cast(*key)->AsArrayIndex(&index)) || 2006 key->IsSymbol()) { 2007 ASSIGN_RETURN_ON_EXCEPTION( 2008 isolate(), store_handle, 2009 StoreIC::Store(object, Handle<Name>::cast(key), value, 2010 JSReceiver::MAY_BE_STORE_FROM_KEYED), 2011 Object); 2012 if (vector_needs_update()) { 2013 if (ConfigureVectorState(MEGAMORPHIC, key)) { 2014 set_slow_stub_reason("unhandled internalized string key"); 2015 TraceIC("StoreIC", key); 2016 } 2017 } 2018 return store_handle; 2019 } 2020 2021 JSObject::MakePrototypesFast(object, kStartAtPrototype, isolate()); 2022 2023 bool use_ic = FLAG_use_ic && !object->IsStringWrapper() && 2024 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy(); 2025 if (use_ic && !object->IsSmi()) { 2026 // Don't use ICs for maps of the objects in Array's prototype chain. We 2027 // expect to be able to trap element sets to objects with those maps in 2028 // the runtime to enable optimization of element hole access. 2029 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 2030 if (heap_object->map()->IsMapInArrayPrototypeChain(isolate())) { 2031 set_slow_stub_reason("map in array prototype"); 2032 use_ic = false; 2033 } 2034 } 2035 2036 Handle<Map> old_receiver_map; 2037 bool is_arguments = false; 2038 bool key_is_valid_index = false; 2039 KeyedAccessStoreMode store_mode = STANDARD_STORE; 2040 if (use_ic && object->IsJSReceiver()) { 2041 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); 2042 old_receiver_map = handle(receiver->map(), isolate()); 2043 is_arguments = receiver->IsJSArgumentsObject(); 2044 bool is_proxy = receiver->IsJSProxy(); 2045 // For JSTypedArray {object}s we can handle negative indices as OOB 2046 // accesses, since integer indexed properties are never looked up 2047 // on the prototype chain. For this we simply map the negative {key}s 2048 // to the [2**31,2**32-1] range, which is safe since JSTypedArray::length 2049 // is always an unsigned Smi. 2050 key_is_valid_index = 2051 key->IsSmi() && (Smi::ToInt(*key) >= 0 || object->IsJSTypedArray()); 2052 if (!is_arguments && !is_proxy) { 2053 if (key_is_valid_index) { 2054 uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key)); 2055 Handle<JSObject> receiver_object = Handle<JSObject>::cast(object); 2056 store_mode = GetStoreMode(receiver_object, index, value); 2057 } 2058 } 2059 } 2060 2061 DCHECK(store_handle.is_null()); 2062 bool receiver_was_cow = 2063 object->IsJSArray() && 2064 Handle<JSArray>::cast(object)->elements()->IsCowArray(); 2065 ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle, 2066 Runtime::SetObjectProperty(isolate(), object, key, 2067 value, language_mode()), 2068 Object); 2069 2070 if (use_ic) { 2071 if (!old_receiver_map.is_null()) { 2072 if (is_arguments) { 2073 set_slow_stub_reason("arguments receiver"); 2074 } else if (key_is_valid_index) { 2075 if (old_receiver_map->is_abandoned_prototype_map()) { 2076 set_slow_stub_reason("receiver with prototype map"); 2077 } else if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly( 2078 isolate())) { 2079 // We should go generic if receiver isn't a dictionary, but our 2080 // prototype chain does have dictionary elements. This ensures that 2081 // other non-dictionary receivers in the polymorphic case benefit 2082 // from fast path keyed stores. 2083 UpdateStoreElement(old_receiver_map, store_mode, receiver_was_cow); 2084 } else { 2085 set_slow_stub_reason("dictionary or proxy prototype"); 2086 } 2087 } else { 2088 set_slow_stub_reason("non-smi-like key"); 2089 } 2090 } else { 2091 set_slow_stub_reason("non-JSObject receiver"); 2092 } 2093 } 2094 2095 if (vector_needs_update()) { 2096 ConfigureVectorState(MEGAMORPHIC, key); 2097 } 2098 TraceIC("StoreIC", key); 2099 2100 return store_handle; 2101 } 2102 2103 namespace { 2104 void StoreOwnElement(Isolate* isolate, Handle<JSArray> array, 2105 Handle<Object> index, Handle<Object> value) { 2106 DCHECK(index->IsNumber()); 2107 bool success = false; 2108 LookupIterator it = LookupIterator::PropertyOrElement( 2109 isolate, array, index, &success, LookupIterator::OWN); 2110 DCHECK(success); 2111 2112 CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE, 2113 kThrowOnError) 2114 .FromJust()); 2115 } 2116 } // namespace 2117 2118 void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index, 2119 Handle<Object> value) { 2120 DCHECK(!array->map()->IsMapInArrayPrototypeChain(isolate())); 2121 DCHECK(index->IsNumber()); 2122 2123 if (!FLAG_use_ic || MigrateDeprecated(array)) { 2124 StoreOwnElement(isolate(), array, index, value); 2125 TraceIC("StoreInArrayLiteralIC", index); 2126 return; 2127 } 2128 2129 // TODO(neis): Convert HeapNumber to Smi if possible? 2130 2131 KeyedAccessStoreMode store_mode = STANDARD_STORE; 2132 if (index->IsSmi()) { 2133 DCHECK_GE(Smi::ToInt(*index), 0); 2134 uint32_t index32 = static_cast<uint32_t>(Smi::ToInt(*index)); 2135 store_mode = GetStoreMode(array, index32, value); 2136 } 2137 2138 Handle<Map> old_array_map(array->map(), isolate()); 2139 bool array_was_cow = array->elements()->IsCowArray(); 2140 StoreOwnElement(isolate(), array, index, value); 2141 2142 if (index->IsSmi()) { 2143 DCHECK(!old_array_map->is_abandoned_prototype_map()); 2144 UpdateStoreElement(old_array_map, store_mode, array_was_cow); 2145 } else { 2146 set_slow_stub_reason("index out of Smi range"); 2147 } 2148 2149 if (vector_needs_update()) { 2150 ConfigureVectorState(MEGAMORPHIC, index); 2151 } 2152 TraceIC("StoreInArrayLiteralIC", index); 2153 } 2154 2155 // ---------------------------------------------------------------------------- 2156 // Static IC stub generators. 2157 // 2158 2159 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { 2160 HandleScope scope(isolate); 2161 DCHECK_EQ(4, args.length()); 2162 // Runtime functions don't follow the IC's calling convention. 2163 Handle<Object> receiver = args.at(0); 2164 Handle<Name> key = args.at<Name>(1); 2165 Handle<Smi> slot = args.at<Smi>(2); 2166 Handle<FeedbackVector> vector = args.at<FeedbackVector>(3); 2167 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2168 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the 2169 // LoadIC miss handler if the handler misses. Since the vector Nexus is 2170 // set up outside the IC, handle that here. 2171 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2172 if (IsLoadICKind(kind)) { 2173 LoadIC ic(isolate, vector, vector_slot); 2174 ic.UpdateState(receiver, key); 2175 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); 2176 2177 } else if (IsLoadGlobalICKind(kind)) { 2178 DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver); 2179 receiver = isolate->global_object(); 2180 LoadGlobalIC ic(isolate, vector, vector_slot); 2181 ic.UpdateState(receiver, key); 2182 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(key)); 2183 2184 } else { 2185 DCHECK(IsKeyedLoadICKind(kind)); 2186 KeyedLoadIC ic(isolate, vector, vector_slot); 2187 ic.UpdateState(receiver, key); 2188 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); 2189 } 2190 } 2191 2192 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Miss) { 2193 HandleScope scope(isolate); 2194 DCHECK_EQ(3, args.length()); 2195 // Runtime functions don't follow the IC's calling convention. 2196 Handle<JSGlobalObject> global = isolate->global_object(); 2197 Handle<String> name = args.at<String>(0); 2198 Handle<Smi> slot = args.at<Smi>(1); 2199 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2200 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2201 2202 LoadGlobalIC ic(isolate, vector, vector_slot); 2203 ic.UpdateState(global, name); 2204 2205 Handle<Object> result; 2206 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(name)); 2207 return *result; 2208 } 2209 2210 RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) { 2211 HandleScope scope(isolate); 2212 DCHECK_EQ(3, args.length()); 2213 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2214 2215 Handle<Context> native_context = isolate->native_context(); 2216 Handle<ScriptContextTable> script_contexts( 2217 native_context->script_context_table(), isolate); 2218 2219 ScriptContextTable::LookupResult lookup_result; 2220 if (ScriptContextTable::Lookup(isolate, script_contexts, name, 2221 &lookup_result)) { 2222 Handle<Context> script_context = ScriptContextTable::GetContext( 2223 isolate, script_contexts, lookup_result.context_index); 2224 Handle<Object> result = 2225 FixedArray::get(*script_context, lookup_result.slot_index, isolate); 2226 if (*result == ReadOnlyRoots(isolate).the_hole_value()) { 2227 THROW_NEW_ERROR_RETURN_FAILURE( 2228 isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); 2229 } 2230 return *result; 2231 } 2232 2233 Handle<JSGlobalObject> global(native_context->global_object(), isolate); 2234 Handle<Object> result; 2235 bool is_found = false; 2236 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2237 isolate, result, 2238 Runtime::GetObjectProperty(isolate, global, name, &is_found)); 2239 if (!is_found) { 2240 Handle<Smi> slot = args.at<Smi>(1); 2241 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2242 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2243 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2244 // It is actually a LoadGlobalICs here but the predicate handles this case 2245 // properly. 2246 if (LoadIC::ShouldThrowReferenceError(kind)) { 2247 THROW_NEW_ERROR_RETURN_FAILURE( 2248 isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); 2249 } 2250 } 2251 return *result; 2252 } 2253 2254 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) { 2255 HandleScope scope(isolate); 2256 DCHECK_EQ(4, args.length()); 2257 // Runtime functions don't follow the IC's calling convention. 2258 Handle<Object> receiver = args.at(0); 2259 Handle<Object> key = args.at(1); 2260 Handle<Smi> slot = args.at<Smi>(2); 2261 Handle<FeedbackVector> vector = args.at<FeedbackVector>(3); 2262 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2263 KeyedLoadIC ic(isolate, vector, vector_slot); 2264 ic.UpdateState(receiver, key); 2265 RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key)); 2266 } 2267 2268 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { 2269 HandleScope scope(isolate); 2270 DCHECK_EQ(5, args.length()); 2271 // Runtime functions don't follow the IC's calling convention. 2272 Handle<Object> value = args.at(0); 2273 Handle<Smi> slot = args.at<Smi>(1); 2274 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2275 Handle<Object> receiver = args.at(3); 2276 Handle<Name> key = args.at<Name>(4); 2277 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2278 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2279 if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) { 2280 StoreIC ic(isolate, vector, vector_slot); 2281 ic.UpdateState(receiver, key); 2282 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); 2283 } else if (IsStoreGlobalICKind(kind)) { 2284 DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver); 2285 receiver = isolate->global_object(); 2286 StoreGlobalIC ic(isolate, vector, vector_slot); 2287 ic.UpdateState(receiver, key); 2288 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value)); 2289 } else { 2290 DCHECK(IsKeyedStoreICKind(kind)); 2291 KeyedStoreIC ic(isolate, vector, vector_slot); 2292 ic.UpdateState(receiver, key); 2293 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); 2294 } 2295 } 2296 2297 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) { 2298 HandleScope scope(isolate); 2299 DCHECK_EQ(4, args.length()); 2300 // Runtime functions don't follow the IC's calling convention. 2301 Handle<Object> value = args.at(0); 2302 Handle<Smi> slot = args.at<Smi>(1); 2303 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2304 Handle<Name> key = args.at<Name>(3); 2305 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2306 StoreGlobalIC ic(isolate, vector, vector_slot); 2307 Handle<JSGlobalObject> global = isolate->global_object(); 2308 ic.UpdateState(global, key); 2309 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value)); 2310 } 2311 2312 RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) { 2313 HandleScope scope(isolate); 2314 DCHECK_EQ(5, args.length()); 2315 // Runtime functions don't follow the IC's calling convention. 2316 Handle<Object> value = args.at(0); 2317 Handle<Smi> slot = args.at<Smi>(1); 2318 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2319 CONVERT_ARG_HANDLE_CHECKED(String, name, 4); 2320 2321 #ifdef DEBUG 2322 { 2323 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2324 FeedbackSlotKind slot_kind = vector->GetKind(vector_slot); 2325 DCHECK(IsStoreGlobalICKind(slot_kind)); 2326 Handle<Object> receiver = args.at(3); 2327 DCHECK(receiver->IsJSGlobalProxy()); 2328 } 2329 #endif 2330 2331 Handle<JSGlobalObject> global = isolate->global_object(); 2332 Handle<Context> native_context = isolate->native_context(); 2333 Handle<ScriptContextTable> script_contexts( 2334 native_context->script_context_table(), isolate); 2335 2336 ScriptContextTable::LookupResult lookup_result; 2337 if (ScriptContextTable::Lookup(isolate, script_contexts, name, 2338 &lookup_result)) { 2339 Handle<Context> script_context = ScriptContextTable::GetContext( 2340 isolate, script_contexts, lookup_result.context_index); 2341 if (lookup_result.mode == VariableMode::kConst) { 2342 THROW_NEW_ERROR_RETURN_FAILURE( 2343 isolate, NewTypeError(MessageTemplate::kConstAssign, global, name)); 2344 } 2345 2346 Handle<Object> previous_value = 2347 FixedArray::get(*script_context, lookup_result.slot_index, isolate); 2348 2349 if (previous_value->IsTheHole(isolate)) { 2350 THROW_NEW_ERROR_RETURN_FAILURE( 2351 isolate, NewReferenceError(MessageTemplate::kNotDefined, name)); 2352 } 2353 2354 script_context->set(lookup_result.slot_index, *value); 2355 return *value; 2356 } 2357 2358 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2359 LanguageMode language_mode = vector->GetLanguageMode(vector_slot); 2360 RETURN_RESULT_OR_FAILURE( 2361 isolate, 2362 Runtime::SetObjectProperty(isolate, global, name, value, language_mode)); 2363 } 2364 2365 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { 2366 HandleScope scope(isolate); 2367 DCHECK_EQ(5, args.length()); 2368 // Runtime functions don't follow the IC's calling convention. 2369 Handle<Object> value = args.at(0); 2370 Handle<Smi> slot = args.at<Smi>(1); 2371 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2372 Handle<Object> receiver = args.at(3); 2373 Handle<Object> key = args.at(4); 2374 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2375 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2376 2377 // The elements store stubs miss into this function, but they are shared by 2378 // different ICs. 2379 if (IsKeyedStoreICKind(kind)) { 2380 KeyedStoreIC ic(isolate, vector, vector_slot); 2381 ic.UpdateState(receiver, key); 2382 RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value)); 2383 } else { 2384 DCHECK(IsStoreInArrayLiteralICKind(kind)); 2385 DCHECK(receiver->IsJSArray()); 2386 DCHECK(key->IsNumber()); 2387 StoreInArrayLiteralIC ic(isolate, vector, vector_slot); 2388 ic.UpdateState(receiver, key); 2389 ic.Store(Handle<JSArray>::cast(receiver), key, value); 2390 return *value; 2391 } 2392 } 2393 2394 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { 2395 HandleScope scope(isolate); 2396 DCHECK_EQ(5, args.length()); 2397 // Runtime functions don't follow the IC's calling convention. 2398 Handle<Object> value = args.at(0); 2399 Handle<Smi> slot = args.at<Smi>(1); 2400 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2401 Handle<Object> object = args.at(3); 2402 Handle<Object> key = args.at(4); 2403 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2404 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2405 DCHECK(IsStoreICKind(kind) || IsKeyedStoreICKind(kind)); 2406 LanguageMode language_mode = GetLanguageModeFromSlotKind(kind); 2407 RETURN_RESULT_OR_FAILURE( 2408 isolate, 2409 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 2410 } 2411 2412 RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) { 2413 HandleScope scope(isolate); 2414 DCHECK_EQ(3, args.length()); 2415 // Runtime functions don't follow the IC's calling convention. 2416 Handle<Object> value = args.at(0); 2417 Handle<Object> array = args.at(1); 2418 Handle<Object> index = args.at(2); 2419 StoreOwnElement(isolate, Handle<JSArray>::cast(array), index, value); 2420 return *value; 2421 } 2422 2423 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { 2424 HandleScope scope(isolate); 2425 DCHECK_EQ(6, args.length()); 2426 // Runtime functions don't follow the IC's calling convention. 2427 Handle<Object> object = args.at(0); 2428 Handle<Object> key = args.at(1); 2429 Handle<Object> value = args.at(2); 2430 Handle<Map> map = args.at<Map>(3); 2431 Handle<Smi> slot = args.at<Smi>(4); 2432 Handle<FeedbackVector> vector = args.at<FeedbackVector>(5); 2433 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2434 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2435 2436 if (object->IsJSObject()) { 2437 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), 2438 map->elements_kind()); 2439 } 2440 2441 if (IsStoreInArrayLiteralICKind(kind)) { 2442 StoreOwnElement(isolate, Handle<JSArray>::cast(object), key, value); 2443 return *value; 2444 } else { 2445 DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind)); 2446 LanguageMode language_mode = GetLanguageModeFromSlotKind(kind); 2447 RETURN_RESULT_OR_FAILURE( 2448 isolate, 2449 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 2450 } 2451 } 2452 2453 static bool CanFastCloneObject(Handle<Map> map) { 2454 DisallowHeapAllocation no_gc; 2455 if (map->IsNullOrUndefinedMap()) return true; 2456 if (!map->IsJSObjectMap() || 2457 !IsSmiOrObjectElementsKind(map->elements_kind()) || 2458 !map->OnlyHasSimpleProperties()) { 2459 return false; 2460 } 2461 2462 DescriptorArray* descriptors = map->instance_descriptors(); 2463 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) { 2464 PropertyDetails details = descriptors->GetDetails(i); 2465 Name* key = descriptors->GetKey(i); 2466 if (details.kind() != kData || !details.IsEnumerable() || 2467 key->IsPrivateField()) { 2468 return false; 2469 } 2470 } 2471 2472 return true; 2473 } 2474 2475 static Handle<Map> FastCloneObjectMap(Isolate* isolate, 2476 Handle<HeapObject> source, int flags) { 2477 Handle<Map> source_map(source->map(), isolate); 2478 SLOW_DCHECK(source->IsNullOrUndefined() || CanFastCloneObject(source_map)); 2479 Handle<JSFunction> constructor(isolate->native_context()->object_function(), 2480 isolate); 2481 DCHECK(constructor->has_initial_map()); 2482 Handle<Map> initial_map(constructor->initial_map(), isolate); 2483 Handle<Map> map = initial_map; 2484 2485 if (source_map->IsJSObjectMap() && source_map->GetInObjectProperties() != 2486 initial_map->GetInObjectProperties()) { 2487 int inobject_properties = source_map->GetInObjectProperties(); 2488 int instance_size = 2489 JSObject::kHeaderSize + kPointerSize * inobject_properties; 2490 int unused = source_map->UnusedInObjectProperties(); 2491 DCHECK(instance_size <= JSObject::kMaxInstanceSize); 2492 map = Map::CopyInitialMap(isolate, map, instance_size, inobject_properties, 2493 unused); 2494 } 2495 2496 if (flags & ObjectLiteral::kHasNullPrototype) { 2497 if (map.is_identical_to(initial_map)) { 2498 map = Map::Copy(isolate, map, "ObjectWithNullProto"); 2499 } 2500 Map::SetPrototype(isolate, map, isolate->factory()->null_value()); 2501 } 2502 2503 if (source->IsNullOrUndefined() || !source_map->NumberOfOwnDescriptors()) { 2504 return map; 2505 } 2506 2507 if (map.is_identical_to(initial_map)) { 2508 map = Map::Copy(isolate, map, "InitializeClonedDescriptors"); 2509 } 2510 2511 Handle<DescriptorArray> source_descriptors(source_map->instance_descriptors(), 2512 isolate); 2513 int size = source_map->NumberOfOwnDescriptors(); 2514 int slack = 0; 2515 Handle<DescriptorArray> descriptors = DescriptorArray::CopyForFastObjectClone( 2516 isolate, source_descriptors, size, slack); 2517 Handle<LayoutDescriptor> layout = 2518 LayoutDescriptor::New(isolate, map, descriptors, size); 2519 map->InitializeDescriptors(*descriptors, *layout); 2520 map->CopyUnusedPropertyFieldsAdjustedForInstanceSize(*source_map); 2521 2522 // Update bitfields 2523 map->set_may_have_interesting_symbols( 2524 source_map->may_have_interesting_symbols()); 2525 2526 return map; 2527 } 2528 2529 static MaybeHandle<JSObject> CloneObjectSlowPath(Isolate* isolate, 2530 Handle<HeapObject> source, 2531 int flags) { 2532 Handle<JSObject> new_object; 2533 if (flags & ObjectLiteral::kHasNullPrototype) { 2534 new_object = isolate->factory()->NewJSObjectWithNullProto(); 2535 } else { 2536 Handle<JSFunction> constructor(isolate->native_context()->object_function(), 2537 isolate); 2538 new_object = isolate->factory()->NewJSObject(constructor); 2539 } 2540 2541 if (source->IsNullOrUndefined()) { 2542 return new_object; 2543 } 2544 2545 MAYBE_RETURN(JSReceiver::SetOrCopyDataProperties(isolate, new_object, source, 2546 nullptr, false), 2547 MaybeHandle<JSObject>()); 2548 return new_object; 2549 } 2550 2551 RUNTIME_FUNCTION(Runtime_CloneObjectIC_Miss) { 2552 HandleScope scope(isolate); 2553 DCHECK_EQ(4, args.length()); 2554 Handle<HeapObject> source = args.at<HeapObject>(0); 2555 int flags = args.smi_at(1); 2556 2557 MigrateDeprecated(source); 2558 2559 FeedbackSlot slot = FeedbackVector::ToSlot(args.smi_at(2)); 2560 Handle<FeedbackVector> vector = args.at<FeedbackVector>(3); 2561 2562 FeedbackNexus nexus(vector, slot); 2563 Handle<Map> source_map(source->map(), isolate); 2564 2565 if (!CanFastCloneObject(source_map) || nexus.IsMegamorphic()) { 2566 // Migrate to slow mode if needed. 2567 nexus.ConfigureMegamorphic(); 2568 RETURN_RESULT_OR_FAILURE(isolate, 2569 CloneObjectSlowPath(isolate, source, flags)); 2570 } 2571 2572 Handle<Map> result_map = FastCloneObjectMap(isolate, source, flags); 2573 nexus.ConfigureCloneObject(source_map, result_map); 2574 2575 return *result_map; 2576 } 2577 2578 RUNTIME_FUNCTION(Runtime_CloneObjectIC_Slow) { 2579 HandleScope scope(isolate); 2580 DCHECK_EQ(2, args.length()); 2581 Handle<HeapObject> source = args.at<HeapObject>(0); 2582 int flags = args.smi_at(1); 2583 RETURN_RESULT_OR_FAILURE(isolate, 2584 CloneObjectSlowPath(isolate, source, flags)); 2585 } 2586 2587 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { 2588 Handle<JSObject> receiver = args.at<JSObject>(0); 2589 Handle<JSObject> holder = args.at<JSObject>(1); 2590 Handle<AccessorInfo> info = args.at<AccessorInfo>(2); 2591 Handle<Name> name = args.at<Name>(3); 2592 Handle<Object> value = args.at(4); 2593 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5); 2594 HandleScope scope(isolate); 2595 2596 if (V8_UNLIKELY(FLAG_runtime_stats)) { 2597 RETURN_RESULT_OR_FAILURE( 2598 isolate, Runtime::SetObjectProperty(isolate, receiver, name, value, 2599 language_mode)); 2600 } 2601 2602 DCHECK(info->IsCompatibleReceiver(*receiver)); 2603 2604 ShouldThrow should_throw = 2605 is_sloppy(language_mode) ? kDontThrow : kThrowOnError; 2606 PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder, 2607 should_throw); 2608 arguments.CallAccessorSetter(info, name, value); 2609 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2610 return *value; 2611 } 2612 2613 RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) { 2614 Handle<JSObject> receiver = args.at<JSObject>(0); 2615 Handle<JSObject> holder = args.at<JSObject>(1); 2616 Handle<AccessorInfo> info = args.at<AccessorInfo>(2); 2617 Handle<Name> name = args.at<Name>(3); 2618 HandleScope scope(isolate); 2619 2620 DCHECK(info->IsCompatibleReceiver(*receiver)); 2621 2622 PropertyCallbackArguments custom_args(isolate, info->data(), *receiver, 2623 *holder, kThrowOnError); 2624 Handle<Object> result = custom_args.CallAccessorGetter(info, name); 2625 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2626 if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value(); 2627 return *result; 2628 } 2629 2630 RUNTIME_FUNCTION(Runtime_LoadAccessorProperty) { 2631 HandleScope scope(isolate); 2632 DCHECK_EQ(args.length(), 3); 2633 Handle<JSObject> receiver = args.at<JSObject>(0); 2634 int handler_kind = args.smi_at(1); 2635 Handle<CallHandlerInfo> call_handler_info = args.at<CallHandlerInfo>(2); 2636 2637 Object* holder = *receiver; 2638 if (handler_kind == LoadHandler::kApiGetterHolderIsPrototype) { 2639 holder = receiver->map()->prototype(); 2640 } else { 2641 DCHECK_EQ(handler_kind, LoadHandler::kApiGetter); 2642 } 2643 2644 // Call the accessor without additional arguments. 2645 FunctionCallbackArguments custom(isolate, call_handler_info->data(), 2646 *receiver, holder, nullptr, nullptr, 0); 2647 Handle<Object> result_handle = custom.Call(*call_handler_info); 2648 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2649 if (result_handle.is_null()) return ReadOnlyRoots(isolate).undefined_value(); 2650 return *result_handle; 2651 } 2652 2653 /** 2654 * Loads a property with an interceptor performing post interceptor 2655 * lookup if interceptor failed. 2656 */ 2657 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { 2658 HandleScope scope(isolate); 2659 DCHECK_EQ(5, args.length()); 2660 Handle<Name> name = args.at<Name>(0); 2661 Handle<Object> receiver = args.at(1); 2662 Handle<JSObject> holder = args.at<JSObject>(2); 2663 2664 if (!receiver->IsJSReceiver()) { 2665 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2666 isolate, receiver, Object::ConvertReceiver(isolate, receiver)); 2667 } 2668 2669 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate); 2670 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, 2671 *holder, kDontThrow); 2672 Handle<Object> result = arguments.CallNamedGetter(interceptor, name); 2673 2674 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2675 2676 if (!result.is_null()) return *result; 2677 2678 LookupIterator it(receiver, name, holder); 2679 // Skip any lookup work until we hit the (possibly non-masking) interceptor. 2680 while (it.state() != LookupIterator::INTERCEPTOR || 2681 !it.GetHolder<JSObject>().is_identical_to(holder)) { 2682 DCHECK(it.state() != LookupIterator::ACCESS_CHECK || it.HasAccess()); 2683 it.Next(); 2684 } 2685 // Skip past the interceptor. 2686 it.Next(); 2687 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it)); 2688 2689 if (it.IsFound()) return *result; 2690 2691 Handle<Smi> slot = args.at<Smi>(3); 2692 Handle<FeedbackVector> vector = args.at<FeedbackVector>(4); 2693 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2694 FeedbackSlotKind slot_kind = vector->GetKind(vector_slot); 2695 // It could actually be any kind of load IC slot here but the predicate 2696 // handles all the cases properly. 2697 if (!LoadIC::ShouldThrowReferenceError(slot_kind)) { 2698 return ReadOnlyRoots(isolate).undefined_value(); 2699 } 2700 2701 // Throw a reference error. 2702 THROW_NEW_ERROR_RETURN_FAILURE( 2703 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name())); 2704 } 2705 2706 2707 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { 2708 HandleScope scope(isolate); 2709 DCHECK_EQ(5, args.length()); 2710 // Runtime functions don't follow the IC's calling convention. 2711 Handle<Object> value = args.at(0); 2712 Handle<Smi> slot = args.at<Smi>(1); 2713 Handle<FeedbackVector> vector = args.at<FeedbackVector>(2); 2714 Handle<JSObject> receiver = args.at<JSObject>(3); 2715 Handle<Name> name = args.at<Name>(4); 2716 FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value()); 2717 LanguageMode language_mode = vector->GetLanguageMode(vector_slot); 2718 2719 // TODO(ishell): Cache interceptor_holder in the store handler like we do 2720 // for LoadHandler::kInterceptor case. 2721 Handle<JSObject> interceptor_holder = receiver; 2722 if (receiver->IsJSGlobalProxy()) { 2723 FeedbackSlotKind kind = vector->GetKind(vector_slot); 2724 if (IsStoreGlobalICKind(kind)) { 2725 interceptor_holder = Handle<JSObject>::cast(isolate->global_object()); 2726 } 2727 } 2728 DCHECK(interceptor_holder->HasNamedInterceptor()); 2729 Handle<InterceptorInfo> interceptor(interceptor_holder->GetNamedInterceptor(), 2730 isolate); 2731 2732 DCHECK(!interceptor->non_masking()); 2733 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, 2734 *receiver, kDontThrow); 2735 2736 Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value); 2737 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2738 if (!result.is_null()) return *value; 2739 2740 LookupIterator it(receiver, name, receiver); 2741 // Skip past any access check on the receiver. 2742 if (it.state() == LookupIterator::ACCESS_CHECK) { 2743 DCHECK(it.HasAccess()); 2744 it.Next(); 2745 } 2746 // Skip past the interceptor on the receiver. 2747 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); 2748 it.Next(); 2749 2750 MAYBE_RETURN(Object::SetProperty(&it, value, language_mode, 2751 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED), 2752 ReadOnlyRoots(isolate).exception()); 2753 return *value; 2754 } 2755 2756 2757 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) { 2758 // TODO(verwaest): This should probably get the holder and receiver as input. 2759 HandleScope scope(isolate); 2760 Handle<JSObject> receiver = args.at<JSObject>(0); 2761 DCHECK_GE(args.smi_at(1), 0); 2762 uint32_t index = args.smi_at(1); 2763 2764 Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(), 2765 isolate); 2766 PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver, 2767 *receiver, kDontThrow); 2768 Handle<Object> result = arguments.CallIndexedGetter(interceptor, index); 2769 2770 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2771 2772 if (result.is_null()) { 2773 LookupIterator it(isolate, receiver, index, receiver); 2774 DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state()); 2775 it.Next(); 2776 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2777 Object::GetProperty(&it)); 2778 } 2779 2780 return *result; 2781 } 2782 } // namespace internal 2783 } // namespace v8 2784