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