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.h" 9 #include "src/arguments.h" 10 #include "src/base/bits.h" 11 #include "src/codegen.h" 12 #include "src/conversions.h" 13 #include "src/execution.h" 14 #include "src/frames-inl.h" 15 #include "src/ic/call-optimization.h" 16 #include "src/ic/handler-compiler.h" 17 #include "src/ic/ic-inl.h" 18 #include "src/ic/ic-compiler.h" 19 #include "src/ic/stub-cache.h" 20 #include "src/isolate-inl.h" 21 #include "src/macro-assembler.h" 22 #include "src/prototype.h" 23 #include "src/runtime/runtime.h" 24 25 namespace v8 { 26 namespace internal { 27 28 char IC::TransitionMarkFromState(IC::State state) { 29 switch (state) { 30 case UNINITIALIZED: 31 return '0'; 32 case PREMONOMORPHIC: 33 return '.'; 34 case MONOMORPHIC: 35 return '1'; 36 case PROTOTYPE_FAILURE: 37 return '^'; 38 case POLYMORPHIC: 39 return 'P'; 40 case MEGAMORPHIC: 41 return 'N'; 42 case GENERIC: 43 return 'G'; 44 45 // We never see the debugger states here, because the state is 46 // computed from the original code - not the patched code. Let 47 // these cases fall through to the unreachable code below. 48 case DEBUG_STUB: 49 break; 50 } 51 UNREACHABLE(); 52 return 0; 53 } 54 55 56 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { 57 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW"; 58 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { 59 return ".IGNORE_OOB"; 60 } 61 if (IsGrowStoreMode(mode)) return ".GROW"; 62 return ""; 63 } 64 65 66 #ifdef DEBUG 67 68 #define TRACE_GENERIC_IC(isolate, type, reason) \ 69 do { \ 70 if (FLAG_trace_ic) { \ 71 PrintF("[%s patching generic stub in ", type); \ 72 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ 73 PrintF(" (%s)]\n", reason); \ 74 } \ 75 } while (false) 76 77 #else 78 79 #define TRACE_GENERIC_IC(isolate, type, reason) \ 80 do { \ 81 if (FLAG_trace_ic) { \ 82 PrintF("[%s patching generic stub in ", type); \ 83 PrintF("(see below) (%s)]\n", reason); \ 84 } \ 85 } while (false) 86 87 #endif // DEBUG 88 89 90 void IC::TraceIC(const char* type, Handle<Object> name) { 91 if (FLAG_trace_ic) { 92 if (AddressIsDeoptimizedCode()) return; 93 State new_state = 94 UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state(); 95 TraceIC(type, name, state(), new_state); 96 } 97 } 98 99 100 void IC::TraceIC(const char* type, Handle<Object> name, State old_state, 101 State new_state) { 102 if (FLAG_trace_ic) { 103 Code* new_target = raw_target(); 104 PrintF("[%s%s in ", new_target->is_keyed_stub() ? "Keyed" : "", type); 105 106 // TODO(jkummerow): Add support for "apply". The logic is roughly: 107 // marker = [fp_ + kMarkerOffset]; 108 // if marker is smi and marker.value == INTERNAL and 109 // the frame's code == builtin(Builtins::kFunctionApply): 110 // then print "apply from" and advance one frame 111 112 Object* maybe_function = 113 Memory::Object_at(fp_ + JavaScriptFrameConstants::kFunctionOffset); 114 if (maybe_function->IsJSFunction()) { 115 JSFunction* function = JSFunction::cast(maybe_function); 116 JavaScriptFrame::PrintFunctionAndOffset(function, function->code(), pc(), 117 stdout, true); 118 } 119 120 const char* modifier = ""; 121 if (new_target->kind() == Code::KEYED_STORE_IC) { 122 KeyedAccessStoreMode mode = 123 casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode(); 124 modifier = GetTransitionMarkModifier(mode); 125 } 126 PrintF(" (%c->%c%s) ", TransitionMarkFromState(old_state), 127 TransitionMarkFromState(new_state), modifier); 128 #ifdef OBJECT_PRINT 129 OFStream os(stdout); 130 name->Print(os); 131 #else 132 name->ShortPrint(stdout); 133 #endif 134 PrintF("]\n"); 135 } 136 } 137 138 139 #define TRACE_IC(type, name) TraceIC(type, name) 140 141 142 IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus) 143 : isolate_(isolate), 144 target_set_(false), 145 vector_set_(false), 146 target_maps_set_(false), 147 nexus_(nexus) { 148 // To improve the performance of the (much used) IC code, we unfold a few 149 // levels of the stack frame iteration code. This yields a ~35% speedup when 150 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. 151 const Address entry = Isolate::c_entry_fp(isolate->thread_local_top()); 152 Address* constant_pool = NULL; 153 if (FLAG_enable_embedded_constant_pool) { 154 constant_pool = reinterpret_cast<Address*>( 155 entry + ExitFrameConstants::kConstantPoolOffset); 156 } 157 Address* pc_address = 158 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); 159 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 160 // If there's another JavaScript frame on the stack or a 161 // StubFailureTrampoline, we need to look one frame further down the stack to 162 // find the frame pointer and the return address stack slot. 163 if (depth == EXTRA_CALL_FRAME) { 164 if (FLAG_enable_embedded_constant_pool) { 165 constant_pool = reinterpret_cast<Address*>( 166 fp + StandardFrameConstants::kConstantPoolOffset); 167 } 168 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; 169 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); 170 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); 171 } 172 #ifdef DEBUG 173 StackFrameIterator it(isolate); 174 for (int i = 0; i < depth + 1; i++) it.Advance(); 175 StackFrame* frame = it.frame(); 176 DCHECK(fp == frame->fp() && pc_address == frame->pc_address()); 177 #endif 178 fp_ = fp; 179 if (FLAG_enable_embedded_constant_pool) { 180 constant_pool_address_ = constant_pool; 181 } 182 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); 183 target_ = handle(raw_target(), isolate); 184 kind_ = target_->kind(); 185 state_ = UseVector() ? nexus->StateFromFeedback() : target_->ic_state(); 186 old_state_ = state_; 187 extra_ic_state_ = target_->extra_ic_state(); 188 } 189 190 191 SharedFunctionInfo* IC::GetSharedFunctionInfo() const { 192 // Compute the JavaScript frame for the frame pointer of this IC 193 // structure. We need this to be able to find the function 194 // corresponding to the frame. 195 StackFrameIterator it(isolate()); 196 while (it.frame()->fp() != this->fp()) it.Advance(); 197 if (FLAG_ignition && it.frame()->type() == StackFrame::STUB) { 198 // Advance over bytecode handler frame. 199 // TODO(rmcilroy): Remove this once bytecode handlers don't need a frame. 200 it.Advance(); 201 } 202 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 203 // Find the function on the stack and both the active code for the 204 // function and the original code. 205 JSFunction* function = frame->function(); 206 return function->shared(); 207 } 208 209 210 Code* IC::GetCode() const { 211 HandleScope scope(isolate()); 212 Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate()); 213 Code* code = shared->code(); 214 return code; 215 } 216 217 218 bool IC::AddressIsOptimizedCode() const { 219 Code* host = 220 isolate()->inner_pointer_to_code_cache()->GetCacheEntry(address())->code; 221 return host->kind() == Code::OPTIMIZED_FUNCTION; 222 } 223 224 225 static void LookupForRead(LookupIterator* it) { 226 for (; it->IsFound(); it->Next()) { 227 switch (it->state()) { 228 case LookupIterator::NOT_FOUND: 229 case LookupIterator::TRANSITION: 230 UNREACHABLE(); 231 case LookupIterator::JSPROXY: 232 return; 233 case LookupIterator::INTERCEPTOR: { 234 // If there is a getter, return; otherwise loop to perform the lookup. 235 Handle<JSObject> holder = it->GetHolder<JSObject>(); 236 if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) { 237 return; 238 } 239 break; 240 } 241 case LookupIterator::ACCESS_CHECK: 242 // PropertyHandlerCompiler::CheckPrototypes() knows how to emit 243 // access checks for global proxies. 244 if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) { 245 break; 246 } 247 return; 248 case LookupIterator::ACCESSOR: 249 case LookupIterator::INTEGER_INDEXED_EXOTIC: 250 case LookupIterator::DATA: 251 return; 252 } 253 } 254 } 255 256 257 bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver, 258 Handle<String> name) { 259 if (!IsNameCompatibleWithPrototypeFailure(name)) return false; 260 if (UseVector()) { 261 maybe_handler_ = nexus()->FindHandlerForMap(receiver_map()); 262 } else { 263 maybe_handler_ = target()->FindHandlerForMap(*receiver_map()); 264 } 265 266 // The current map wasn't handled yet. There's no reason to stay monomorphic, 267 // *unless* we're moving from a deprecated map to its replacement, or 268 // to a more general elements kind. 269 // TODO(verwaest): Check if the current map is actually what the old map 270 // would transition to. 271 if (maybe_handler_.is_null()) { 272 if (!receiver_map()->IsJSObjectMap()) return false; 273 Map* first_map = FirstTargetMap(); 274 if (first_map == NULL) return false; 275 Handle<Map> old_map(first_map); 276 if (old_map->is_deprecated()) return true; 277 return IsMoreGeneralElementsKindTransition(old_map->elements_kind(), 278 receiver_map()->elements_kind()); 279 } 280 281 CacheHolderFlag flag; 282 Handle<Map> ic_holder_map(GetICCacheHolder(receiver_map(), isolate(), &flag)); 283 284 DCHECK(flag != kCacheOnReceiver || receiver->IsJSObject()); 285 DCHECK(flag != kCacheOnPrototype || !receiver->IsJSReceiver()); 286 DCHECK(flag != kCacheOnPrototypeReceiverIsDictionary); 287 288 if (state() == MONOMORPHIC) { 289 int index = ic_holder_map->IndexInCodeCache(*name, *target()); 290 if (index >= 0) { 291 ic_holder_map->RemoveFromCodeCache(*name, *target(), index); 292 } 293 } 294 295 if (receiver->IsJSGlobalObject()) { 296 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver); 297 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 298 if (it.state() == LookupIterator::ACCESS_CHECK) return false; 299 if (!it.IsFound()) return false; 300 return it.property_details().cell_type() == PropertyCellType::kConstant; 301 } 302 303 return true; 304 } 305 306 307 bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) { 308 if (target()->is_keyed_stub()) { 309 // Determine whether the failure is due to a name failure. 310 if (!name->IsName()) return false; 311 Name* stub_name = 312 UseVector() ? nexus()->FindFirstName() : target()->FindFirstName(); 313 if (*name != stub_name) return false; 314 } 315 316 return true; 317 } 318 319 320 void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) { 321 update_receiver_map(receiver); 322 if (!name->IsString()) return; 323 if (state() != MONOMORPHIC && state() != POLYMORPHIC) return; 324 if (receiver->IsUndefined() || receiver->IsNull()) return; 325 326 // Remove the target from the code cache if it became invalid 327 // because of changes in the prototype chain to avoid hitting it 328 // again. 329 if (TryRemoveInvalidPrototypeDependentStub(receiver, 330 Handle<String>::cast(name))) { 331 MarkPrototypeFailure(name); 332 return; 333 } 334 } 335 336 337 MaybeHandle<Object> IC::TypeError(MessageTemplate::Template index, 338 Handle<Object> object, Handle<Object> key) { 339 HandleScope scope(isolate()); 340 THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object); 341 } 342 343 344 MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) { 345 HandleScope scope(isolate()); 346 THROW_NEW_ERROR( 347 isolate(), NewReferenceError(MessageTemplate::kNotDefined, name), Object); 348 } 349 350 351 static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state, 352 int* polymorphic_delta, 353 int* generic_delta) { 354 switch (old_state) { 355 case UNINITIALIZED: 356 case PREMONOMORPHIC: 357 if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break; 358 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) { 359 *polymorphic_delta = 1; 360 } else if (new_state == MEGAMORPHIC || new_state == GENERIC) { 361 *generic_delta = 1; 362 } 363 break; 364 case MONOMORPHIC: 365 case POLYMORPHIC: 366 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break; 367 *polymorphic_delta = -1; 368 if (new_state == MEGAMORPHIC || new_state == GENERIC) { 369 *generic_delta = 1; 370 } 371 break; 372 case MEGAMORPHIC: 373 case GENERIC: 374 if (new_state == MEGAMORPHIC || new_state == GENERIC) break; 375 *generic_delta = -1; 376 if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) { 377 *polymorphic_delta = 1; 378 } 379 break; 380 case PROTOTYPE_FAILURE: 381 case DEBUG_STUB: 382 UNREACHABLE(); 383 } 384 } 385 386 387 void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, 388 State old_state, State new_state, 389 bool target_remains_ic_stub) { 390 Code* host = 391 isolate->inner_pointer_to_code_cache()->GetCacheEntry(address)->code; 392 if (host->kind() != Code::FUNCTION) return; 393 394 if (FLAG_type_info_threshold > 0 && target_remains_ic_stub && 395 // Not all Code objects have TypeFeedbackInfo. 396 host->type_feedback_info()->IsTypeFeedbackInfo()) { 397 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic. 398 int generic_delta = 0; // "Generic" here includes megamorphic. 399 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta, 400 &generic_delta); 401 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); 402 info->change_ic_with_type_info_count(polymorphic_delta); 403 info->change_ic_generic_count(generic_delta); 404 } 405 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { 406 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); 407 info->change_own_type_change_checksum(); 408 } 409 host->set_profiler_ticks(0); 410 isolate->runtime_profiler()->NotifyICChanged(); 411 // TODO(2029): When an optimized function is patched, it would 412 // be nice to propagate the corresponding type information to its 413 // unoptimized version for the benefit of later inlining. 414 } 415 416 417 // static 418 void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) { 419 if (host->kind() != Code::FUNCTION) return; 420 421 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); 422 info->change_own_type_change_checksum(); 423 host->set_profiler_ticks(0); 424 isolate->runtime_profiler()->NotifyICChanged(); 425 // TODO(2029): When an optimized function is patched, it would 426 // be nice to propagate the corresponding type information to its 427 // unoptimized version for the benefit of later inlining. 428 } 429 430 431 void IC::PostPatching(Address address, Code* target, Code* old_target) { 432 // Type vector based ICs update these statistics at a different time because 433 // they don't always patch on state change. 434 if (ICUseVector(target->kind())) return; 435 436 Isolate* isolate = target->GetHeap()->isolate(); 437 State old_state = UNINITIALIZED; 438 State new_state = UNINITIALIZED; 439 bool target_remains_ic_stub = false; 440 if (old_target->is_inline_cache_stub() && target->is_inline_cache_stub()) { 441 old_state = old_target->ic_state(); 442 new_state = target->ic_state(); 443 target_remains_ic_stub = true; 444 } 445 446 OnTypeFeedbackChanged(isolate, address, old_state, new_state, 447 target_remains_ic_stub); 448 } 449 450 451 void IC::Clear(Isolate* isolate, Address address, Address constant_pool) { 452 Code* target = GetTargetAtAddress(address, constant_pool); 453 454 // Don't clear debug break inline cache as it will remove the break point. 455 if (target->is_debug_stub()) return; 456 457 switch (target->kind()) { 458 case Code::LOAD_IC: 459 case Code::KEYED_LOAD_IC: 460 case Code::STORE_IC: 461 case Code::KEYED_STORE_IC: 462 return; 463 case Code::COMPARE_IC: 464 return CompareIC::Clear(isolate, address, target, constant_pool); 465 case Code::COMPARE_NIL_IC: 466 return CompareNilIC::Clear(address, target, constant_pool); 467 case Code::CALL_IC: // CallICs are vector-based and cleared differently. 468 case Code::BINARY_OP_IC: 469 case Code::TO_BOOLEAN_IC: 470 // Clearing these is tricky and does not 471 // make any performance difference. 472 return; 473 default: 474 UNREACHABLE(); 475 } 476 } 477 478 479 void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) { 480 if (IsCleared(nexus)) return; 481 // Make sure to also clear the map used in inline fast cases. If we 482 // do not clear these maps, cached code can keep objects alive 483 // through the embedded maps. 484 nexus->ConfigurePremonomorphic(); 485 OnTypeFeedbackChanged(isolate, host); 486 } 487 488 489 void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) { 490 // Determine our state. 491 Object* feedback = nexus->vector()->Get(nexus->slot()); 492 State state = nexus->StateFromFeedback(); 493 494 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) { 495 nexus->ConfigureUninitialized(); 496 // The change in state must be processed. 497 OnTypeFeedbackChanged(isolate, host); 498 } 499 } 500 501 502 void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) { 503 if (IsCleared(nexus)) return; 504 nexus->ConfigurePremonomorphic(); 505 OnTypeFeedbackChanged(isolate, host); 506 } 507 508 509 void StoreIC::Clear(Isolate* isolate, Address address, Code* target, 510 Address constant_pool) { 511 if (IsCleared(target)) return; 512 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::STORE_IC, 513 target->extra_ic_state()); 514 SetTargetAtAddress(address, code, constant_pool); 515 } 516 517 518 void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) { 519 if (IsCleared(nexus)) return; 520 nexus->ConfigurePremonomorphic(); 521 OnTypeFeedbackChanged(isolate, host); 522 } 523 524 525 void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target, 526 Address constant_pool) { 527 if (IsCleared(target)) return; 528 Handle<Code> code = pre_monomorphic_stub( 529 isolate, StoreICState::GetLanguageMode(target->extra_ic_state())); 530 SetTargetAtAddress(address, *code, constant_pool); 531 } 532 533 534 void KeyedStoreIC::Clear(Isolate* isolate, Code* host, 535 KeyedStoreICNexus* nexus) { 536 if (IsCleared(nexus)) return; 537 nexus->ConfigurePremonomorphic(); 538 OnTypeFeedbackChanged(isolate, host); 539 } 540 541 542 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, 543 Address constant_pool) { 544 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); 545 CompareICStub stub(target->stub_key(), isolate); 546 // Only clear CompareICs that can retain objects. 547 if (stub.state() != CompareICState::KNOWN_RECEIVER) return; 548 SetTargetAtAddress(address, 549 GetRawUninitialized(isolate, stub.op(), stub.strength()), 550 constant_pool); 551 PatchInlinedSmiCode(isolate, address, DISABLE_INLINED_SMI_CHECK); 552 } 553 554 555 // static 556 Handle<Code> KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate, 557 ExtraICState extra_state) { 558 if (FLAG_compiled_keyed_generic_loads) { 559 return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode(); 560 } else { 561 return is_strong(LoadICState::GetLanguageMode(extra_state)) 562 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong() 563 : isolate->builtins()->KeyedLoadIC_Megamorphic(); 564 } 565 } 566 567 568 static bool MigrateDeprecated(Handle<Object> object) { 569 if (!object->IsJSObject()) return false; 570 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 571 if (!receiver->map()->is_deprecated()) return false; 572 JSObject::MigrateInstance(Handle<JSObject>::cast(object)); 573 return true; 574 } 575 576 577 void IC::ConfigureVectorState(IC::State new_state) { 578 DCHECK(UseVector()); 579 if (new_state == PREMONOMORPHIC) { 580 nexus()->ConfigurePremonomorphic(); 581 } else if (new_state == MEGAMORPHIC) { 582 nexus()->ConfigureMegamorphic(); 583 } else { 584 UNREACHABLE(); 585 } 586 587 vector_set_ = true; 588 OnTypeFeedbackChanged(isolate(), get_host()); 589 } 590 591 592 void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, 593 Handle<Code> handler) { 594 DCHECK(UseVector()); 595 if (kind() == Code::LOAD_IC) { 596 LoadICNexus* nexus = casted_nexus<LoadICNexus>(); 597 nexus->ConfigureMonomorphic(map, handler); 598 } else if (kind() == Code::KEYED_LOAD_IC) { 599 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); 600 nexus->ConfigureMonomorphic(name, map, handler); 601 } else if (kind() == Code::STORE_IC) { 602 StoreICNexus* nexus = casted_nexus<StoreICNexus>(); 603 nexus->ConfigureMonomorphic(map, handler); 604 } else { 605 DCHECK(kind() == Code::KEYED_STORE_IC); 606 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); 607 nexus->ConfigureMonomorphic(name, map, handler); 608 } 609 610 vector_set_ = true; 611 OnTypeFeedbackChanged(isolate(), get_host()); 612 } 613 614 615 void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps, 616 CodeHandleList* handlers) { 617 DCHECK(UseVector()); 618 if (kind() == Code::LOAD_IC) { 619 LoadICNexus* nexus = casted_nexus<LoadICNexus>(); 620 nexus->ConfigurePolymorphic(maps, handlers); 621 } else if (kind() == Code::KEYED_LOAD_IC) { 622 KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); 623 nexus->ConfigurePolymorphic(name, maps, handlers); 624 } else if (kind() == Code::STORE_IC) { 625 StoreICNexus* nexus = casted_nexus<StoreICNexus>(); 626 nexus->ConfigurePolymorphic(maps, handlers); 627 } else { 628 DCHECK(kind() == Code::KEYED_STORE_IC); 629 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); 630 nexus->ConfigurePolymorphic(name, maps, handlers); 631 } 632 633 vector_set_ = true; 634 OnTypeFeedbackChanged(isolate(), get_host()); 635 } 636 637 638 void IC::ConfigureVectorState(MapHandleList* maps, 639 MapHandleList* transitioned_maps, 640 CodeHandleList* handlers) { 641 DCHECK(UseVector()); 642 DCHECK(kind() == Code::KEYED_STORE_IC); 643 KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>(); 644 nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers); 645 646 vector_set_ = true; 647 OnTypeFeedbackChanged(isolate(), get_host()); 648 } 649 650 651 MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { 652 // If the object is undefined or null it's illegal to try to get any 653 // of its properties; throw a TypeError in that case. 654 if (object->IsUndefined() || object->IsNull()) { 655 return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name); 656 } 657 658 // Check if the name is trivially convertible to an index and get 659 // the element or char if so. 660 uint32_t index; 661 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { 662 // Rewrite to the generic keyed load stub. 663 if (FLAG_use_ic) { 664 DCHECK(UseVector()); 665 ConfigureVectorState(MEGAMORPHIC); 666 TRACE_IC("LoadIC", name); 667 TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index"); 668 } 669 Handle<Object> result; 670 ASSIGN_RETURN_ON_EXCEPTION( 671 isolate(), result, 672 Object::GetElement(isolate(), object, index, language_mode()), Object); 673 return result; 674 } 675 676 bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic; 677 678 if (object->IsJSGlobalObject() && name->IsString()) { 679 // Look up in script context table. 680 Handle<String> str_name = Handle<String>::cast(name); 681 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object); 682 Handle<ScriptContextTable> script_contexts( 683 global->native_context()->script_context_table()); 684 685 ScriptContextTable::LookupResult lookup_result; 686 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { 687 Handle<Object> result = 688 FixedArray::get(ScriptContextTable::GetContext( 689 script_contexts, lookup_result.context_index), 690 lookup_result.slot_index); 691 if (*result == *isolate()->factory()->the_hole_value()) { 692 // Do not install stubs and stay pre-monomorphic for 693 // uninitialized accesses. 694 return ReferenceError(name); 695 } 696 697 if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) { 698 LoadScriptContextFieldStub stub(isolate(), &lookup_result); 699 PatchCache(name, stub.GetCode()); 700 } 701 return result; 702 } 703 } 704 705 // Named lookup in the object. 706 LookupIterator it(object, name); 707 LookupForRead(&it); 708 709 if (it.IsFound() || !ShouldThrowReferenceError(object)) { 710 // Update inline cache and stub cache. 711 if (use_ic) UpdateCaches(&it); 712 713 // Get the property. 714 Handle<Object> result; 715 716 ASSIGN_RETURN_ON_EXCEPTION( 717 isolate(), result, Object::GetProperty(&it, language_mode()), Object); 718 if (it.IsFound()) { 719 return result; 720 } else if (!ShouldThrowReferenceError(object)) { 721 LOG(isolate(), SuspectReadEvent(*name, *object)); 722 return result; 723 } 724 } 725 return ReferenceError(name); 726 } 727 728 729 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, 730 Handle<Map> new_receiver_map) { 731 DCHECK(!new_receiver_map.is_null()); 732 for (int current = 0; current < receiver_maps->length(); ++current) { 733 if (!receiver_maps->at(current).is_null() && 734 receiver_maps->at(current).is_identical_to(new_receiver_map)) { 735 return false; 736 } 737 } 738 receiver_maps->Add(new_receiver_map); 739 return true; 740 } 741 742 743 bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) { 744 if (!code->is_handler()) return false; 745 if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false; 746 Handle<Map> map = receiver_map(); 747 MapHandleList maps; 748 CodeHandleList handlers; 749 750 TargetMaps(&maps); 751 int number_of_maps = maps.length(); 752 int deprecated_maps = 0; 753 int handler_to_overwrite = -1; 754 755 for (int i = 0; i < number_of_maps; i++) { 756 Handle<Map> current_map = maps.at(i); 757 if (current_map->is_deprecated()) { 758 // Filter out deprecated maps to ensure their instances get migrated. 759 ++deprecated_maps; 760 } else if (map.is_identical_to(current_map)) { 761 // If the receiver type is already in the polymorphic IC, this indicates 762 // there was a prototoype chain failure. In that case, just overwrite the 763 // handler. 764 handler_to_overwrite = i; 765 } else if (handler_to_overwrite == -1 && 766 IsTransitionOfMonomorphicTarget(*current_map, *map)) { 767 handler_to_overwrite = i; 768 } 769 } 770 771 int number_of_valid_maps = 772 number_of_maps - deprecated_maps - (handler_to_overwrite != -1); 773 774 if (number_of_valid_maps >= 4) return false; 775 if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) { 776 return false; 777 } 778 if (UseVector()) { 779 if (!nexus()->FindHandlers(&handlers, maps.length())) return false; 780 } else { 781 if (!target()->FindHandlers(&handlers, maps.length())) return false; 782 } 783 784 number_of_valid_maps++; 785 if (number_of_valid_maps > 1 && target()->is_keyed_stub()) return false; 786 Handle<Code> ic; 787 if (number_of_valid_maps == 1) { 788 ConfigureVectorState(name, receiver_map(), code); 789 } else { 790 if (handler_to_overwrite >= 0) { 791 handlers.Set(handler_to_overwrite, code); 792 if (!map.is_identical_to(maps.at(handler_to_overwrite))) { 793 maps.Set(handler_to_overwrite, map); 794 } 795 } else { 796 maps.Add(map); 797 handlers.Add(code); 798 } 799 800 ConfigureVectorState(name, &maps, &handlers); 801 } 802 803 if (!UseVector()) set_target(*ic); 804 return true; 805 } 806 807 808 void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) { 809 DCHECK(handler->is_handler()); 810 ConfigureVectorState(name, receiver_map(), handler); 811 } 812 813 814 void IC::CopyICToMegamorphicCache(Handle<Name> name) { 815 MapHandleList maps; 816 CodeHandleList handlers; 817 TargetMaps(&maps); 818 if (!target()->FindHandlers(&handlers, maps.length())) return; 819 for (int i = 0; i < maps.length(); i++) { 820 UpdateMegamorphicCache(*maps.at(i), *name, *handlers.at(i)); 821 } 822 } 823 824 825 bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { 826 if (source_map == NULL) return true; 827 if (target_map == NULL) return false; 828 ElementsKind target_elements_kind = target_map->elements_kind(); 829 bool more_general_transition = IsMoreGeneralElementsKindTransition( 830 source_map->elements_kind(), target_elements_kind); 831 Map* transitioned_map = 832 more_general_transition 833 ? source_map->LookupElementsTransitionMap(target_elements_kind) 834 : NULL; 835 836 return transitioned_map == target_map; 837 } 838 839 840 void IC::PatchCache(Handle<Name> name, Handle<Code> code) { 841 switch (state()) { 842 case UNINITIALIZED: 843 case PREMONOMORPHIC: 844 UpdateMonomorphicIC(code, name); 845 break; 846 case PROTOTYPE_FAILURE: 847 case MONOMORPHIC: 848 case POLYMORPHIC: 849 if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) { 850 if (UpdatePolymorphicIC(name, code)) break; 851 // For keyed stubs, we can't know whether old handlers were for the 852 // same key. 853 CopyICToMegamorphicCache(name); 854 } 855 if (UseVector()) { 856 ConfigureVectorState(MEGAMORPHIC); 857 } else { 858 set_target(*megamorphic_stub()); 859 } 860 // Fall through. 861 case MEGAMORPHIC: 862 UpdateMegamorphicCache(*receiver_map(), *name, *code); 863 // Indicate that we've handled this case. 864 if (UseVector()) { 865 vector_set_ = true; 866 } else { 867 target_set_ = true; 868 } 869 break; 870 case DEBUG_STUB: 871 break; 872 case GENERIC: 873 UNREACHABLE(); 874 break; 875 } 876 } 877 878 879 Handle<Code> LoadIC::initialize_stub(Isolate* isolate, 880 ExtraICState extra_state) { 881 return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode(); 882 } 883 884 885 Handle<Code> LoadIC::initialize_stub_in_optimized_code( 886 Isolate* isolate, ExtraICState extra_state, State initialization_state) { 887 return LoadICStub(isolate, LoadICState(extra_state)).GetCode(); 888 } 889 890 891 Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate, 892 ExtraICState extra_state) { 893 return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode(); 894 } 895 896 897 Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code( 898 Isolate* isolate, State initialization_state, ExtraICState extra_state) { 899 if (initialization_state != MEGAMORPHIC) { 900 return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode(); 901 } 902 return is_strong(LoadICState::GetLanguageMode(extra_state)) 903 ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong() 904 : isolate->builtins()->KeyedLoadIC_Megamorphic(); 905 } 906 907 908 static Handle<Code> KeyedStoreICInitializeStubHelper( 909 Isolate* isolate, LanguageMode language_mode, 910 InlineCacheState initialization_state) { 911 switch (initialization_state) { 912 case UNINITIALIZED: 913 return is_strict(language_mode) 914 ? isolate->builtins()->KeyedStoreIC_Initialize_Strict() 915 : isolate->builtins()->KeyedStoreIC_Initialize(); 916 case PREMONOMORPHIC: 917 return is_strict(language_mode) 918 ? isolate->builtins()->KeyedStoreIC_PreMonomorphic_Strict() 919 : isolate->builtins()->KeyedStoreIC_PreMonomorphic(); 920 case MEGAMORPHIC: 921 return is_strict(language_mode) 922 ? isolate->builtins()->KeyedStoreIC_Megamorphic_Strict() 923 : isolate->builtins()->KeyedStoreIC_Megamorphic(); 924 default: 925 UNREACHABLE(); 926 } 927 return Handle<Code>(); 928 } 929 930 931 Handle<Code> KeyedStoreIC::initialize_stub(Isolate* isolate, 932 LanguageMode language_mode, 933 State initialization_state) { 934 if (initialization_state != MEGAMORPHIC) { 935 VectorKeyedStoreICTrampolineStub stub(isolate, StoreICState(language_mode)); 936 return stub.GetCode(); 937 } 938 939 return KeyedStoreICInitializeStubHelper(isolate, language_mode, 940 initialization_state); 941 } 942 943 944 Handle<Code> KeyedStoreIC::initialize_stub_in_optimized_code( 945 Isolate* isolate, LanguageMode language_mode, State initialization_state) { 946 if (initialization_state != MEGAMORPHIC) { 947 VectorKeyedStoreICStub stub(isolate, StoreICState(language_mode)); 948 return stub.GetCode(); 949 } 950 951 return KeyedStoreICInitializeStubHelper(isolate, language_mode, 952 initialization_state); 953 } 954 955 956 Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate, 957 ExtraICState extra_state) { 958 LanguageMode mode = StoreICState::GetLanguageMode(extra_state); 959 return KeyedStoreICInitializeStubHelper(isolate, mode, MEGAMORPHIC); 960 } 961 962 963 Handle<Code> LoadIC::megamorphic_stub() { 964 DCHECK_EQ(Code::KEYED_LOAD_IC, kind()); 965 return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state()); 966 } 967 968 969 Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) { 970 LoadFieldStub stub(isolate(), index); 971 return stub.GetCode(); 972 } 973 974 975 bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) { 976 DCHECK(lookup->state() == LookupIterator::ACCESSOR); 977 Isolate* isolate = lookup->isolate(); 978 Handle<Object> accessors = lookup->GetAccessors(); 979 if (accessors->IsExecutableAccessorInfo()) { 980 Handle<ExecutableAccessorInfo> info = 981 Handle<ExecutableAccessorInfo>::cast(accessors); 982 if (info->getter() != NULL && 983 !ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate, info, 984 receiver_map)) { 985 return false; 986 } 987 } else if (accessors->IsAccessorPair()) { 988 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), 989 isolate); 990 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 991 Handle<Object> receiver = lookup->GetReceiver(); 992 if (getter->IsJSFunction() && holder->HasFastProperties()) { 993 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); 994 if (receiver->IsJSObject() || function->shared()->IsBuiltin() || 995 !is_sloppy(function->shared()->language_mode())) { 996 CallOptimization call_optimization(function); 997 if (call_optimization.is_simple_api_call() && 998 !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) { 999 return false; 1000 } 1001 } 1002 } 1003 } 1004 return true; 1005 } 1006 1007 1008 void LoadIC::UpdateCaches(LookupIterator* lookup) { 1009 if (state() == UNINITIALIZED) { 1010 // This is the first time we execute this inline cache. Set the target to 1011 // the pre monomorphic stub to delay setting the monomorphic state. 1012 ConfigureVectorState(PREMONOMORPHIC); 1013 TRACE_IC("LoadIC", lookup->name()); 1014 return; 1015 } 1016 1017 Handle<Code> code; 1018 if (lookup->state() == LookupIterator::JSPROXY || 1019 lookup->state() == LookupIterator::ACCESS_CHECK) { 1020 code = slow_stub(); 1021 } else if (!lookup->IsFound()) { 1022 if (kind() == Code::LOAD_IC && !is_strong(language_mode())) { 1023 code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), 1024 receiver_map()); 1025 // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. 1026 if (code.is_null()) code = slow_stub(); 1027 } else { 1028 code = slow_stub(); 1029 } 1030 } else { 1031 if (lookup->state() == LookupIterator::ACCESSOR) { 1032 if (!IsCompatibleReceiver(lookup, receiver_map())) { 1033 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); 1034 code = slow_stub(); 1035 } 1036 } else if (lookup->state() == LookupIterator::INTERCEPTOR) { 1037 // Perform a lookup behind the interceptor. Copy the LookupIterator since 1038 // the original iterator will be used to fetch the value. 1039 LookupIterator it = *lookup; 1040 it.Next(); 1041 LookupForRead(&it); 1042 if (it.state() == LookupIterator::ACCESSOR && 1043 !IsCompatibleReceiver(&it, receiver_map())) { 1044 TRACE_GENERIC_IC(isolate(), "LoadIC", "incompatible receiver type"); 1045 code = slow_stub(); 1046 } 1047 } 1048 if (code.is_null()) code = ComputeHandler(lookup); 1049 } 1050 1051 PatchCache(lookup->name(), code); 1052 TRACE_IC("LoadIC", lookup->name()); 1053 } 1054 1055 1056 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { 1057 isolate()->stub_cache()->Set(name, map, code); 1058 } 1059 1060 1061 Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) { 1062 bool receiver_is_holder = 1063 lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>()); 1064 CacheHolderFlag flag; 1065 Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder( 1066 receiver_map(), receiver_is_holder, isolate(), &flag); 1067 1068 Handle<Code> code = PropertyHandlerCompiler::Find( 1069 lookup->name(), stub_holder_map, kind(), flag, 1070 lookup->is_dictionary_holder() ? Code::NORMAL : Code::FAST); 1071 // Use the cached value if it exists, and if it is different from the 1072 // handler that just missed. 1073 if (!code.is_null()) { 1074 if (!maybe_handler_.is_null() && 1075 !maybe_handler_.ToHandleChecked().is_identical_to(code)) { 1076 return code; 1077 } 1078 if (maybe_handler_.is_null()) { 1079 // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs. 1080 // In MEGAMORPHIC case, check if the handler in the megamorphic stub 1081 // cache (which just missed) is different from the cached handler. 1082 if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { 1083 Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); 1084 Code* megamorphic_cached_code = 1085 isolate()->stub_cache()->Get(*lookup->name(), map, code->flags()); 1086 if (megamorphic_cached_code != *code) return code; 1087 } else { 1088 return code; 1089 } 1090 } 1091 } 1092 1093 code = CompileHandler(lookup, value, flag); 1094 DCHECK(code->is_handler()); 1095 1096 // TODO(mvstanton): we'd only like to cache code on the map when it's custom 1097 // code compiled for this map, otherwise it's already cached in the global 1098 // code 1099 // cache. We are also guarding against installing code with flags that don't 1100 // match the desired CacheHolderFlag computed above, which would lead to 1101 // invalid lookups later. 1102 if (code->type() != Code::NORMAL && 1103 Code::ExtractCacheHolderFromFlags(code->flags()) == flag) { 1104 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); 1105 } 1106 1107 return code; 1108 } 1109 1110 1111 Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, 1112 Handle<Object> unused, 1113 CacheHolderFlag cache_holder) { 1114 Handle<Object> receiver = lookup->GetReceiver(); 1115 if (receiver->IsString() && 1116 Name::Equals(isolate()->factory()->length_string(), lookup->name())) { 1117 FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset); 1118 return SimpleFieldLoad(index); 1119 } 1120 1121 if (receiver->IsStringWrapper() && 1122 Name::Equals(isolate()->factory()->length_string(), lookup->name())) { 1123 StringLengthStub string_length_stub(isolate()); 1124 return string_length_stub.GetCode(); 1125 } 1126 1127 // Use specialized code for getting prototype of functions. 1128 if (receiver->IsJSFunction() && 1129 Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) && 1130 receiver->IsConstructor() && 1131 !Handle<JSFunction>::cast(receiver) 1132 ->map() 1133 ->has_non_instance_prototype()) { 1134 Handle<Code> stub; 1135 FunctionPrototypeStub function_prototype_stub(isolate()); 1136 return function_prototype_stub.GetCode(); 1137 } 1138 1139 Handle<Map> map = receiver_map(); 1140 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1141 bool receiver_is_holder = receiver.is_identical_to(holder); 1142 switch (lookup->state()) { 1143 case LookupIterator::INTERCEPTOR: { 1144 DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 1145 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); 1146 // Perform a lookup behind the interceptor. Copy the LookupIterator since 1147 // the original iterator will be used to fetch the value. 1148 LookupIterator it = *lookup; 1149 it.Next(); 1150 LookupForRead(&it); 1151 return compiler.CompileLoadInterceptor(&it); 1152 } 1153 1154 case LookupIterator::ACCESSOR: { 1155 // Use simple field loads for some well-known callback properties. 1156 // The method will only return true for absolute truths based on the 1157 // receiver maps. 1158 int object_offset; 1159 if (Accessors::IsJSObjectFieldAccessor(map, lookup->name(), 1160 &object_offset)) { 1161 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); 1162 return SimpleFieldLoad(index); 1163 } 1164 if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(), 1165 &object_offset)) { 1166 FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map); 1167 ArrayBufferViewLoadFieldStub stub(isolate(), index); 1168 return stub.GetCode(); 1169 } 1170 1171 Handle<Object> accessors = lookup->GetAccessors(); 1172 if (accessors->IsExecutableAccessorInfo()) { 1173 Handle<ExecutableAccessorInfo> info = 1174 Handle<ExecutableAccessorInfo>::cast(accessors); 1175 if (v8::ToCData<Address>(info->getter()) == 0) break; 1176 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info, 1177 map)) { 1178 // This case should be already handled in LoadIC::UpdateCaches. 1179 UNREACHABLE(); 1180 break; 1181 } 1182 if (!holder->HasFastProperties()) break; 1183 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); 1184 return compiler.CompileLoadCallback(lookup->name(), info); 1185 } 1186 if (accessors->IsAccessorPair()) { 1187 Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), 1188 isolate()); 1189 if (!getter->IsJSFunction()) break; 1190 if (!holder->HasFastProperties()) break; 1191 // When debugging we need to go the slow path to flood the accessor. 1192 if (GetSharedFunctionInfo()->HasDebugInfo()) break; 1193 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); 1194 if (!receiver->IsJSObject() && !function->shared()->IsBuiltin() && 1195 is_sloppy(function->shared()->language_mode())) { 1196 // Calling sloppy non-builtins with a value as the receiver 1197 // requires boxing. 1198 break; 1199 } 1200 CallOptimization call_optimization(function); 1201 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); 1202 if (call_optimization.is_simple_api_call()) { 1203 if (call_optimization.IsCompatibleReceiver(receiver, holder)) { 1204 return compiler.CompileLoadCallback( 1205 lookup->name(), call_optimization, lookup->GetAccessorIndex()); 1206 } else { 1207 // This case should be already handled in LoadIC::UpdateCaches. 1208 UNREACHABLE(); 1209 } 1210 } 1211 int expected_arguments = 1212 function->shared()->internal_formal_parameter_count(); 1213 return compiler.CompileLoadViaGetter( 1214 lookup->name(), lookup->GetAccessorIndex(), expected_arguments); 1215 } 1216 break; 1217 } 1218 1219 case LookupIterator::DATA: { 1220 if (lookup->is_dictionary_holder()) { 1221 if (kind() != Code::LOAD_IC) break; 1222 if (holder->IsJSGlobalObject()) { 1223 NamedLoadHandlerCompiler compiler(isolate(), map, holder, 1224 cache_holder); 1225 Handle<PropertyCell> cell = lookup->GetPropertyCell(); 1226 Handle<Code> code = compiler.CompileLoadGlobal( 1227 cell, lookup->name(), lookup->IsConfigurable()); 1228 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. 1229 CacheHolderFlag flag; 1230 Handle<Map> stub_holder_map = 1231 GetHandlerCacheHolder(map, receiver_is_holder, isolate(), &flag); 1232 Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); 1233 return code; 1234 } 1235 // There is only one shared stub for loading normalized 1236 // properties. It does not traverse the prototype chain, so the 1237 // property must be found in the object for the stub to be 1238 // applicable. 1239 if (!receiver_is_holder) break; 1240 return is_strong(language_mode()) 1241 ? isolate()->builtins()->LoadIC_Normal_Strong() 1242 : isolate()->builtins()->LoadIC_Normal(); 1243 } 1244 1245 // -------------- Fields -------------- 1246 if (lookup->property_details().type() == DATA) { 1247 FieldIndex field = lookup->GetFieldIndex(); 1248 if (receiver_is_holder) { 1249 return SimpleFieldLoad(field); 1250 } 1251 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); 1252 return compiler.CompileLoadField(lookup->name(), field); 1253 } 1254 1255 // -------------- Constant properties -------------- 1256 DCHECK(lookup->property_details().type() == DATA_CONSTANT); 1257 if (receiver_is_holder) { 1258 LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); 1259 return stub.GetCode(); 1260 } 1261 NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder); 1262 return compiler.CompileLoadConstant(lookup->name(), 1263 lookup->GetConstantIndex()); 1264 } 1265 1266 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1267 return slow_stub(); 1268 case LookupIterator::ACCESS_CHECK: 1269 case LookupIterator::JSPROXY: 1270 case LookupIterator::NOT_FOUND: 1271 case LookupIterator::TRANSITION: 1272 UNREACHABLE(); 1273 } 1274 1275 return slow_stub(); 1276 } 1277 1278 1279 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { 1280 // This helper implements a few common fast cases for converting 1281 // non-smi keys of keyed loads/stores to a smi or a string. 1282 if (key->IsHeapNumber()) { 1283 double value = Handle<HeapNumber>::cast(key)->value(); 1284 if (std::isnan(value)) { 1285 key = isolate->factory()->nan_string(); 1286 } else { 1287 int int_value = FastD2I(value); 1288 if (value == int_value && Smi::IsValid(int_value)) { 1289 key = handle(Smi::FromInt(int_value), isolate); 1290 } 1291 } 1292 } else if (key->IsUndefined()) { 1293 key = isolate->factory()->undefined_string(); 1294 } 1295 return key; 1296 } 1297 1298 1299 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) { 1300 Handle<Code> null_handle; 1301 Handle<Map> receiver_map(receiver->map(), isolate()); 1302 MapHandleList target_receiver_maps; 1303 TargetMaps(&target_receiver_maps); 1304 1305 1306 if (target_receiver_maps.length() == 0) { 1307 Handle<Code> handler = 1308 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( 1309 receiver_map, extra_ic_state()); 1310 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler); 1311 return null_handle; 1312 } 1313 1314 // The first time a receiver is seen that is a transitioned version of the 1315 // previous monomorphic receiver type, assume the new ElementsKind is the 1316 // monomorphic type. This benefits global arrays that only transition 1317 // once, and all call sites accessing them are faster if they remain 1318 // monomorphic. If this optimistic assumption is not true, the IC will 1319 // miss again and it will become polymorphic and support both the 1320 // untransitioned and transitioned maps. 1321 if (state() == MONOMORPHIC && !receiver->IsString() && 1322 IsMoreGeneralElementsKindTransition( 1323 target_receiver_maps.at(0)->elements_kind(), 1324 Handle<JSObject>::cast(receiver)->GetElementsKind())) { 1325 Handle<Code> handler = 1326 PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( 1327 receiver_map, extra_ic_state()); 1328 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler); 1329 return null_handle; 1330 } 1331 1332 DCHECK(state() != GENERIC); 1333 1334 // Determine the list of receiver maps that this call site has seen, 1335 // adding the map that was just encountered. 1336 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { 1337 // If the miss wasn't due to an unseen map, a polymorphic stub 1338 // won't help, use the generic stub. 1339 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice"); 1340 return megamorphic_stub(); 1341 } 1342 1343 // If the maximum number of receiver maps has been exceeded, use the generic 1344 // version of the IC. 1345 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { 1346 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded"); 1347 return megamorphic_stub(); 1348 } 1349 1350 CodeHandleList handlers(target_receiver_maps.length()); 1351 ElementHandlerCompiler compiler(isolate()); 1352 compiler.CompileElementHandlers(&target_receiver_maps, &handlers, 1353 language_mode()); 1354 ConfigureVectorState(Handle<Name>::null(), &target_receiver_maps, &handlers); 1355 return null_handle; 1356 } 1357 1358 1359 MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object, 1360 Handle<Object> key) { 1361 if (MigrateDeprecated(object)) { 1362 Handle<Object> result; 1363 ASSIGN_RETURN_ON_EXCEPTION( 1364 isolate(), result, 1365 Runtime::GetObjectProperty(isolate(), object, key, language_mode()), 1366 Object); 1367 return result; 1368 } 1369 1370 Handle<Object> load_handle; 1371 Handle<Code> stub = megamorphic_stub(); 1372 1373 // Check for non-string values that can be converted into an 1374 // internalized string directly or is representable as a smi. 1375 key = TryConvertKey(key, isolate()); 1376 1377 if (key->IsInternalizedString() || key->IsSymbol()) { 1378 ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle, 1379 LoadIC::Load(object, Handle<Name>::cast(key)), 1380 Object); 1381 } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) { 1382 if (object->IsJSObject() || (object->IsString() && key->IsNumber())) { 1383 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); 1384 if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver); 1385 } 1386 } 1387 1388 DCHECK(UseVector()); 1389 if (!is_vector_set() || stub.is_null()) { 1390 Code* generic = *megamorphic_stub(); 1391 if (!stub.is_null() && *stub == generic) { 1392 ConfigureVectorState(MEGAMORPHIC); 1393 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic"); 1394 } 1395 1396 TRACE_IC("LoadIC", key); 1397 } 1398 1399 if (!load_handle.is_null()) return load_handle; 1400 1401 Handle<Object> result; 1402 ASSIGN_RETURN_ON_EXCEPTION( 1403 isolate(), result, 1404 Runtime::GetObjectProperty(isolate(), object, key, language_mode()), 1405 Object); 1406 return result; 1407 } 1408 1409 1410 bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, 1411 JSReceiver::StoreFromKeyed store_mode) { 1412 // Disable ICs for non-JSObjects for now. 1413 Handle<Object> receiver = it->GetReceiver(); 1414 if (!receiver->IsJSObject()) return false; 1415 DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated()); 1416 1417 for (; it->IsFound(); it->Next()) { 1418 switch (it->state()) { 1419 case LookupIterator::NOT_FOUND: 1420 case LookupIterator::TRANSITION: 1421 UNREACHABLE(); 1422 case LookupIterator::JSPROXY: 1423 return false; 1424 case LookupIterator::INTERCEPTOR: { 1425 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1426 InterceptorInfo* info = holder->GetNamedInterceptor(); 1427 if (it->HolderIsReceiverOrHiddenPrototype()) { 1428 if (!info->setter()->IsUndefined()) return true; 1429 } else if (!info->getter()->IsUndefined() || 1430 !info->query()->IsUndefined()) { 1431 return false; 1432 } 1433 break; 1434 } 1435 case LookupIterator::ACCESS_CHECK: 1436 if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false; 1437 break; 1438 case LookupIterator::ACCESSOR: 1439 return !it->IsReadOnly(); 1440 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1441 return false; 1442 case LookupIterator::DATA: { 1443 if (it->IsReadOnly()) return false; 1444 Handle<JSObject> holder = it->GetHolder<JSObject>(); 1445 if (receiver.is_identical_to(holder)) { 1446 it->PrepareForDataProperty(value); 1447 // The previous receiver map might just have been deprecated, 1448 // so reload it. 1449 update_receiver_map(receiver); 1450 return true; 1451 } 1452 1453 // Receiver != holder. 1454 PrototypeIterator iter(it->isolate(), receiver); 1455 if (receiver->IsJSGlobalProxy()) { 1456 return it->GetHolder<Object>().is_identical_to( 1457 PrototypeIterator::GetCurrent(iter)); 1458 } 1459 1460 if (it->HolderIsReceiverOrHiddenPrototype()) return false; 1461 1462 it->PrepareTransitionToDataProperty(value, NONE, store_mode); 1463 return it->IsCacheableTransition(); 1464 } 1465 } 1466 } 1467 1468 it->PrepareTransitionToDataProperty(value, NONE, store_mode); 1469 return it->IsCacheableTransition(); 1470 } 1471 1472 1473 MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name, 1474 Handle<Object> value, 1475 JSReceiver::StoreFromKeyed store_mode) { 1476 // Check if the name is trivially convertible to an index and set the element. 1477 uint32_t index; 1478 if (kind() == Code::KEYED_STORE_IC && name->AsArrayIndex(&index)) { 1479 // Rewrite to the generic keyed store stub. 1480 if (FLAG_use_ic) { 1481 if (UseVector()) { 1482 ConfigureVectorState(MEGAMORPHIC); 1483 } else if (!AddressIsDeoptimizedCode()) { 1484 set_target(*megamorphic_stub()); 1485 } 1486 TRACE_IC("StoreIC", name); 1487 TRACE_GENERIC_IC(isolate(), "StoreIC", "name as array index"); 1488 } 1489 Handle<Object> result; 1490 ASSIGN_RETURN_ON_EXCEPTION( 1491 isolate(), result, 1492 Object::SetElement(isolate(), object, index, value, language_mode()), 1493 Object); 1494 return result; 1495 } 1496 1497 if (object->IsJSGlobalObject() && name->IsString()) { 1498 // Look up in script context table. 1499 Handle<String> str_name = Handle<String>::cast(name); 1500 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object); 1501 Handle<ScriptContextTable> script_contexts( 1502 global->native_context()->script_context_table()); 1503 1504 ScriptContextTable::LookupResult lookup_result; 1505 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { 1506 Handle<Context> script_context = ScriptContextTable::GetContext( 1507 script_contexts, lookup_result.context_index); 1508 if (lookup_result.mode == CONST) { 1509 return TypeError(MessageTemplate::kConstAssign, object, name); 1510 } 1511 1512 Handle<Object> previous_value = 1513 FixedArray::get(script_context, lookup_result.slot_index); 1514 1515 if (*previous_value == *isolate()->factory()->the_hole_value()) { 1516 // Do not install stubs and stay pre-monomorphic for 1517 // uninitialized accesses. 1518 return ReferenceError(name); 1519 } 1520 1521 if (FLAG_use_ic && 1522 StoreScriptContextFieldStub::Accepted(&lookup_result)) { 1523 StoreScriptContextFieldStub stub(isolate(), &lookup_result); 1524 PatchCache(name, stub.GetCode()); 1525 } 1526 1527 script_context->set(lookup_result.slot_index, *value); 1528 return value; 1529 } 1530 } 1531 1532 // TODO(verwaest): Let SetProperty do the migration, since storing a property 1533 // might deprecate the current map again, if value does not fit. 1534 if (MigrateDeprecated(object) || object->IsJSProxy()) { 1535 Handle<Object> result; 1536 ASSIGN_RETURN_ON_EXCEPTION( 1537 isolate(), result, 1538 Object::SetProperty(object, name, value, language_mode()), Object); 1539 return result; 1540 } 1541 1542 // If the object is undefined or null it's illegal to try to set any 1543 // properties on it; throw a TypeError in that case. 1544 if (object->IsUndefined() || object->IsNull()) { 1545 return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name); 1546 } 1547 1548 // Observed objects are always modified through the runtime. 1549 if (object->IsHeapObject() && 1550 Handle<HeapObject>::cast(object)->map()->is_observed()) { 1551 Handle<Object> result; 1552 ASSIGN_RETURN_ON_EXCEPTION( 1553 isolate(), result, 1554 Object::SetProperty(object, name, value, language_mode(), store_mode), 1555 Object); 1556 return result; 1557 } 1558 1559 LookupIterator it(object, name); 1560 if (FLAG_use_ic) UpdateCaches(&it, value, store_mode); 1561 1562 MAYBE_RETURN_NULL( 1563 Object::SetProperty(&it, value, language_mode(), store_mode)); 1564 return value; 1565 } 1566 1567 1568 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc, 1569 ConvertReceiverMode mode) { 1570 CallICTrampolineStub stub(isolate, CallICState(argc, mode)); 1571 Handle<Code> code = stub.GetCode(); 1572 return code; 1573 } 1574 1575 1576 Handle<Code> CallIC::initialize_stub_in_optimized_code( 1577 Isolate* isolate, int argc, ConvertReceiverMode mode) { 1578 CallICStub stub(isolate, CallICState(argc, mode)); 1579 Handle<Code> code = stub.GetCode(); 1580 return code; 1581 } 1582 1583 1584 static Handle<Code> StoreICInitializeStubHelper( 1585 Isolate* isolate, ExtraICState extra_state, 1586 InlineCacheState initialization_state) { 1587 Handle<Code> ic = PropertyICCompiler::ComputeStore( 1588 isolate, initialization_state, extra_state); 1589 return ic; 1590 } 1591 1592 1593 Handle<Code> StoreIC::initialize_stub(Isolate* isolate, 1594 LanguageMode language_mode, 1595 State initialization_state) { 1596 DCHECK(initialization_state == UNINITIALIZED || 1597 initialization_state == PREMONOMORPHIC || 1598 initialization_state == MEGAMORPHIC); 1599 VectorStoreICTrampolineStub stub(isolate, StoreICState(language_mode)); 1600 return stub.GetCode(); 1601 } 1602 1603 1604 Handle<Code> StoreIC::initialize_stub_in_optimized_code( 1605 Isolate* isolate, LanguageMode language_mode, State initialization_state) { 1606 DCHECK(initialization_state == UNINITIALIZED || 1607 initialization_state == PREMONOMORPHIC || 1608 initialization_state == MEGAMORPHIC); 1609 if (initialization_state != MEGAMORPHIC) { 1610 VectorStoreICStub stub(isolate, StoreICState(language_mode)); 1611 return stub.GetCode(); 1612 } 1613 1614 return StoreICInitializeStubHelper( 1615 isolate, ComputeExtraICState(language_mode), initialization_state); 1616 } 1617 1618 1619 Handle<Code> StoreIC::megamorphic_stub() { 1620 if (kind() == Code::STORE_IC) { 1621 return PropertyICCompiler::ComputeStore(isolate(), MEGAMORPHIC, 1622 extra_ic_state()); 1623 } else { 1624 DCHECK(kind() == Code::KEYED_STORE_IC); 1625 if (is_strict(language_mode())) { 1626 return isolate()->builtins()->KeyedStoreIC_Megamorphic_Strict(); 1627 } else { 1628 return isolate()->builtins()->KeyedStoreIC_Megamorphic(); 1629 } 1630 } 1631 } 1632 1633 1634 Handle<Code> StoreIC::slow_stub() const { 1635 if (kind() == Code::STORE_IC) { 1636 return isolate()->builtins()->StoreIC_Slow(); 1637 } else { 1638 DCHECK(kind() == Code::KEYED_STORE_IC); 1639 return isolate()->builtins()->KeyedStoreIC_Slow(); 1640 } 1641 } 1642 1643 1644 Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate, 1645 LanguageMode language_mode) { 1646 ExtraICState state = ComputeExtraICState(language_mode); 1647 return PropertyICCompiler::ComputeStore(isolate, PREMONOMORPHIC, state); 1648 } 1649 1650 1651 void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value, 1652 JSReceiver::StoreFromKeyed store_mode) { 1653 if (state() == UNINITIALIZED) { 1654 // This is the first time we execute this inline cache. Set the target to 1655 // the pre monomorphic stub to delay setting the monomorphic state. 1656 ConfigureVectorState(PREMONOMORPHIC); 1657 TRACE_IC("StoreIC", lookup->name()); 1658 return; 1659 } 1660 1661 bool use_ic = LookupForWrite(lookup, value, store_mode); 1662 if (!use_ic) { 1663 TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'"); 1664 } 1665 Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub(); 1666 1667 PatchCache(lookup->name(), code); 1668 TRACE_IC("StoreIC", lookup->name()); 1669 } 1670 1671 1672 static Handle<Code> PropertyCellStoreHandler( 1673 Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder, 1674 Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) { 1675 auto constant_type = Nothing<PropertyCellConstantType>(); 1676 if (type == PropertyCellType::kConstantType) { 1677 constant_type = Just(cell->GetConstantType()); 1678 } 1679 StoreGlobalStub stub(isolate, type, constant_type, 1680 receiver->IsJSGlobalProxy()); 1681 auto code = stub.GetCodeCopyFromTemplate(holder, cell); 1682 // TODO(verwaest): Move caching of these NORMAL stubs outside as well. 1683 HeapObject::UpdateMapCodeCache(receiver, name, code); 1684 return code; 1685 } 1686 1687 1688 Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, 1689 Handle<Object> value, 1690 CacheHolderFlag cache_holder) { 1691 DCHECK_NE(LookupIterator::JSPROXY, lookup->state()); 1692 1693 // This is currently guaranteed by checks in StoreIC::Store. 1694 Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver()); 1695 Handle<JSObject> holder = lookup->GetHolder<JSObject>(); 1696 DCHECK(!receiver->IsAccessCheckNeeded() || 1697 isolate()->IsInternallyUsedPropertyName(lookup->name())); 1698 1699 switch (lookup->state()) { 1700 case LookupIterator::TRANSITION: { 1701 auto store_target = lookup->GetStoreTarget(); 1702 if (store_target->IsJSGlobalObject()) { 1703 // TODO(dcarney): this currently just deopts. Use the transition cell. 1704 auto cell = isolate()->factory()->NewPropertyCell(); 1705 cell->set_value(*value); 1706 auto code = PropertyCellStoreHandler( 1707 isolate(), store_target, Handle<JSGlobalObject>::cast(store_target), 1708 lookup->name(), cell, PropertyCellType::kConstant); 1709 cell->set_value(isolate()->heap()->the_hole_value()); 1710 return code; 1711 } 1712 Handle<Map> transition = lookup->transition_map(); 1713 // Currently not handled by CompileStoreTransition. 1714 if (!holder->HasFastProperties()) { 1715 TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow"); 1716 break; 1717 } 1718 1719 DCHECK(lookup->IsCacheableTransition()); 1720 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); 1721 return compiler.CompileStoreTransition(transition, lookup->name()); 1722 } 1723 1724 case LookupIterator::INTERCEPTOR: { 1725 DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); 1726 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); 1727 return compiler.CompileStoreInterceptor(lookup->name()); 1728 } 1729 1730 case LookupIterator::ACCESSOR: { 1731 if (!holder->HasFastProperties()) { 1732 TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map"); 1733 break; 1734 } 1735 Handle<Object> accessors = lookup->GetAccessors(); 1736 if (accessors->IsExecutableAccessorInfo()) { 1737 Handle<ExecutableAccessorInfo> info = 1738 Handle<ExecutableAccessorInfo>::cast(accessors); 1739 if (v8::ToCData<Address>(info->setter()) == 0) { 1740 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0"); 1741 break; 1742 } 1743 if (AccessorInfo::cast(*accessors)->is_special_data_property() && 1744 !lookup->HolderIsReceiverOrHiddenPrototype()) { 1745 TRACE_GENERIC_IC(isolate(), "StoreIC", 1746 "special data property in prototype chain"); 1747 break; 1748 } 1749 if (!ExecutableAccessorInfo::IsCompatibleReceiverMap(isolate(), info, 1750 receiver_map())) { 1751 TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type"); 1752 break; 1753 } 1754 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); 1755 return compiler.CompileStoreCallback(receiver, lookup->name(), info); 1756 } else if (accessors->IsAccessorPair()) { 1757 Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), 1758 isolate()); 1759 if (!setter->IsJSFunction()) { 1760 TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function"); 1761 break; 1762 } 1763 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); 1764 CallOptimization call_optimization(function); 1765 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); 1766 if (call_optimization.is_simple_api_call() && 1767 call_optimization.IsCompatibleReceiver(receiver, holder)) { 1768 return compiler.CompileStoreCallback(receiver, lookup->name(), 1769 call_optimization, 1770 lookup->GetAccessorIndex()); 1771 } 1772 int expected_arguments = 1773 function->shared()->internal_formal_parameter_count(); 1774 return compiler.CompileStoreViaSetter(receiver, lookup->name(), 1775 lookup->GetAccessorIndex(), 1776 expected_arguments); 1777 } 1778 break; 1779 } 1780 1781 case LookupIterator::DATA: { 1782 if (lookup->is_dictionary_holder()) { 1783 if (holder->IsJSGlobalObject()) { 1784 DCHECK(holder.is_identical_to(receiver) || 1785 receiver->map()->prototype() == *holder); 1786 auto cell = lookup->GetPropertyCell(); 1787 auto updated_type = PropertyCell::UpdatedType( 1788 cell, value, lookup->property_details()); 1789 auto code = PropertyCellStoreHandler( 1790 isolate(), receiver, Handle<JSGlobalObject>::cast(holder), 1791 lookup->name(), cell, updated_type); 1792 return code; 1793 } 1794 DCHECK(holder.is_identical_to(receiver)); 1795 return isolate()->builtins()->StoreIC_Normal(); 1796 } 1797 1798 // -------------- Fields -------------- 1799 if (lookup->property_details().type() == DATA) { 1800 bool use_stub = true; 1801 if (lookup->representation().IsHeapObject()) { 1802 // Only use a generic stub if no types need to be tracked. 1803 Handle<HeapType> field_type = lookup->GetFieldType(); 1804 HeapType::Iterator<Map> it = field_type->Classes(); 1805 use_stub = it.Done(); 1806 } 1807 if (use_stub) { 1808 StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), 1809 lookup->representation()); 1810 return stub.GetCode(); 1811 } 1812 NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder); 1813 return compiler.CompileStoreField(lookup); 1814 } 1815 1816 // -------------- Constant properties -------------- 1817 DCHECK(lookup->property_details().type() == DATA_CONSTANT); 1818 TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property"); 1819 break; 1820 } 1821 1822 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1823 case LookupIterator::ACCESS_CHECK: 1824 case LookupIterator::JSPROXY: 1825 case LookupIterator::NOT_FOUND: 1826 UNREACHABLE(); 1827 } 1828 return slow_stub(); 1829 } 1830 1831 1832 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<Map> receiver_map, 1833 KeyedAccessStoreMode store_mode) { 1834 Handle<Code> null_handle; 1835 // Don't handle megamorphic property accesses for INTERCEPTORS or 1836 // ACCESSOR_CONSTANT 1837 // via megamorphic stubs, since they don't have a map in their relocation info 1838 // and so the stubs can't be harvested for the object needed for a map check. 1839 if (target()->type() != Code::NORMAL) { 1840 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-NORMAL target type"); 1841 return megamorphic_stub(); 1842 } 1843 1844 MapHandleList target_receiver_maps; 1845 TargetMaps(&target_receiver_maps); 1846 if (target_receiver_maps.length() == 0) { 1847 Handle<Map> monomorphic_map = 1848 ComputeTransitionedMap(receiver_map, store_mode); 1849 store_mode = GetNonTransitioningStoreMode(store_mode); 1850 Handle<Code> handler = 1851 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( 1852 monomorphic_map, language_mode(), store_mode); 1853 ConfigureVectorState(Handle<Name>::null(), monomorphic_map, handler); 1854 return null_handle; 1855 } 1856 1857 // There are several special cases where an IC that is MONOMORPHIC can still 1858 // transition to a different GetNonTransitioningStoreMode IC that handles a 1859 // superset of the original IC. Handle those here if the receiver map hasn't 1860 // changed or it has transitioned to a more general kind. 1861 KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode(); 1862 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); 1863 if (state() == MONOMORPHIC) { 1864 Handle<Map> transitioned_receiver_map = receiver_map; 1865 if (IsTransitionStoreMode(store_mode)) { 1866 transitioned_receiver_map = 1867 ComputeTransitionedMap(receiver_map, store_mode); 1868 } 1869 if ((receiver_map.is_identical_to(previous_receiver_map) && 1870 IsTransitionStoreMode(store_mode)) || 1871 IsTransitionOfMonomorphicTarget(*previous_receiver_map, 1872 *transitioned_receiver_map)) { 1873 // If the "old" and "new" maps are in the same elements map family, or 1874 // if they at least come from the same origin for a transitioning store, 1875 // stay MONOMORPHIC and use the map for the most generic ElementsKind. 1876 store_mode = GetNonTransitioningStoreMode(store_mode); 1877 Handle<Code> handler = 1878 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( 1879 transitioned_receiver_map, language_mode(), store_mode); 1880 ConfigureVectorState(Handle<Name>::null(), transitioned_receiver_map, 1881 handler); 1882 return null_handle; 1883 } else if (receiver_map.is_identical_to(previous_receiver_map) && 1884 old_store_mode == STANDARD_STORE && 1885 (store_mode == STORE_AND_GROW_NO_TRANSITION || 1886 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1887 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { 1888 // A "normal" IC that handles stores can switch to a version that can 1889 // grow at the end of the array, handle OOB accesses or copy COW arrays 1890 // and still stay MONOMORPHIC. 1891 Handle<Code> handler = 1892 PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler( 1893 receiver_map, language_mode(), store_mode); 1894 ConfigureVectorState(Handle<Name>::null(), receiver_map, handler); 1895 return null_handle; 1896 } 1897 } 1898 1899 DCHECK(state() != GENERIC); 1900 1901 bool map_added = 1902 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); 1903 1904 if (IsTransitionStoreMode(store_mode)) { 1905 Handle<Map> transitioned_receiver_map = 1906 ComputeTransitionedMap(receiver_map, store_mode); 1907 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, 1908 transitioned_receiver_map); 1909 } 1910 1911 if (!map_added) { 1912 // If the miss wasn't due to an unseen map, a polymorphic stub 1913 // won't help, use the megamorphic stub which can handle everything. 1914 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "same map added twice"); 1915 return megamorphic_stub(); 1916 } 1917 1918 // If the maximum number of receiver maps has been exceeded, use the 1919 // megamorphic version of the IC. 1920 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { 1921 return megamorphic_stub(); 1922 } 1923 1924 // Make sure all polymorphic handlers have the same store mode, otherwise the 1925 // megamorphic stub must be used. 1926 store_mode = GetNonTransitioningStoreMode(store_mode); 1927 if (old_store_mode != STANDARD_STORE) { 1928 if (store_mode == STANDARD_STORE) { 1929 store_mode = old_store_mode; 1930 } else if (store_mode != old_store_mode) { 1931 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "store mode mismatch"); 1932 return megamorphic_stub(); 1933 } 1934 } 1935 1936 // If the store mode isn't the standard mode, make sure that all polymorphic 1937 // receivers are either external arrays, or all "normal" arrays. Otherwise, 1938 // use the megamorphic stub. 1939 if (store_mode != STANDARD_STORE) { 1940 int external_arrays = 0; 1941 for (int i = 0; i < target_receiver_maps.length(); ++i) { 1942 if (target_receiver_maps[i]->has_fixed_typed_array_elements()) { 1943 external_arrays++; 1944 } 1945 } 1946 if (external_arrays != 0 && 1947 external_arrays != target_receiver_maps.length()) { 1948 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", 1949 "unsupported combination of external and normal arrays"); 1950 return megamorphic_stub(); 1951 } 1952 } 1953 1954 MapHandleList transitioned_maps(target_receiver_maps.length()); 1955 CodeHandleList handlers(target_receiver_maps.length()); 1956 PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers( 1957 &target_receiver_maps, &transitioned_maps, &handlers, store_mode, 1958 language_mode()); 1959 ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers); 1960 return null_handle; 1961 } 1962 1963 1964 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( 1965 Handle<Map> map, KeyedAccessStoreMode store_mode) { 1966 switch (store_mode) { 1967 case STORE_TRANSITION_TO_OBJECT: 1968 case STORE_AND_GROW_TRANSITION_TO_OBJECT: { 1969 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind()) 1970 ? FAST_HOLEY_ELEMENTS 1971 : FAST_ELEMENTS; 1972 return Map::TransitionElementsTo(map, kind); 1973 } 1974 case STORE_TRANSITION_TO_DOUBLE: 1975 case STORE_AND_GROW_TRANSITION_TO_DOUBLE: { 1976 ElementsKind kind = IsFastHoleyElementsKind(map->elements_kind()) 1977 ? FAST_HOLEY_DOUBLE_ELEMENTS 1978 : FAST_DOUBLE_ELEMENTS; 1979 return Map::TransitionElementsTo(map, kind); 1980 } 1981 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: 1982 DCHECK(map->has_fixed_typed_array_elements()); 1983 // Fall through 1984 case STORE_NO_TRANSITION_HANDLE_COW: 1985 case STANDARD_STORE: 1986 case STORE_AND_GROW_NO_TRANSITION: 1987 return map; 1988 } 1989 UNREACHABLE(); 1990 return MaybeHandle<Map>().ToHandleChecked(); 1991 } 1992 1993 1994 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, uint32_t index) { 1995 uint32_t length = 0; 1996 if (receiver->IsJSArray()) { 1997 JSArray::cast(*receiver)->length()->ToArrayLength(&length); 1998 } else { 1999 length = static_cast<uint32_t>(receiver->elements()->length()); 2000 } 2001 return index >= length; 2002 } 2003 2004 2005 static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver, 2006 uint32_t index, Handle<Object> value) { 2007 bool oob_access = IsOutOfBoundsAccess(receiver, index); 2008 // Don't consider this a growing store if the store would send the receiver to 2009 // dictionary mode. 2010 bool allow_growth = receiver->IsJSArray() && oob_access && 2011 !receiver->WouldConvertToSlowElements(index); 2012 if (allow_growth) { 2013 // Handle growing array in stub if necessary. 2014 if (receiver->HasFastSmiElements()) { 2015 if (value->IsHeapNumber()) { 2016 return STORE_AND_GROW_TRANSITION_TO_DOUBLE; 2017 } 2018 if (value->IsHeapObject()) { 2019 return STORE_AND_GROW_TRANSITION_TO_OBJECT; 2020 } 2021 } else if (receiver->HasFastDoubleElements()) { 2022 if (!value->IsSmi() && !value->IsHeapNumber()) { 2023 return STORE_AND_GROW_TRANSITION_TO_OBJECT; 2024 } 2025 } 2026 return STORE_AND_GROW_NO_TRANSITION; 2027 } else { 2028 // Handle only in-bounds elements accesses. 2029 if (receiver->HasFastSmiElements()) { 2030 if (value->IsHeapNumber()) { 2031 return STORE_TRANSITION_TO_DOUBLE; 2032 } else if (value->IsHeapObject()) { 2033 return STORE_TRANSITION_TO_OBJECT; 2034 } 2035 } else if (receiver->HasFastDoubleElements()) { 2036 if (!value->IsSmi() && !value->IsHeapNumber()) { 2037 return STORE_TRANSITION_TO_OBJECT; 2038 } 2039 } 2040 if (!FLAG_trace_external_array_abuse && 2041 receiver->map()->has_fixed_typed_array_elements() && oob_access) { 2042 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS; 2043 } 2044 Heap* heap = receiver->GetHeap(); 2045 if (receiver->elements()->map() == heap->fixed_cow_array_map()) { 2046 return STORE_NO_TRANSITION_HANDLE_COW; 2047 } else { 2048 return STANDARD_STORE; 2049 } 2050 } 2051 } 2052 2053 2054 MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, 2055 Handle<Object> key, 2056 Handle<Object> value) { 2057 // TODO(verwaest): Let SetProperty do the migration, since storing a property 2058 // might deprecate the current map again, if value does not fit. 2059 if (MigrateDeprecated(object)) { 2060 Handle<Object> result; 2061 ASSIGN_RETURN_ON_EXCEPTION( 2062 isolate(), result, Runtime::SetObjectProperty(isolate(), object, key, 2063 value, language_mode()), 2064 Object); 2065 return result; 2066 } 2067 2068 // Check for non-string values that can be converted into an 2069 // internalized string directly or is representable as a smi. 2070 key = TryConvertKey(key, isolate()); 2071 2072 Handle<Object> store_handle; 2073 Handle<Code> stub = megamorphic_stub(); 2074 2075 uint32_t index; 2076 if ((key->IsInternalizedString() && 2077 !String::cast(*key)->AsArrayIndex(&index)) || 2078 key->IsSymbol()) { 2079 ASSIGN_RETURN_ON_EXCEPTION( 2080 isolate(), store_handle, 2081 StoreIC::Store(object, Handle<Name>::cast(key), value, 2082 JSReceiver::MAY_BE_STORE_FROM_KEYED), 2083 Object); 2084 if (!is_vector_set()) { 2085 ConfigureVectorState(MEGAMORPHIC); 2086 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", 2087 "unhandled internalized string key"); 2088 TRACE_IC("StoreIC", key); 2089 } 2090 return store_handle; 2091 } 2092 2093 bool use_ic = 2094 FLAG_use_ic && !object->IsStringWrapper() && 2095 !object->IsAccessCheckNeeded() && !object->IsJSGlobalProxy() && 2096 !(object->IsJSObject() && JSObject::cast(*object)->map()->is_observed()); 2097 if (use_ic && !object->IsSmi()) { 2098 // Don't use ICs for maps of the objects in Array's prototype chain. We 2099 // expect to be able to trap element sets to objects with those maps in 2100 // the runtime to enable optimization of element hole access. 2101 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 2102 if (heap_object->map()->IsMapInArrayPrototypeChain()) { 2103 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "map in array prototype"); 2104 use_ic = false; 2105 } 2106 } 2107 2108 Handle<Map> old_receiver_map; 2109 bool sloppy_arguments_elements = false; 2110 bool key_is_valid_index = false; 2111 KeyedAccessStoreMode store_mode = STANDARD_STORE; 2112 if (use_ic && object->IsJSObject()) { 2113 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 2114 old_receiver_map = handle(receiver->map(), isolate()); 2115 sloppy_arguments_elements = 2116 !is_sloppy(language_mode()) && 2117 receiver->elements()->map() == 2118 isolate()->heap()->sloppy_arguments_elements_map(); 2119 if (!sloppy_arguments_elements) { 2120 key_is_valid_index = key->IsSmi() && Smi::cast(*key)->value() >= 0; 2121 if (key_is_valid_index) { 2122 uint32_t index = static_cast<uint32_t>(Smi::cast(*key)->value()); 2123 store_mode = GetStoreMode(receiver, index, value); 2124 } 2125 } 2126 } 2127 2128 DCHECK(store_handle.is_null()); 2129 ASSIGN_RETURN_ON_EXCEPTION(isolate(), store_handle, 2130 Runtime::SetObjectProperty(isolate(), object, key, 2131 value, language_mode()), 2132 Object); 2133 2134 if (use_ic) { 2135 if (!old_receiver_map.is_null()) { 2136 if (sloppy_arguments_elements) { 2137 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "arguments receiver"); 2138 } else if (key_is_valid_index) { 2139 // We should go generic if receiver isn't a dictionary, but our 2140 // prototype chain does have dictionary elements. This ensures that 2141 // other non-dictionary receivers in the polymorphic case benefit 2142 // from fast path keyed stores. 2143 if (!old_receiver_map->DictionaryElementsInPrototypeChainOnly()) { 2144 stub = StoreElementStub(old_receiver_map, store_mode); 2145 } else { 2146 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", 2147 "dictionary or proxy prototype"); 2148 } 2149 } else { 2150 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-smi-like key"); 2151 } 2152 } else { 2153 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "non-JSObject receiver"); 2154 } 2155 } 2156 2157 if (!is_vector_set() || stub.is_null()) { 2158 Code* megamorphic = *megamorphic_stub(); 2159 if (!stub.is_null() && (*stub == megamorphic || *stub == *slow_stub())) { 2160 ConfigureVectorState(MEGAMORPHIC); 2161 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", 2162 *stub == megamorphic ? "set generic" : "slow stub"); 2163 } 2164 } 2165 TRACE_IC("StoreIC", key); 2166 2167 return store_handle; 2168 } 2169 2170 2171 void CallIC::HandleMiss(Handle<Object> function) { 2172 Handle<Object> name = isolate()->factory()->empty_string(); 2173 CallICNexus* nexus = casted_nexus<CallICNexus>(); 2174 Object* feedback = nexus->GetFeedback(); 2175 2176 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. 2177 DCHECK(!feedback->IsSmi()); 2178 2179 if (feedback->IsWeakCell() || !function->IsJSFunction() || 2180 feedback->IsAllocationSite()) { 2181 // We are going generic. 2182 nexus->ConfigureMegamorphic(); 2183 } else { 2184 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate())); 2185 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); 2186 2187 Handle<JSFunction> array_function = 2188 Handle<JSFunction>(isolate()->native_context()->array_function()); 2189 if (array_function.is_identical_to(js_function)) { 2190 // Alter the slot. 2191 nexus->ConfigureMonomorphicArray(); 2192 } else if (js_function->context()->native_context() != 2193 *isolate()->native_context()) { 2194 // Don't collect cross-native context feedback for the CallIC. 2195 // TODO(bmeurer): We should collect the SharedFunctionInfo as 2196 // feedback in this case instead. 2197 nexus->ConfigureMegamorphic(); 2198 } else { 2199 nexus->ConfigureMonomorphic(js_function); 2200 } 2201 } 2202 2203 if (function->IsJSFunction()) { 2204 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); 2205 name = handle(js_function->shared()->name(), isolate()); 2206 } 2207 2208 OnTypeFeedbackChanged(isolate(), get_host()); 2209 TRACE_IC("CallIC", name); 2210 } 2211 2212 2213 #undef TRACE_IC 2214 2215 2216 // ---------------------------------------------------------------------------- 2217 // Static IC stub generators. 2218 // 2219 2220 // Used from ic-<arch>.cc. 2221 RUNTIME_FUNCTION(Runtime_CallIC_Miss) { 2222 TimerEventScope<TimerEventIcMiss> timer(isolate); 2223 HandleScope scope(isolate); 2224 DCHECK(args.length() == 3); 2225 Handle<Object> function = args.at<Object>(0); 2226 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(1); 2227 Handle<Smi> slot = args.at<Smi>(2); 2228 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2229 CallICNexus nexus(vector, vector_slot); 2230 CallIC ic(isolate, &nexus); 2231 ic.HandleMiss(function); 2232 return *function; 2233 } 2234 2235 2236 // Used from ic-<arch>.cc. 2237 RUNTIME_FUNCTION(Runtime_LoadIC_Miss) { 2238 TimerEventScope<TimerEventIcMiss> timer(isolate); 2239 HandleScope scope(isolate); 2240 Handle<Object> receiver = args.at<Object>(0); 2241 Handle<Name> key = args.at<Name>(1); 2242 Handle<Object> result; 2243 2244 DCHECK(args.length() == 4); 2245 Handle<Smi> slot = args.at<Smi>(2); 2246 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); 2247 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2248 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the 2249 // LoadIC miss handler if the handler misses. Since the vector Nexus is 2250 // set up outside the IC, handle that here. 2251 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) { 2252 LoadICNexus nexus(vector, vector_slot); 2253 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2254 ic.UpdateState(receiver, key); 2255 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2256 } else { 2257 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, 2258 vector->GetKind(vector_slot)); 2259 KeyedLoadICNexus nexus(vector, vector_slot); 2260 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2261 ic.UpdateState(receiver, key); 2262 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2263 } 2264 return *result; 2265 } 2266 2267 2268 // Used from ic-<arch>.cc 2269 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_Miss) { 2270 TimerEventScope<TimerEventIcMiss> timer(isolate); 2271 HandleScope scope(isolate); 2272 Handle<Object> receiver = args.at<Object>(0); 2273 Handle<Object> key = args.at<Object>(1); 2274 Handle<Object> result; 2275 2276 DCHECK(args.length() == 4); 2277 Handle<Smi> slot = args.at<Smi>(2); 2278 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); 2279 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2280 KeyedLoadICNexus nexus(vector, vector_slot); 2281 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2282 ic.UpdateState(receiver, key); 2283 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2284 return *result; 2285 } 2286 2287 2288 RUNTIME_FUNCTION(Runtime_KeyedLoadIC_MissFromStubFailure) { 2289 TimerEventScope<TimerEventIcMiss> timer(isolate); 2290 HandleScope scope(isolate); 2291 Handle<Object> receiver = args.at<Object>(0); 2292 Handle<Object> key = args.at<Object>(1); 2293 Handle<Object> result; 2294 2295 DCHECK(args.length() == 4); 2296 Handle<Smi> slot = args.at<Smi>(2); 2297 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); 2298 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2299 KeyedLoadICNexus nexus(vector, vector_slot); 2300 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2301 ic.UpdateState(receiver, key); 2302 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2303 2304 return *result; 2305 } 2306 2307 2308 // Used from ic-<arch>.cc. 2309 RUNTIME_FUNCTION(Runtime_StoreIC_Miss) { 2310 TimerEventScope<TimerEventIcMiss> timer(isolate); 2311 HandleScope scope(isolate); 2312 Handle<Object> receiver = args.at<Object>(0); 2313 Handle<Name> key = args.at<Name>(1); 2314 Handle<Object> value = args.at<Object>(2); 2315 Handle<Object> result; 2316 2317 DCHECK(args.length() == 5 || args.length() == 6); 2318 Handle<Smi> slot = args.at<Smi>(3); 2319 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4); 2320 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2321 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) { 2322 StoreICNexus nexus(vector, vector_slot); 2323 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2324 ic.UpdateState(receiver, key); 2325 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2326 ic.Store(receiver, key, value)); 2327 } else { 2328 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, 2329 vector->GetKind(vector_slot)); 2330 KeyedStoreICNexus nexus(vector, vector_slot); 2331 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2332 ic.UpdateState(receiver, key); 2333 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2334 ic.Store(receiver, key, value)); 2335 } 2336 return *result; 2337 } 2338 2339 2340 RUNTIME_FUNCTION(Runtime_StoreIC_MissFromStubFailure) { 2341 TimerEventScope<TimerEventIcMiss> timer(isolate); 2342 HandleScope scope(isolate); 2343 Handle<Object> receiver = args.at<Object>(0); 2344 Handle<Name> key = args.at<Name>(1); 2345 Handle<Object> value = args.at<Object>(2); 2346 Handle<Object> result; 2347 2348 int length = args.length(); 2349 DCHECK(length == 5 || length == 6); 2350 // We might have slot and vector, for a normal miss (slot(3), vector(4)). 2351 // Or, map and vector for a transitioning store miss (map(3), vector(4)). 2352 // In this case, we need to recover the slot from a virtual register. 2353 // If length == 6, then a map is included (map(3), slot(4), vector(5)). 2354 Handle<Smi> slot; 2355 Handle<TypeFeedbackVector> vector; 2356 if (length == 5) { 2357 if (args.at<Object>(3)->IsMap()) { 2358 vector = args.at<TypeFeedbackVector>(4); 2359 slot = handle( 2360 *reinterpret_cast<Smi**>(isolate->virtual_slot_register_address()), 2361 isolate); 2362 } else { 2363 vector = args.at<TypeFeedbackVector>(4); 2364 slot = args.at<Smi>(3); 2365 } 2366 } else { 2367 vector = args.at<TypeFeedbackVector>(5); 2368 slot = args.at<Smi>(4); 2369 } 2370 2371 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2372 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::STORE_IC) { 2373 StoreICNexus nexus(vector, vector_slot); 2374 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2375 ic.UpdateState(receiver, key); 2376 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2377 ic.Store(receiver, key, value)); 2378 } else { 2379 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, 2380 vector->GetKind(vector_slot)); 2381 KeyedStoreICNexus nexus(vector, vector_slot); 2382 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2383 ic.UpdateState(receiver, key); 2384 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2385 ic.Store(receiver, key, value)); 2386 } 2387 return *result; 2388 } 2389 2390 2391 // Used from ic-<arch>.cc. 2392 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) { 2393 TimerEventScope<TimerEventIcMiss> timer(isolate); 2394 HandleScope scope(isolate); 2395 Handle<Object> receiver = args.at<Object>(0); 2396 Handle<Object> key = args.at<Object>(1); 2397 Handle<Object> value = args.at<Object>(2); 2398 Handle<Object> result; 2399 2400 DCHECK(args.length() == 5); 2401 Handle<Smi> slot = args.at<Smi>(3); 2402 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4); 2403 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2404 KeyedStoreICNexus nexus(vector, vector_slot); 2405 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2406 ic.UpdateState(receiver, key); 2407 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2408 ic.Store(receiver, key, value)); 2409 return *result; 2410 } 2411 2412 2413 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_MissFromStubFailure) { 2414 TimerEventScope<TimerEventIcMiss> timer(isolate); 2415 HandleScope scope(isolate); 2416 Handle<Object> receiver = args.at<Object>(0); 2417 Handle<Object> key = args.at<Object>(1); 2418 Handle<Object> value = args.at<Object>(2); 2419 Handle<Object> result; 2420 2421 DCHECK(args.length() == 5); 2422 Handle<Smi> slot = args.at<Smi>(3); 2423 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(4); 2424 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2425 KeyedStoreICNexus nexus(vector, vector_slot); 2426 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2427 ic.UpdateState(receiver, key); 2428 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2429 ic.Store(receiver, key, value)); 2430 return *result; 2431 } 2432 2433 2434 RUNTIME_FUNCTION(Runtime_StoreIC_Slow) { 2435 HandleScope scope(isolate); 2436 DCHECK(args.length() == 5); 2437 Handle<Object> object = args.at<Object>(0); 2438 Handle<Object> key = args.at<Object>(1); 2439 Handle<Object> value = args.at<Object>(2); 2440 LanguageMode language_mode; 2441 StoreICNexus nexus(isolate); 2442 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2443 language_mode = ic.language_mode(); 2444 Handle<Object> result; 2445 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2446 isolate, result, 2447 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 2448 return *result; 2449 } 2450 2451 2452 RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) { 2453 HandleScope scope(isolate); 2454 DCHECK(args.length() == 5); 2455 Handle<Object> object = args.at<Object>(0); 2456 Handle<Object> key = args.at<Object>(1); 2457 Handle<Object> value = args.at<Object>(2); 2458 LanguageMode language_mode; 2459 KeyedStoreICNexus nexus(isolate); 2460 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2461 language_mode = ic.language_mode(); 2462 Handle<Object> result; 2463 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2464 isolate, result, 2465 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 2466 return *result; 2467 } 2468 2469 2470 RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) { 2471 TimerEventScope<TimerEventIcMiss> timer(isolate); 2472 HandleScope scope(isolate); 2473 // Length == 5 or 6, depending on whether the vector slot 2474 // is passed in a virtual register or not. 2475 DCHECK(args.length() == 5 || args.length() == 6); 2476 Handle<Object> object = args.at<Object>(0); 2477 Handle<Object> key = args.at<Object>(1); 2478 Handle<Object> value = args.at<Object>(2); 2479 Handle<Map> map = args.at<Map>(3); 2480 LanguageMode language_mode; 2481 KeyedStoreICNexus nexus(isolate); 2482 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2483 language_mode = ic.language_mode(); 2484 if (object->IsJSObject()) { 2485 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), 2486 map->elements_kind()); 2487 } 2488 Handle<Object> result; 2489 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2490 isolate, result, 2491 Runtime::SetObjectProperty(isolate, object, key, value, language_mode)); 2492 return *result; 2493 } 2494 2495 2496 MaybeHandle<Object> BinaryOpIC::Transition( 2497 Handle<AllocationSite> allocation_site, Handle<Object> left, 2498 Handle<Object> right) { 2499 BinaryOpICState state(isolate(), target()->extra_ic_state()); 2500 2501 // Compute the actual result using the builtin for the binary operation. 2502 Handle<Object> result; 2503 switch (state.op()) { 2504 default: 2505 UNREACHABLE(); 2506 case Token::ADD: 2507 ASSIGN_RETURN_ON_EXCEPTION( 2508 isolate(), result, 2509 Object::Add(isolate(), left, right, state.strength()), Object); 2510 break; 2511 case Token::SUB: 2512 ASSIGN_RETURN_ON_EXCEPTION( 2513 isolate(), result, 2514 Object::Subtract(isolate(), left, right, state.strength()), Object); 2515 break; 2516 case Token::MUL: 2517 ASSIGN_RETURN_ON_EXCEPTION( 2518 isolate(), result, 2519 Object::Multiply(isolate(), left, right, state.strength()), Object); 2520 break; 2521 case Token::DIV: 2522 ASSIGN_RETURN_ON_EXCEPTION( 2523 isolate(), result, 2524 Object::Divide(isolate(), left, right, state.strength()), Object); 2525 break; 2526 case Token::MOD: 2527 ASSIGN_RETURN_ON_EXCEPTION( 2528 isolate(), result, 2529 Object::Modulus(isolate(), left, right, state.strength()), Object); 2530 break; 2531 case Token::BIT_OR: 2532 ASSIGN_RETURN_ON_EXCEPTION( 2533 isolate(), result, 2534 Object::BitwiseOr(isolate(), left, right, state.strength()), Object); 2535 break; 2536 case Token::BIT_AND: 2537 ASSIGN_RETURN_ON_EXCEPTION( 2538 isolate(), result, 2539 Object::BitwiseAnd(isolate(), left, right, state.strength()), Object); 2540 break; 2541 case Token::BIT_XOR: 2542 ASSIGN_RETURN_ON_EXCEPTION( 2543 isolate(), result, 2544 Object::BitwiseXor(isolate(), left, right, state.strength()), Object); 2545 break; 2546 case Token::SAR: 2547 ASSIGN_RETURN_ON_EXCEPTION( 2548 isolate(), result, 2549 Object::ShiftRight(isolate(), left, right, state.strength()), Object); 2550 break; 2551 case Token::SHR: 2552 ASSIGN_RETURN_ON_EXCEPTION( 2553 isolate(), result, 2554 Object::ShiftRightLogical(isolate(), left, right, state.strength()), 2555 Object); 2556 break; 2557 case Token::SHL: 2558 ASSIGN_RETURN_ON_EXCEPTION( 2559 isolate(), result, 2560 Object::ShiftLeft(isolate(), left, right, state.strength()), Object); 2561 break; 2562 } 2563 2564 // Do not try to update the target if the code was marked for lazy 2565 // deoptimization. (Since we do not relocate addresses in these 2566 // code objects, an attempt to access the target could fail.) 2567 if (AddressIsDeoptimizedCode()) { 2568 return result; 2569 } 2570 2571 // Execution::Call can execute arbitrary JavaScript, hence potentially 2572 // update the state of this very IC, so we must update the stored state. 2573 UpdateTarget(); 2574 2575 // Compute the new state. 2576 BinaryOpICState old_state(isolate(), target()->extra_ic_state()); 2577 state.Update(left, right, result); 2578 2579 // Check if we have a string operation here. 2580 Handle<Code> target; 2581 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) { 2582 // Setup the allocation site on-demand. 2583 if (allocation_site.is_null()) { 2584 allocation_site = isolate()->factory()->NewAllocationSite(); 2585 } 2586 2587 // Install the stub with an allocation site. 2588 BinaryOpICWithAllocationSiteStub stub(isolate(), state); 2589 target = stub.GetCodeCopyFromTemplate(allocation_site); 2590 2591 // Sanity check the trampoline stub. 2592 DCHECK_EQ(*allocation_site, target->FindFirstAllocationSite()); 2593 } else { 2594 // Install the generic stub. 2595 BinaryOpICStub stub(isolate(), state); 2596 target = stub.GetCode(); 2597 2598 // Sanity check the generic stub. 2599 DCHECK_NULL(target->FindFirstAllocationSite()); 2600 } 2601 set_target(*target); 2602 2603 if (FLAG_trace_ic) { 2604 OFStream os(stdout); 2605 os << "[BinaryOpIC" << old_state << " => " << state << " @ " 2606 << static_cast<void*>(*target) << " <- "; 2607 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); 2608 if (!allocation_site.is_null()) { 2609 os << " using allocation site " << static_cast<void*>(*allocation_site); 2610 } 2611 os << "]" << std::endl; 2612 } 2613 2614 // Patch the inlined smi code as necessary. 2615 if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) { 2616 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK); 2617 } else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) { 2618 PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK); 2619 } 2620 2621 return result; 2622 } 2623 2624 2625 RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) { 2626 TimerEventScope<TimerEventIcMiss> timer(isolate); 2627 HandleScope scope(isolate); 2628 DCHECK_EQ(2, args.length()); 2629 Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft); 2630 Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight); 2631 BinaryOpIC ic(isolate); 2632 Handle<Object> result; 2633 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2634 isolate, result, 2635 ic.Transition(Handle<AllocationSite>::null(), left, right)); 2636 return *result; 2637 } 2638 2639 2640 RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) { 2641 TimerEventScope<TimerEventIcMiss> timer(isolate); 2642 HandleScope scope(isolate); 2643 DCHECK_EQ(3, args.length()); 2644 Handle<AllocationSite> allocation_site = 2645 args.at<AllocationSite>(BinaryOpWithAllocationSiteStub::kAllocationSite); 2646 Handle<Object> left = args.at<Object>(BinaryOpWithAllocationSiteStub::kLeft); 2647 Handle<Object> right = 2648 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight); 2649 BinaryOpIC ic(isolate); 2650 Handle<Object> result; 2651 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2652 isolate, result, ic.Transition(allocation_site, left, right)); 2653 return *result; 2654 } 2655 2656 2657 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op, 2658 Strength strength) { 2659 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED, 2660 CompareICState::UNINITIALIZED, 2661 CompareICState::UNINITIALIZED); 2662 Code* code = NULL; 2663 CHECK(stub.FindCodeInCache(&code)); 2664 return code; 2665 } 2666 2667 2668 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op, 2669 Strength strength) { 2670 CompareICStub stub(isolate, op, strength, CompareICState::UNINITIALIZED, 2671 CompareICState::UNINITIALIZED, 2672 CompareICState::UNINITIALIZED); 2673 return stub.GetCode(); 2674 } 2675 2676 2677 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { 2678 HandleScope scope(isolate()); 2679 CompareICStub old_stub(target()->stub_key(), isolate()); 2680 CompareICState::State new_left = 2681 CompareICState::NewInputState(old_stub.left(), x); 2682 CompareICState::State new_right = 2683 CompareICState::NewInputState(old_stub.right(), y); 2684 CompareICState::State state = CompareICState::TargetState( 2685 old_stub.state(), old_stub.left(), old_stub.right(), op_, 2686 HasInlinedSmiCode(address()), x, y); 2687 CompareICStub stub(isolate(), op_, old_stub.strength(), new_left, new_right, 2688 state); 2689 if (state == CompareICState::KNOWN_RECEIVER) { 2690 stub.set_known_map( 2691 Handle<Map>(Handle<JSReceiver>::cast(x)->map(), isolate())); 2692 } 2693 Handle<Code> new_target = stub.GetCode(); 2694 set_target(*new_target); 2695 2696 if (FLAG_trace_ic) { 2697 PrintF("[CompareIC in "); 2698 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); 2699 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", 2700 CompareICState::GetStateName(old_stub.left()), 2701 CompareICState::GetStateName(old_stub.right()), 2702 CompareICState::GetStateName(old_stub.state()), 2703 CompareICState::GetStateName(new_left), 2704 CompareICState::GetStateName(new_right), 2705 CompareICState::GetStateName(state), Token::Name(op_), 2706 static_cast<void*>(*stub.GetCode())); 2707 } 2708 2709 // Activate inlined smi code. 2710 if (old_stub.state() == CompareICState::UNINITIALIZED) { 2711 PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK); 2712 } 2713 2714 return *new_target; 2715 } 2716 2717 2718 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc. 2719 RUNTIME_FUNCTION(Runtime_CompareIC_Miss) { 2720 TimerEventScope<TimerEventIcMiss> timer(isolate); 2721 HandleScope scope(isolate); 2722 DCHECK(args.length() == 3); 2723 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); 2724 return ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); 2725 } 2726 2727 2728 void CompareNilIC::Clear(Address address, Code* target, Address constant_pool) { 2729 if (IsCleared(target)) return; 2730 ExtraICState state = target->extra_ic_state(); 2731 2732 CompareNilICStub stub(target->GetIsolate(), state, 2733 HydrogenCodeStub::UNINITIALIZED); 2734 stub.ClearState(); 2735 2736 Code* code = NULL; 2737 CHECK(stub.FindCodeInCache(&code)); 2738 2739 SetTargetAtAddress(address, code, constant_pool); 2740 } 2741 2742 2743 Handle<Object> CompareNilIC::DoCompareNilSlow(Isolate* isolate, NilValue nil, 2744 Handle<Object> object) { 2745 if (object->IsNull() || object->IsUndefined()) { 2746 return isolate->factory()->true_value(); 2747 } 2748 return isolate->factory()->ToBoolean(object->IsUndetectableObject()); 2749 } 2750 2751 2752 Handle<Object> CompareNilIC::CompareNil(Handle<Object> object) { 2753 ExtraICState extra_ic_state = target()->extra_ic_state(); 2754 2755 CompareNilICStub stub(isolate(), extra_ic_state); 2756 2757 // Extract the current supported types from the patched IC and calculate what 2758 // types must be supported as a result of the miss. 2759 bool already_monomorphic = stub.IsMonomorphic(); 2760 2761 stub.UpdateStatus(object); 2762 2763 NilValue nil = stub.nil_value(); 2764 2765 // Find or create the specialized stub to support the new set of types. 2766 Handle<Code> code; 2767 if (stub.IsMonomorphic()) { 2768 Handle<Map> monomorphic_map(already_monomorphic && FirstTargetMap() != NULL 2769 ? FirstTargetMap() 2770 : HeapObject::cast(*object)->map()); 2771 code = PropertyICCompiler::ComputeCompareNil(monomorphic_map, &stub); 2772 } else { 2773 code = stub.GetCode(); 2774 } 2775 set_target(*code); 2776 return DoCompareNilSlow(isolate(), nil, object); 2777 } 2778 2779 2780 RUNTIME_FUNCTION(Runtime_CompareNilIC_Miss) { 2781 TimerEventScope<TimerEventIcMiss> timer(isolate); 2782 HandleScope scope(isolate); 2783 Handle<Object> object = args.at<Object>(0); 2784 CompareNilIC ic(isolate); 2785 return *ic.CompareNil(object); 2786 } 2787 2788 2789 RUNTIME_FUNCTION(Runtime_Unreachable) { 2790 UNREACHABLE(); 2791 CHECK(false); 2792 return isolate->heap()->undefined_value(); 2793 } 2794 2795 2796 Handle<Object> ToBooleanIC::ToBoolean(Handle<Object> object) { 2797 ToBooleanStub stub(isolate(), target()->extra_ic_state()); 2798 bool to_boolean_value = stub.UpdateStatus(object); 2799 Handle<Code> code = stub.GetCode(); 2800 set_target(*code); 2801 return isolate()->factory()->ToBoolean(to_boolean_value); 2802 } 2803 2804 2805 RUNTIME_FUNCTION(Runtime_ToBooleanIC_Miss) { 2806 TimerEventScope<TimerEventIcMiss> timer(isolate); 2807 DCHECK(args.length() == 1); 2808 HandleScope scope(isolate); 2809 Handle<Object> object = args.at<Object>(0); 2810 ToBooleanIC ic(isolate); 2811 return *ic.ToBoolean(object); 2812 } 2813 2814 2815 RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) { 2816 Handle<JSObject> receiver = args.at<JSObject>(0); 2817 Handle<JSObject> holder = args.at<JSObject>(1); 2818 Handle<HeapObject> callback_or_cell = args.at<HeapObject>(2); 2819 Handle<Name> name = args.at<Name>(3); 2820 Handle<Object> value = args.at<Object>(4); 2821 HandleScope scope(isolate); 2822 2823 Handle<ExecutableAccessorInfo> callback( 2824 callback_or_cell->IsWeakCell() 2825 ? ExecutableAccessorInfo::cast( 2826 WeakCell::cast(*callback_or_cell)->value()) 2827 : ExecutableAccessorInfo::cast(*callback_or_cell)); 2828 2829 DCHECK(callback->IsCompatibleReceiver(*receiver)); 2830 2831 Address setter_address = v8::ToCData<Address>(callback->setter()); 2832 v8::AccessorNameSetterCallback fun = 2833 FUNCTION_CAST<v8::AccessorNameSetterCallback>(setter_address); 2834 DCHECK(fun != NULL); 2835 2836 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name)); 2837 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver, 2838 *holder); 2839 custom_args.Call(fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); 2840 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 2841 return *value; 2842 } 2843 2844 2845 /** 2846 * Attempts to load a property with an interceptor (which must be present), 2847 * but doesn't search the prototype chain. 2848 * 2849 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't 2850 * provide any value for the given name. 2851 */ 2852 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) { 2853 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); 2854 Handle<Name> name = 2855 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); 2856 Handle<JSObject> receiver = 2857 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); 2858 Handle<JSObject> holder = 2859 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); 2860 HandleScope scope(isolate); 2861 LookupIterator it(receiver, name, holder, LookupIterator::OWN); 2862 bool done; 2863 Handle<Object> result; 2864 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2865 isolate, result, JSObject::GetPropertyWithInterceptor(&it, &done)); 2866 if (done) return *result; 2867 return isolate->heap()->no_interceptor_result_sentinel(); 2868 } 2869 2870 2871 /** 2872 * Loads a property with an interceptor performing post interceptor 2873 * lookup if interceptor failed. 2874 */ 2875 RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) { 2876 HandleScope scope(isolate); 2877 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength); 2878 Handle<Name> name = 2879 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex); 2880 Handle<JSObject> receiver = 2881 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex); 2882 Handle<JSObject> holder = 2883 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex); 2884 2885 Handle<Object> result; 2886 LookupIterator it(receiver, name, holder); 2887 // TODO(conradw): Investigate strong mode semantics for this. 2888 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 2889 JSObject::GetProperty(&it)); 2890 2891 if (it.IsFound()) return *result; 2892 2893 // Return the undefined result if the reference error should not be thrown. 2894 // Note that both keyed and non-keyed loads may end up here. 2895 LoadICNexus nexus(isolate); 2896 LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2897 if (!ic.ShouldThrowReferenceError(it.GetReceiver())) { 2898 return isolate->heap()->undefined_value(); 2899 } 2900 2901 // Throw a reference error. 2902 THROW_NEW_ERROR_RETURN_FAILURE( 2903 isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name())); 2904 } 2905 2906 2907 RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) { 2908 HandleScope scope(isolate); 2909 DCHECK(args.length() == 3); 2910 StoreICNexus nexus(isolate); 2911 StoreIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus); 2912 Handle<JSObject> receiver = args.at<JSObject>(0); 2913 Handle<Name> name = args.at<Name>(1); 2914 Handle<Object> value = args.at<Object>(2); 2915 #ifdef DEBUG 2916 PrototypeIterator iter(isolate, receiver, 2917 PrototypeIterator::START_AT_RECEIVER); 2918 bool found = false; 2919 for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) { 2920 Handle<Object> current = PrototypeIterator::GetCurrent(iter); 2921 if (current->IsJSObject() && 2922 Handle<JSObject>::cast(current)->HasNamedInterceptor()) { 2923 found = true; 2924 break; 2925 } 2926 } 2927 DCHECK(found); 2928 #endif 2929 Handle<Object> result; 2930 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2931 isolate, result, 2932 JSObject::SetProperty(receiver, name, value, ic.language_mode())); 2933 return *result; 2934 } 2935 2936 2937 RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) { 2938 // TODO(verwaest): This should probably get the holder and receiver as input. 2939 HandleScope scope(isolate); 2940 Handle<JSObject> receiver = args.at<JSObject>(0); 2941 DCHECK(args.smi_at(1) >= 0); 2942 uint32_t index = args.smi_at(1); 2943 Handle<Object> result; 2944 // TODO(conradw): Investigate strong mode semantics for this. 2945 LanguageMode language_mode = SLOPPY; 2946 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2947 isolate, result, 2948 Object::GetElement(isolate, receiver, index, language_mode)); 2949 return *result; 2950 } 2951 2952 2953 RUNTIME_FUNCTION(Runtime_LoadIC_MissFromStubFailure) { 2954 TimerEventScope<TimerEventIcMiss> timer(isolate); 2955 HandleScope scope(isolate); 2956 Handle<Object> receiver = args.at<Object>(0); 2957 Handle<Name> key = args.at<Name>(1); 2958 Handle<Object> result; 2959 2960 DCHECK(args.length() == 4); 2961 Handle<Smi> slot = args.at<Smi>(2); 2962 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3); 2963 FeedbackVectorSlot vector_slot = vector->ToSlot(slot->value()); 2964 // A monomorphic or polymorphic KeyedLoadIC with a string key can call the 2965 // LoadIC miss handler if the handler misses. Since the vector Nexus is 2966 // set up outside the IC, handle that here. 2967 if (vector->GetKind(vector_slot) == FeedbackVectorSlotKind::LOAD_IC) { 2968 LoadICNexus nexus(vector, vector_slot); 2969 LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2970 ic.UpdateState(receiver, key); 2971 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2972 } else { 2973 DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, 2974 vector->GetKind(vector_slot)); 2975 KeyedLoadICNexus nexus(vector, vector_slot); 2976 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus); 2977 ic.UpdateState(receiver, key); 2978 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key)); 2979 } 2980 2981 return *result; 2982 } 2983 } // namespace internal 2984 } // namespace v8 2985