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