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