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