1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "accessors.h" 31 #include "api.h" 32 #include "arguments.h" 33 #include "codegen.h" 34 #include "execution.h" 35 #include "ic-inl.h" 36 #include "runtime.h" 37 #include "stub-cache.h" 38 39 namespace v8 { 40 namespace internal { 41 42 #ifdef DEBUG 43 char IC::TransitionMarkFromState(IC::State state) { 44 switch (state) { 45 case UNINITIALIZED: return '0'; 46 case PREMONOMORPHIC: return '.'; 47 case MONOMORPHIC: return '1'; 48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; 49 case POLYMORPHIC: return 'P'; 50 case MEGAMORPHIC: return 'N'; 51 case GENERIC: return 'G'; 52 53 // We never see the debugger states here, because the state is 54 // computed from the original code - not the patched code. Let 55 // these cases fall through to the unreachable code below. 56 case DEBUG_STUB: break; 57 } 58 UNREACHABLE(); 59 return 0; 60 } 61 62 63 const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { 64 if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW"; 65 if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { 66 return ".IGNORE_OOB"; 67 } 68 if (IsGrowStoreMode(mode)) return ".GROW"; 69 return ""; 70 } 71 72 73 void IC::TraceIC(const char* type, 74 Handle<Object> name, 75 State old_state, 76 Code* new_target) { 77 if (FLAG_trace_ic) { 78 Object* undef = new_target->GetHeap()->undefined_value(); 79 State new_state = StateFrom(new_target, undef, undef); 80 PrintF("[%s in ", type); 81 Isolate* isolate = new_target->GetIsolate(); 82 StackFrameIterator it(isolate); 83 while (it.frame()->fp() != this->fp()) it.Advance(); 84 StackFrame* raw_frame = it.frame(); 85 if (raw_frame->is_internal()) { 86 Code* apply_builtin = isolate->builtins()->builtin( 87 Builtins::kFunctionApply); 88 if (raw_frame->unchecked_code() == apply_builtin) { 89 PrintF("apply from "); 90 it.Advance(); 91 raw_frame = it.frame(); 92 } 93 } 94 JavaScriptFrame::PrintTop(isolate, stdout, false, true); 95 Code::ExtraICState state = new_target->extra_ic_state(); 96 const char* modifier = 97 GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(state)); 98 PrintF(" (%c->%c%s)", 99 TransitionMarkFromState(old_state), 100 TransitionMarkFromState(new_state), 101 modifier); 102 name->Print(); 103 PrintF("]\n"); 104 } 105 } 106 107 #define TRACE_GENERIC_IC(isolate, type, reason) \ 108 do { \ 109 if (FLAG_trace_ic) { \ 110 PrintF("[%s patching generic stub in ", type); \ 111 JavaScriptFrame::PrintTop(isolate, stdout, false, true); \ 112 PrintF(" (%s)]\n", reason); \ 113 } \ 114 } while (false) 115 116 #else 117 #define TRACE_GENERIC_IC(isolate, type, reason) 118 #endif // DEBUG 119 120 #define TRACE_IC(type, name, old_state, new_target) \ 121 ASSERT((TraceIC(type, name, old_state, new_target), true)) 122 123 IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { 124 // To improve the performance of the (much used) IC code, we unfold a few 125 // levels of the stack frame iteration code. This yields a ~35% speedup when 126 // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. 127 const Address entry = 128 Isolate::c_entry_fp(isolate->thread_local_top()); 129 Address* pc_address = 130 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); 131 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 132 // If there's another JavaScript frame on the stack or a 133 // StubFailureTrampoline, we need to look one frame further down the stack to 134 // find the frame pointer and the return address stack slot. 135 if (depth == EXTRA_CALL_FRAME) { 136 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; 137 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); 138 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); 139 } 140 #ifdef DEBUG 141 StackFrameIterator it(isolate); 142 for (int i = 0; i < depth + 1; i++) it.Advance(); 143 StackFrame* frame = it.frame(); 144 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); 145 #endif 146 fp_ = fp; 147 pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); 148 } 149 150 151 #ifdef ENABLE_DEBUGGER_SUPPORT 152 Address IC::OriginalCodeAddress() const { 153 HandleScope scope(isolate()); 154 // Compute the JavaScript frame for the frame pointer of this IC 155 // structure. We need this to be able to find the function 156 // corresponding to the frame. 157 StackFrameIterator it(isolate()); 158 while (it.frame()->fp() != this->fp()) it.Advance(); 159 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 160 // Find the function on the stack and both the active code for the 161 // function and the original code. 162 JSFunction* function = frame->function(); 163 Handle<SharedFunctionInfo> shared(function->shared(), isolate()); 164 Code* code = shared->code(); 165 ASSERT(Debug::HasDebugInfo(shared)); 166 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); 167 ASSERT(original_code->IsCode()); 168 // Get the address of the call site in the active code. This is the 169 // place where the call to DebugBreakXXX is and where the IC 170 // normally would be. 171 Address addr = Assembler::target_address_from_return_address(pc()); 172 // Return the address in the original code. This is the place where 173 // the call which has been overwritten by the DebugBreakXXX resides 174 // and the place where the inline cache system should look. 175 intptr_t delta = 176 original_code->instruction_start() - code->instruction_start(); 177 return addr + delta; 178 } 179 #endif 180 181 182 static bool TryRemoveInvalidPrototypeDependentStub(Code* target, 183 Object* receiver, 184 Object* name) { 185 if (target->is_keyed_load_stub() || 186 target->is_keyed_call_stub() || 187 target->is_keyed_store_stub()) { 188 // Determine whether the failure is due to a name failure. 189 if (!name->IsName()) return false; 190 Name* stub_name = target->FindFirstName(); 191 if (Name::cast(name) != stub_name) return false; 192 } 193 194 InlineCacheHolderFlag cache_holder = 195 Code::ExtractCacheHolderFromFlags(target->flags()); 196 197 Isolate* isolate = target->GetIsolate(); 198 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { 199 // The stub was generated for JSObject but called for non-JSObject. 200 // IC::GetCodeCacheHolder is not applicable. 201 return false; 202 } else if (cache_holder == PROTOTYPE_MAP && 203 receiver->GetPrototype(isolate)->IsNull()) { 204 // IC::GetCodeCacheHolder is not applicable. 205 return false; 206 } 207 Map* map = IC::GetCodeCacheHolder(isolate, receiver, cache_holder)->map(); 208 209 // Decide whether the inline cache failed because of changes to the 210 // receiver itself or changes to one of its prototypes. 211 // 212 // If there are changes to the receiver itself, the map of the 213 // receiver will have changed and the current target will not be in 214 // the receiver map's code cache. Therefore, if the current target 215 // is in the receiver map's code cache, the inline cache failed due 216 // to prototype check failure. 217 int index = map->IndexInCodeCache(name, target); 218 if (index >= 0) { 219 map->RemoveFromCodeCache(String::cast(name), target, index); 220 // For loads and stores, handlers are stored in addition to the ICs on the 221 // map. Remove those, too. 222 if ((target->is_load_stub() || target->is_keyed_load_stub() || 223 target->is_store_stub() || target->is_keyed_store_stub()) && 224 target->type() != Code::NORMAL) { 225 Code* handler = target->FindFirstCode(); 226 index = map->IndexInCodeCache(name, handler); 227 if (index >= 0) { 228 map->RemoveFromCodeCache(String::cast(name), handler, index); 229 } 230 } 231 return true; 232 } 233 234 // The stub is not in the cache. We've ruled out all other kinds of failure 235 // except for proptotype chain changes, a deprecated map, a map that's 236 // different from the one that the stub expects, elements kind changes, or a 237 // constant global property that will become mutable. Threat all those 238 // situations as prototype failures (stay monomorphic if possible). 239 240 // If the IC is shared between multiple receivers (slow dictionary mode), then 241 // the map cannot be deprecated and the stub invalidated. 242 if (cache_holder == OWN_MAP) { 243 Map* old_map = target->FindFirstMap(); 244 if (old_map == map) return true; 245 if (old_map != NULL) { 246 if (old_map->is_deprecated()) return true; 247 if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(), 248 map->elements_kind())) { 249 return true; 250 } 251 } 252 } 253 254 if (receiver->IsGlobalObject()) { 255 if (!name->IsName()) return false; 256 Isolate* isolate = target->GetIsolate(); 257 LookupResult lookup(isolate); 258 GlobalObject* global = GlobalObject::cast(receiver); 259 global->LocalLookupRealNamedProperty(Name::cast(name), &lookup); 260 if (!lookup.IsFound()) return false; 261 PropertyCell* cell = global->GetPropertyCell(&lookup); 262 return cell->type()->IsConstant(); 263 } 264 265 return false; 266 } 267 268 269 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { 270 IC::State state = target->ic_state(); 271 272 if (state != MONOMORPHIC || !name->IsString()) return state; 273 if (receiver->IsUndefined() || receiver->IsNull()) return state; 274 275 Code::Kind kind = target->kind(); 276 // Remove the target from the code cache if it became invalid 277 // because of changes in the prototype chain to avoid hitting it 278 // again. 279 // Call stubs handle this later to allow extra IC state 280 // transitions. 281 if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && 282 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { 283 return MONOMORPHIC_PROTOTYPE_FAILURE; 284 } 285 286 // The builtins object is special. It only changes when JavaScript 287 // builtins are loaded lazily. It is important to keep inline 288 // caches for the builtins object monomorphic. Therefore, if we get 289 // an inline cache miss for the builtins object after lazily loading 290 // JavaScript builtins, we return uninitialized as the state to 291 // force the inline cache back to monomorphic state. 292 if (receiver->IsJSBuiltinsObject()) { 293 return UNINITIALIZED; 294 } 295 296 return MONOMORPHIC; 297 } 298 299 300 RelocInfo::Mode IC::ComputeMode() { 301 Address addr = address(); 302 Code* code = Code::cast(isolate()->FindCodeObject(addr)); 303 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); 304 !it.done(); it.next()) { 305 RelocInfo* info = it.rinfo(); 306 if (info->pc() == addr) return info->rmode(); 307 } 308 UNREACHABLE(); 309 return RelocInfo::NONE32; 310 } 311 312 313 Failure* IC::TypeError(const char* type, 314 Handle<Object> object, 315 Handle<Object> key) { 316 HandleScope scope(isolate()); 317 Handle<Object> args[2] = { key, object }; 318 Handle<Object> error = isolate()->factory()->NewTypeError( 319 type, HandleVector(args, 2)); 320 return isolate()->Throw(*error); 321 } 322 323 324 Failure* IC::ReferenceError(const char* type, Handle<String> name) { 325 HandleScope scope(isolate()); 326 Handle<Object> error = isolate()->factory()->NewReferenceError( 327 type, HandleVector(&name, 1)); 328 return isolate()->Throw(*error); 329 } 330 331 332 static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) { 333 bool was_uninitialized = 334 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; 335 bool is_uninitialized = 336 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; 337 return (was_uninitialized && !is_uninitialized) ? 1 : 338 (!was_uninitialized && is_uninitialized) ? -1 : 0; 339 } 340 341 342 void IC::PostPatching(Address address, Code* target, Code* old_target) { 343 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { 344 return; 345 } 346 Isolate* isolate = target->GetHeap()->isolate(); 347 Code* host = isolate-> 348 inner_pointer_to_code_cache()->GetCacheEntry(address)->code; 349 if (host->kind() != Code::FUNCTION) return; 350 351 if (FLAG_type_info_threshold > 0 && 352 old_target->is_inline_cache_stub() && 353 target->is_inline_cache_stub()) { 354 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), 355 target->ic_state()); 356 // Not all Code objects have TypeFeedbackInfo. 357 if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) { 358 TypeFeedbackInfo* info = 359 TypeFeedbackInfo::cast(host->type_feedback_info()); 360 info->change_ic_with_type_info_count(delta); 361 } 362 } 363 if (host->type_feedback_info()->IsTypeFeedbackInfo()) { 364 TypeFeedbackInfo* info = 365 TypeFeedbackInfo::cast(host->type_feedback_info()); 366 info->change_own_type_change_checksum(); 367 } 368 if (FLAG_watch_ic_patching) { 369 host->set_profiler_ticks(0); 370 isolate->runtime_profiler()->NotifyICChanged(); 371 } 372 // TODO(2029): When an optimized function is patched, it would 373 // be nice to propagate the corresponding type information to its 374 // unoptimized version for the benefit of later inlining. 375 } 376 377 378 void IC::Clear(Address address) { 379 Code* target = GetTargetAtAddress(address); 380 381 // Don't clear debug break inline cache as it will remove the break point. 382 if (target->is_debug_stub()) return; 383 384 switch (target->kind()) { 385 case Code::LOAD_IC: return LoadIC::Clear(address, target); 386 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); 387 case Code::STORE_IC: return StoreIC::Clear(address, target); 388 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); 389 case Code::CALL_IC: return CallIC::Clear(address, target); 390 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); 391 case Code::COMPARE_IC: return CompareIC::Clear(address, target); 392 case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target); 393 case Code::BINARY_OP_IC: 394 case Code::TO_BOOLEAN_IC: 395 // Clearing these is tricky and does not 396 // make any performance difference. 397 return; 398 default: UNREACHABLE(); 399 } 400 } 401 402 403 void CallICBase::Clear(Address address, Code* target) { 404 if (target->ic_state() == UNINITIALIZED) return; 405 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state()); 406 Code* code = 407 Isolate::Current()->stub_cache()->FindCallInitialize( 408 target->arguments_count(), 409 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET, 410 target->kind()); 411 SetTargetAtAddress(address, code); 412 } 413 414 415 void KeyedLoadIC::Clear(Address address, Code* target) { 416 if (target->ic_state() == UNINITIALIZED) return; 417 // Make sure to also clear the map used in inline fast cases. If we 418 // do not clear these maps, cached code can keep objects alive 419 // through the embedded maps. 420 SetTargetAtAddress(address, *initialize_stub()); 421 } 422 423 424 void LoadIC::Clear(Address address, Code* target) { 425 if (target->ic_state() == UNINITIALIZED) return; 426 SetTargetAtAddress(address, *initialize_stub()); 427 } 428 429 430 void StoreIC::Clear(Address address, Code* target) { 431 if (target->ic_state() == UNINITIALIZED) return; 432 SetTargetAtAddress(address, 433 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) 434 ? *initialize_stub_strict() 435 : *initialize_stub()); 436 } 437 438 439 void KeyedStoreIC::Clear(Address address, Code* target) { 440 if (target->ic_state() == UNINITIALIZED) return; 441 SetTargetAtAddress(address, 442 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) 443 ? *initialize_stub_strict() 444 : *initialize_stub()); 445 } 446 447 448 void CompareIC::Clear(Address address, Code* target) { 449 ASSERT(target->major_key() == CodeStub::CompareIC); 450 CompareIC::State handler_state; 451 Token::Value op; 452 ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, 453 &handler_state, &op); 454 // Only clear CompareICs that can retain objects. 455 if (handler_state != KNOWN_OBJECT) return; 456 SetTargetAtAddress(address, GetRawUninitialized(op)); 457 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); 458 } 459 460 461 static bool HasInterceptorGetter(JSObject* object) { 462 return !object->GetNamedInterceptor()->getter()->IsUndefined(); 463 } 464 465 466 static void LookupForRead(Handle<Object> object, 467 Handle<String> name, 468 LookupResult* lookup) { 469 // Skip all the objects with named interceptors, but 470 // without actual getter. 471 while (true) { 472 object->Lookup(*name, lookup); 473 // Besides normal conditions (property not found or it's not 474 // an interceptor), bail out if lookup is not cacheable: we won't 475 // be able to IC it anyway and regular lookup should work fine. 476 if (!lookup->IsInterceptor() || !lookup->IsCacheable()) { 477 return; 478 } 479 480 Handle<JSObject> holder(lookup->holder(), lookup->isolate()); 481 if (HasInterceptorGetter(*holder)) { 482 return; 483 } 484 485 holder->LocalLookupRealNamedProperty(*name, lookup); 486 if (lookup->IsFound()) { 487 ASSERT(!lookup->IsInterceptor()); 488 return; 489 } 490 491 Handle<Object> proto(holder->GetPrototype(), lookup->isolate()); 492 if (proto->IsNull()) { 493 ASSERT(!lookup->IsFound()); 494 return; 495 } 496 497 object = proto; 498 } 499 } 500 501 502 Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { 503 Handle<Object> delegate = Execution::GetFunctionDelegate(object); 504 505 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { 506 // Patch the receiver and use the delegate as the function to 507 // invoke. This is used for invoking objects as if they were functions. 508 const int argc = target()->arguments_count(); 509 StackFrameLocator locator(isolate()); 510 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 511 int index = frame->ComputeExpressionsCount() - (argc + 1); 512 frame->SetExpression(index, *object); 513 } 514 515 return delegate; 516 } 517 518 519 void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, 520 Handle<Object> object) { 521 while (callee->IsJSFunctionProxy()) { 522 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(), 523 isolate()); 524 } 525 526 if (callee->IsJSFunction()) { 527 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); 528 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) { 529 // Do not wrap receiver for strict mode functions or for builtins. 530 return; 531 } 532 } 533 534 // And only wrap string, number or boolean. 535 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 536 // Change the receiver to the result of calling ToObject on it. 537 const int argc = this->target()->arguments_count(); 538 StackFrameLocator locator(isolate()); 539 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 540 int index = frame->ComputeExpressionsCount() - (argc + 1); 541 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); 542 } 543 } 544 545 546 MaybeObject* CallICBase::LoadFunction(State state, 547 Code::ExtraICState extra_ic_state, 548 Handle<Object> object, 549 Handle<String> name) { 550 if (object->IsJSObject()) { 551 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 552 if (receiver->map()->is_deprecated()) { 553 JSObject::MigrateInstance(receiver); 554 } 555 } 556 557 // If the object is undefined or null it's illegal to try to get any 558 // of its properties; throw a TypeError in that case. 559 if (object->IsUndefined() || object->IsNull()) { 560 return TypeError("non_object_property_call", object, name); 561 } 562 563 // Check if the name is trivially convertible to an index and get 564 // the element if so. 565 uint32_t index; 566 if (name->AsArrayIndex(&index)) { 567 Handle<Object> result = Object::GetElement(object, index); 568 RETURN_IF_EMPTY_HANDLE(isolate(), result); 569 if (result->IsJSFunction()) return *result; 570 571 // Try to find a suitable function delegate for the object at hand. 572 result = TryCallAsFunction(result); 573 if (result->IsJSFunction()) return *result; 574 575 // Otherwise, it will fail in the lookup step. 576 } 577 578 // Lookup the property in the object. 579 LookupResult lookup(isolate()); 580 LookupForRead(object, name, &lookup); 581 582 if (!lookup.IsFound()) { 583 // If the object does not have the requested property, check which 584 // exception we need to throw. 585 return IsUndeclaredGlobal(object) 586 ? ReferenceError("not_defined", name) 587 : TypeError("undefined_method", object, name); 588 } 589 590 // Lookup is valid: Update inline cache and stub cache. 591 if (FLAG_use_ic) { 592 UpdateCaches(&lookup, state, extra_ic_state, object, name); 593 } 594 595 // Get the property. 596 PropertyAttributes attr; 597 Handle<Object> result = 598 Object::GetProperty(object, object, &lookup, name, &attr); 599 RETURN_IF_EMPTY_HANDLE(isolate(), result); 600 601 if (lookup.IsInterceptor() && attr == ABSENT) { 602 // If the object does not have the requested property, check which 603 // exception we need to throw. 604 return IsUndeclaredGlobal(object) 605 ? ReferenceError("not_defined", name) 606 : TypeError("undefined_method", object, name); 607 } 608 609 ASSERT(!result->IsTheHole()); 610 611 // Make receiver an object if the callee requires it. Strict mode or builtin 612 // functions do not wrap the receiver, non-strict functions and objects 613 // called as functions do. 614 ReceiverToObjectIfRequired(result, object); 615 616 if (result->IsJSFunction()) { 617 Handle<JSFunction> function = Handle<JSFunction>::cast(result); 618 #ifdef ENABLE_DEBUGGER_SUPPORT 619 // Handle stepping into a function if step into is active. 620 Debug* debug = isolate()->debug(); 621 if (debug->StepInActive()) { 622 // Protect the result in a handle as the debugger can allocate and might 623 // cause GC. 624 debug->HandleStepIn(function, object, fp(), false); 625 } 626 #endif 627 return *function; 628 } 629 630 // Try to find a suitable function delegate for the object at hand. 631 result = TryCallAsFunction(result); 632 if (result->IsJSFunction()) return *result; 633 634 return TypeError("property_not_function", object, name); 635 } 636 637 638 bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, 639 Handle<Object> object, 640 Code::ExtraICState* extra_ic_state) { 641 ASSERT(kind_ == Code::CALL_IC); 642 if (!lookup->IsConstantFunction()) return false; 643 JSFunction* function = lookup->GetConstantFunction(); 644 if (!function->shared()->HasBuiltinFunctionId()) return false; 645 646 // Fetch the arguments passed to the called function. 647 const int argc = target()->arguments_count(); 648 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); 649 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 650 Arguments args(argc + 1, 651 &Memory::Object_at(fp + 652 StandardFrameConstants::kCallerSPOffset + 653 argc * kPointerSize)); 654 switch (function->shared()->builtin_function_id()) { 655 case kStringCharCodeAt: 656 case kStringCharAt: 657 if (object->IsString()) { 658 String* string = String::cast(*object); 659 // Check there's the right string value or wrapper in the receiver slot. 660 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); 661 // If we're in the default (fastest) state and the index is 662 // out of bounds, update the state to record this fact. 663 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB && 664 argc >= 1 && args[1]->IsNumber()) { 665 double index = DoubleToInteger(args.number_at(1)); 666 if (index < 0 || index >= string->length()) { 667 *extra_ic_state = 668 StringStubState::update(*extra_ic_state, 669 STRING_INDEX_OUT_OF_BOUNDS); 670 return true; 671 } 672 } 673 } 674 break; 675 default: 676 return false; 677 } 678 return false; 679 } 680 681 682 Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, 683 State state, 684 Code::ExtraICState extra_state, 685 Handle<Object> object, 686 Handle<String> name) { 687 int argc = target()->arguments_count(); 688 Handle<JSObject> holder(lookup->holder(), isolate()); 689 switch (lookup->type()) { 690 case FIELD: { 691 PropertyIndex index = lookup->GetFieldIndex(); 692 return isolate()->stub_cache()->ComputeCallField( 693 argc, kind_, extra_state, name, object, holder, index); 694 } 695 case CONSTANT: { 696 if (!lookup->IsConstantFunction()) return Handle<Code>::null(); 697 // Get the constant function and compute the code stub for this 698 // call; used for rewriting to monomorphic state and making sure 699 // that the code stub is in the stub cache. 700 Handle<JSFunction> function(lookup->GetConstantFunction(), isolate()); 701 return isolate()->stub_cache()->ComputeCallConstant( 702 argc, kind_, extra_state, name, object, holder, function); 703 } 704 case NORMAL: { 705 // If we return a null handle, the IC will not be patched. 706 if (!object->IsJSObject()) return Handle<Code>::null(); 707 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 708 709 if (holder->IsGlobalObject()) { 710 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 711 Handle<PropertyCell> cell( 712 global->GetPropertyCell(lookup), isolate()); 713 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); 714 Handle<JSFunction> function(JSFunction::cast(cell->value())); 715 return isolate()->stub_cache()->ComputeCallGlobal( 716 argc, kind_, extra_state, name, receiver, global, cell, function); 717 } else { 718 // There is only one shared stub for calling normalized 719 // properties. It does not traverse the prototype chain, so the 720 // property must be found in the receiver for the stub to be 721 // applicable. 722 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); 723 return isolate()->stub_cache()->ComputeCallNormal( 724 argc, kind_, extra_state); 725 } 726 break; 727 } 728 case INTERCEPTOR: 729 ASSERT(HasInterceptorGetter(*holder)); 730 return isolate()->stub_cache()->ComputeCallInterceptor( 731 argc, kind_, extra_state, name, object, holder); 732 default: 733 return Handle<Code>::null(); 734 } 735 } 736 737 738 void CallICBase::UpdateCaches(LookupResult* lookup, 739 State state, 740 Code::ExtraICState extra_ic_state, 741 Handle<Object> object, 742 Handle<String> name) { 743 // Bail out if we didn't find a result. 744 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; 745 746 // Compute the number of arguments. 747 int argc = target()->arguments_count(); 748 Handle<Code> code; 749 if (state == UNINITIALIZED) { 750 // This is the first time we execute this inline cache. 751 // Set the target to the pre monomorphic stub to delay 752 // setting the monomorphic state. 753 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( 754 argc, kind_, extra_ic_state); 755 } else if (state == MONOMORPHIC) { 756 if (kind_ == Code::CALL_IC && 757 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { 758 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 759 object, name); 760 } else if (TryRemoveInvalidPrototypeDependentStub(target(), 761 *object, 762 *name)) { 763 state = MONOMORPHIC_PROTOTYPE_FAILURE; 764 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 765 object, name); 766 } else { 767 code = isolate()->stub_cache()->ComputeCallMegamorphic( 768 argc, kind_, extra_ic_state); 769 } 770 } else { 771 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 772 object, name); 773 } 774 775 // If there's no appropriate stub we simply avoid updating the caches. 776 if (code.is_null()) return; 777 778 // Patch the call site depending on the state of the cache. 779 switch (state) { 780 case UNINITIALIZED: 781 case MONOMORPHIC_PROTOTYPE_FAILURE: 782 case PREMONOMORPHIC: 783 case MONOMORPHIC: 784 set_target(*code); 785 break; 786 case MEGAMORPHIC: { 787 // Cache code holding map should be consistent with 788 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. 789 Handle<JSObject> cache_object = object->IsJSObject() 790 ? Handle<JSObject>::cast(object) 791 : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())), 792 isolate()); 793 // Update the stub cache. 794 UpdateMegamorphicCache(cache_object->map(), *name, *code); 795 break; 796 } 797 case DEBUG_STUB: 798 break; 799 case POLYMORPHIC: 800 case GENERIC: 801 UNREACHABLE(); 802 break; 803 } 804 805 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", 806 name, state, target()); 807 } 808 809 810 MaybeObject* KeyedCallIC::LoadFunction(State state, 811 Handle<Object> object, 812 Handle<Object> key) { 813 if (key->IsInternalizedString()) { 814 return CallICBase::LoadFunction(state, 815 Code::kNoExtraICState, 816 object, 817 Handle<String>::cast(key)); 818 } 819 820 if (object->IsJSObject()) { 821 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 822 if (receiver->map()->is_deprecated()) { 823 JSObject::MigrateInstance(receiver); 824 } 825 } 826 827 if (object->IsUndefined() || object->IsNull()) { 828 return TypeError("non_object_property_call", object, key); 829 } 830 831 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 832 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 833 834 if (use_ic && state != MEGAMORPHIC) { 835 int argc = target()->arguments_count(); 836 Handle<Code> stub = isolate()->stub_cache()->ComputeCallMegamorphic( 837 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); 838 if (object->IsJSObject()) { 839 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 840 if (receiver->elements()->map() == 841 isolate()->heap()->non_strict_arguments_elements_map()) { 842 stub = isolate()->stub_cache()->ComputeCallArguments(argc); 843 } 844 } 845 ASSERT(!stub.is_null()); 846 set_target(*stub); 847 TRACE_IC("KeyedCallIC", key, state, target()); 848 } 849 850 Handle<Object> result = GetProperty(isolate(), object, key); 851 RETURN_IF_EMPTY_HANDLE(isolate(), result); 852 853 // Make receiver an object if the callee requires it. Strict mode or builtin 854 // functions do not wrap the receiver, non-strict functions and objects 855 // called as functions do. 856 ReceiverToObjectIfRequired(result, object); 857 if (result->IsJSFunction()) return *result; 858 859 result = TryCallAsFunction(result); 860 if (result->IsJSFunction()) return *result; 861 862 return TypeError("property_not_function", object, key); 863 } 864 865 866 MaybeObject* LoadIC::Load(State state, 867 Handle<Object> object, 868 Handle<String> name) { 869 // If the object is undefined or null it's illegal to try to get any 870 // of its properties; throw a TypeError in that case. 871 if (object->IsUndefined() || object->IsNull()) { 872 return TypeError("non_object_property_load", object, name); 873 } 874 875 if (FLAG_use_ic) { 876 // Use specialized code for getting the length of strings and 877 // string wrapper objects. The length property of string wrapper 878 // objects is read-only and therefore always returns the length of 879 // the underlying string value. See ECMA-262 15.5.5.1. 880 if ((object->IsString() || object->IsStringWrapper()) && 881 name->Equals(isolate()->heap()->length_string())) { 882 Handle<Code> stub; 883 if (state == UNINITIALIZED) { 884 stub = pre_monomorphic_stub(); 885 } else if (state == PREMONOMORPHIC) { 886 StringLengthStub string_length_stub(kind(), !object->IsString()); 887 stub = string_length_stub.GetCode(isolate()); 888 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { 889 StringLengthStub string_length_stub(kind(), true); 890 stub = string_length_stub.GetCode(isolate()); 891 } else if (state != MEGAMORPHIC) { 892 ASSERT(state != GENERIC); 893 stub = megamorphic_stub(); 894 } 895 if (!stub.is_null()) { 896 set_target(*stub); 897 #ifdef DEBUG 898 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); 899 #endif 900 } 901 // Get the string if we have a string wrapper object. 902 Handle<Object> string = object->IsJSValue() 903 ? Handle<Object>(Handle<JSValue>::cast(object)->value(), isolate()) 904 : object; 905 return Smi::FromInt(String::cast(*string)->length()); 906 } 907 908 // Use specialized code for getting prototype of functions. 909 if (object->IsJSFunction() && 910 name->Equals(isolate()->heap()->prototype_string()) && 911 Handle<JSFunction>::cast(object)->should_have_prototype()) { 912 Handle<Code> stub; 913 if (state == UNINITIALIZED) { 914 stub = pre_monomorphic_stub(); 915 } else if (state == PREMONOMORPHIC) { 916 FunctionPrototypeStub function_prototype_stub(kind()); 917 stub = function_prototype_stub.GetCode(isolate()); 918 } else if (state != MEGAMORPHIC) { 919 ASSERT(state != GENERIC); 920 stub = megamorphic_stub(); 921 } 922 if (!stub.is_null()) { 923 set_target(*stub); 924 #ifdef DEBUG 925 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); 926 #endif 927 } 928 return *Accessors::FunctionGetPrototype(object); 929 } 930 } 931 932 // Check if the name is trivially convertible to an index and get 933 // the element or char if so. 934 uint32_t index; 935 if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) { 936 // Rewrite to the generic keyed load stub. 937 if (FLAG_use_ic) set_target(*generic_stub()); 938 return Runtime::GetElementOrCharAtOrFail(isolate(), object, index); 939 } 940 941 if (object->IsJSObject()) { 942 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 943 if (receiver->map()->is_deprecated()) { 944 JSObject::MigrateInstance(receiver); 945 } 946 } 947 948 // Named lookup in the object. 949 LookupResult lookup(isolate()); 950 LookupForRead(object, name, &lookup); 951 952 // If we did not find a property, check if we need to throw an exception. 953 if (!lookup.IsFound()) { 954 if (IsUndeclaredGlobal(object)) { 955 return ReferenceError("not_defined", name); 956 } 957 LOG(isolate(), SuspectReadEvent(*name, *object)); 958 } 959 960 // Update inline cache and stub cache. 961 if (FLAG_use_ic) UpdateCaches(&lookup, state, object, name); 962 963 PropertyAttributes attr; 964 if (lookup.IsInterceptor() || lookup.IsHandler()) { 965 // Get the property. 966 Handle<Object> result = 967 Object::GetProperty(object, object, &lookup, name, &attr); 968 RETURN_IF_EMPTY_HANDLE(isolate(), result); 969 // If the property is not present, check if we need to throw an 970 // exception. 971 if (attr == ABSENT && IsUndeclaredGlobal(object)) { 972 return ReferenceError("not_defined", name); 973 } 974 return *result; 975 } 976 977 // Get the property. 978 return Object::GetPropertyOrFail(object, object, &lookup, name, &attr); 979 } 980 981 982 static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, 983 Handle<Map> new_receiver_map) { 984 ASSERT(!new_receiver_map.is_null()); 985 for (int current = 0; current < receiver_maps->length(); ++current) { 986 if (!receiver_maps->at(current).is_null() && 987 receiver_maps->at(current).is_identical_to(new_receiver_map)) { 988 return false; 989 } 990 } 991 receiver_maps->Add(new_receiver_map); 992 return true; 993 } 994 995 996 bool IC::UpdatePolymorphicIC(State state, 997 Handle<JSObject> receiver, 998 Handle<String> name, 999 Handle<Code> code, 1000 StrictModeFlag strict_mode) { 1001 if (code->type() == Code::NORMAL) return false; 1002 if (target()->ic_state() == MONOMORPHIC && 1003 target()->type() == Code::NORMAL) { 1004 return false; 1005 } 1006 1007 MapHandleList receiver_maps; 1008 CodeHandleList handlers; 1009 1010 int number_of_valid_maps; 1011 int handler_to_overwrite = -1; 1012 Handle<Map> new_receiver_map(receiver->map()); 1013 { 1014 DisallowHeapAllocation no_gc; 1015 target()->FindAllMaps(&receiver_maps); 1016 int number_of_maps = receiver_maps.length(); 1017 number_of_valid_maps = number_of_maps; 1018 1019 for (int i = 0; i < number_of_maps; i++) { 1020 Handle<Map> map = receiver_maps.at(i); 1021 // Filter out deprecated maps to ensure its instances get migrated. 1022 if (map->is_deprecated()) { 1023 number_of_valid_maps--; 1024 // If the receiver map is already in the polymorphic IC, this indicates 1025 // there was a prototoype chain failure. In that case, just overwrite the 1026 // handler. 1027 } else if (map.is_identical_to(new_receiver_map)) { 1028 number_of_valid_maps--; 1029 handler_to_overwrite = i; 1030 } 1031 } 1032 1033 if (number_of_valid_maps >= 4) return false; 1034 1035 // Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. 1036 // In that case, allow the IC to go back monomorphic. 1037 if (number_of_maps == 0 && target()->ic_state() != UNINITIALIZED) { 1038 return false; 1039 } 1040 target()->FindAllCode(&handlers, receiver_maps.length()); 1041 } 1042 1043 number_of_valid_maps++; 1044 if (handler_to_overwrite >= 0) { 1045 handlers.Set(handler_to_overwrite, code); 1046 } else { 1047 receiver_maps.Add(new_receiver_map); 1048 handlers.Add(code); 1049 } 1050 1051 Handle<Code> ic = ComputePolymorphicIC( 1052 &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode); 1053 set_target(*ic); 1054 return true; 1055 } 1056 1057 1058 Handle<Code> LoadIC::ComputePolymorphicIC(MapHandleList* receiver_maps, 1059 CodeHandleList* handlers, 1060 int number_of_valid_maps, 1061 Handle<Name> name, 1062 StrictModeFlag strict_mode) { 1063 return isolate()->stub_cache()->ComputePolymorphicLoadIC( 1064 receiver_maps, handlers, number_of_valid_maps, name); 1065 } 1066 1067 1068 Handle<Code> StoreIC::ComputePolymorphicIC(MapHandleList* receiver_maps, 1069 CodeHandleList* handlers, 1070 int number_of_valid_maps, 1071 Handle<Name> name, 1072 StrictModeFlag strict_mode) { 1073 return isolate()->stub_cache()->ComputePolymorphicStoreIC( 1074 receiver_maps, handlers, number_of_valid_maps, name, strict_mode); 1075 } 1076 1077 1078 void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, 1079 Handle<Code> handler, 1080 Handle<String> name, 1081 StrictModeFlag strict_mode) { 1082 if (handler->type() == Code::NORMAL) return set_target(*handler); 1083 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC( 1084 receiver, handler, name); 1085 set_target(*ic); 1086 } 1087 1088 1089 void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, 1090 Handle<Code> handler, 1091 Handle<String> name, 1092 StrictModeFlag strict_mode) { 1093 if (handler->type() == Code::NORMAL) return set_target(*handler); 1094 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC( 1095 receiver, handler, name); 1096 set_target(*ic); 1097 } 1098 1099 1100 void StoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver, 1101 Handle<Code> handler, 1102 Handle<String> name, 1103 StrictModeFlag strict_mode) { 1104 if (handler->type() == Code::NORMAL) return set_target(*handler); 1105 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC( 1106 receiver, handler, name, strict_mode); 1107 set_target(*ic); 1108 } 1109 1110 1111 void KeyedStoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver, 1112 Handle<Code> handler, 1113 Handle<String> name, 1114 StrictModeFlag strict_mode) { 1115 if (handler->type() == Code::NORMAL) return set_target(*handler); 1116 Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC( 1117 receiver, handler, name, strict_mode); 1118 set_target(*ic); 1119 } 1120 1121 1122 void IC::CopyICToMegamorphicCache(Handle<String> name) { 1123 MapHandleList receiver_maps; 1124 CodeHandleList handlers; 1125 { 1126 DisallowHeapAllocation no_gc; 1127 target()->FindAllMaps(&receiver_maps); 1128 target()->FindAllCode(&handlers, receiver_maps.length()); 1129 } 1130 for (int i = 0; i < receiver_maps.length(); i++) { 1131 UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); 1132 } 1133 } 1134 1135 1136 bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) { 1137 DisallowHeapAllocation no_allocation; 1138 1139 Map* current_map = target()->FindFirstMap(); 1140 ElementsKind receiver_elements_kind = receiver_map->elements_kind(); 1141 bool more_general_transition = 1142 IsMoreGeneralElementsKindTransition( 1143 current_map->elements_kind(), receiver_elements_kind); 1144 Map* transitioned_map = more_general_transition 1145 ? current_map->LookupElementsTransitionMap(receiver_elements_kind) 1146 : NULL; 1147 1148 return transitioned_map == receiver_map; 1149 } 1150 1151 1152 // Since GC may have been invoked, by the time PatchCache is called, |state| is 1153 // not necessarily equal to target()->state(). 1154 void IC::PatchCache(State state, 1155 StrictModeFlag strict_mode, 1156 Handle<JSObject> receiver, 1157 Handle<String> name, 1158 Handle<Code> code) { 1159 switch (state) { 1160 case UNINITIALIZED: 1161 case PREMONOMORPHIC: 1162 case MONOMORPHIC_PROTOTYPE_FAILURE: 1163 UpdateMonomorphicIC(receiver, code, name, strict_mode); 1164 break; 1165 case MONOMORPHIC: 1166 // Only move to megamorphic if the target changes. 1167 if (target() != *code) { 1168 if (target()->is_load_stub() || target()->is_store_stub()) { 1169 bool is_same_handler = false; 1170 { 1171 DisallowHeapAllocation no_allocation; 1172 Code* old_handler = target()->FindFirstCode(); 1173 is_same_handler = old_handler == *code; 1174 } 1175 if (is_same_handler 1176 && IsTransitionedMapOfMonomorphicTarget(receiver->map())) { 1177 UpdateMonomorphicIC(receiver, code, name, strict_mode); 1178 break; 1179 } 1180 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { 1181 break; 1182 } 1183 1184 if (target()->type() != Code::NORMAL) { 1185 CopyICToMegamorphicCache(name); 1186 } 1187 } 1188 1189 UpdateMegamorphicCache(receiver->map(), *name, *code); 1190 set_target((strict_mode == kStrictMode) 1191 ? *megamorphic_stub_strict() 1192 : *megamorphic_stub()); 1193 } 1194 break; 1195 case MEGAMORPHIC: 1196 // Update the stub cache. 1197 UpdateMegamorphicCache(receiver->map(), *name, *code); 1198 break; 1199 case POLYMORPHIC: 1200 if (target()->is_load_stub() || target()->is_store_stub()) { 1201 if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) { 1202 break; 1203 } 1204 CopyICToMegamorphicCache(name); 1205 UpdateMegamorphicCache(receiver->map(), *name, *code); 1206 set_target((strict_mode == kStrictMode) 1207 ? *megamorphic_stub_strict() 1208 : *megamorphic_stub()); 1209 } else { 1210 // When trying to patch a polymorphic keyed load/store element stub 1211 // with anything other than another polymorphic stub, go generic. 1212 set_target((strict_mode == kStrictMode) 1213 ? *generic_stub_strict() 1214 : *generic_stub()); 1215 } 1216 break; 1217 case DEBUG_STUB: 1218 break; 1219 case GENERIC: 1220 UNREACHABLE(); 1221 break; 1222 } 1223 } 1224 1225 1226 static void GetReceiverMapsForStub(Handle<Code> stub, 1227 MapHandleList* result) { 1228 ASSERT(stub->is_inline_cache_stub()); 1229 switch (stub->ic_state()) { 1230 case MONOMORPHIC: { 1231 Map* map = stub->FindFirstMap(); 1232 if (map != NULL) { 1233 result->Add(Handle<Map>(map)); 1234 } 1235 break; 1236 } 1237 case POLYMORPHIC: { 1238 DisallowHeapAllocation no_allocation; 1239 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 1240 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { 1241 RelocInfo* info = it.rinfo(); 1242 Handle<Object> object(info->target_object(), stub->GetIsolate()); 1243 if (object->IsString()) break; 1244 ASSERT(object->IsMap()); 1245 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); 1246 } 1247 break; 1248 } 1249 case MEGAMORPHIC: 1250 break; 1251 case UNINITIALIZED: 1252 case PREMONOMORPHIC: 1253 case MONOMORPHIC_PROTOTYPE_FAILURE: 1254 case GENERIC: 1255 case DEBUG_STUB: 1256 UNREACHABLE(); 1257 break; 1258 } 1259 } 1260 1261 1262 void LoadIC::UpdateCaches(LookupResult* lookup, 1263 State state, 1264 Handle<Object> object, 1265 Handle<String> name) { 1266 // Bail out if the result is not cacheable. 1267 if (!lookup->IsCacheable()) { 1268 set_target(*generic_stub()); 1269 return; 1270 } 1271 1272 // TODO(jkummerow): It would be nice to support non-JSObjects in 1273 // UpdateCaches, then we wouldn't need to go generic here. 1274 if (!object->IsJSObject()) { 1275 set_target(*generic_stub()); 1276 return; 1277 } 1278 1279 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1280 Handle<Code> code; 1281 if (state == UNINITIALIZED) { 1282 // This is the first time we execute this inline cache. 1283 // Set the target to the pre monomorphic stub to delay 1284 // setting the monomorphic state. 1285 code = pre_monomorphic_stub(); 1286 } else { 1287 code = ComputeLoadHandler(lookup, receiver, name); 1288 if (code.is_null()) { 1289 set_target(*generic_stub()); 1290 return; 1291 } 1292 } 1293 1294 PatchCache(state, kNonStrictMode, receiver, name, code); 1295 TRACE_IC("LoadIC", name, state, target()); 1296 } 1297 1298 1299 void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) { 1300 // Cache code holding map should be consistent with 1301 // GenerateMonomorphicCacheProbe. 1302 isolate()->stub_cache()->Set(name, map, code); 1303 } 1304 1305 1306 Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, 1307 Handle<JSObject> receiver, 1308 Handle<String> name) { 1309 if (!lookup->IsProperty()) { 1310 // Nonexistent property. The result is undefined. 1311 return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); 1312 } 1313 1314 // Compute monomorphic stub. 1315 Handle<JSObject> holder(lookup->holder()); 1316 switch (lookup->type()) { 1317 case FIELD: 1318 return isolate()->stub_cache()->ComputeLoadField( 1319 name, receiver, holder, 1320 lookup->GetFieldIndex(), lookup->representation()); 1321 case CONSTANT: { 1322 Handle<Object> constant(lookup->GetConstant(), isolate()); 1323 // TODO(2803): Don't compute a stub for cons strings because they cannot 1324 // be embedded into code. 1325 if (constant->IsConsString()) return Handle<Code>::null(); 1326 return isolate()->stub_cache()->ComputeLoadConstant( 1327 name, receiver, holder, constant); 1328 } 1329 case NORMAL: 1330 if (holder->IsGlobalObject()) { 1331 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 1332 Handle<PropertyCell> cell( 1333 global->GetPropertyCell(lookup), isolate()); 1334 return isolate()->stub_cache()->ComputeLoadGlobal( 1335 name, receiver, global, cell, lookup->IsDontDelete()); 1336 } 1337 // There is only one shared stub for loading normalized 1338 // properties. It does not traverse the prototype chain, so the 1339 // property must be found in the receiver for the stub to be 1340 // applicable. 1341 if (!holder.is_identical_to(receiver)) break; 1342 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); 1343 case CALLBACKS: { 1344 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); 1345 if (callback->IsExecutableAccessorInfo()) { 1346 Handle<ExecutableAccessorInfo> info = 1347 Handle<ExecutableAccessorInfo>::cast(callback); 1348 if (v8::ToCData<Address>(info->getter()) == 0) break; 1349 if (!info->IsCompatibleReceiver(*receiver)) break; 1350 return isolate()->stub_cache()->ComputeLoadCallback( 1351 name, receiver, holder, info); 1352 } else if (callback->IsAccessorPair()) { 1353 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), 1354 isolate()); 1355 if (!getter->IsJSFunction()) break; 1356 if (holder->IsGlobalObject()) break; 1357 if (!holder->HasFastProperties()) break; 1358 return isolate()->stub_cache()->ComputeLoadViaGetter( 1359 name, receiver, holder, Handle<JSFunction>::cast(getter)); 1360 } else if (receiver->IsJSArray() && 1361 name->Equals(isolate()->heap()->length_string())) { 1362 PropertyIndex lengthIndex = 1363 PropertyIndex::NewHeaderIndex(JSArray::kLengthOffset / kPointerSize); 1364 return isolate()->stub_cache()->ComputeLoadField( 1365 name, receiver, holder, lengthIndex, Representation::Tagged()); 1366 } 1367 // TODO(dcarney): Handle correctly. 1368 if (callback->IsDeclaredAccessorInfo()) break; 1369 ASSERT(callback->IsForeign()); 1370 // No IC support for old-style native accessors. 1371 break; 1372 } 1373 case INTERCEPTOR: 1374 ASSERT(HasInterceptorGetter(*holder)); 1375 return isolate()->stub_cache()->ComputeLoadInterceptor( 1376 name, receiver, holder); 1377 default: 1378 break; 1379 } 1380 return Handle<Code>::null(); 1381 } 1382 1383 1384 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { 1385 // This helper implements a few common fast cases for converting 1386 // non-smi keys of keyed loads/stores to a smi or a string. 1387 if (key->IsHeapNumber()) { 1388 double value = Handle<HeapNumber>::cast(key)->value(); 1389 if (std::isnan(value)) { 1390 key = isolate->factory()->nan_string(); 1391 } else { 1392 int int_value = FastD2I(value); 1393 if (value == int_value && Smi::IsValid(int_value)) { 1394 key = Handle<Smi>(Smi::FromInt(int_value), isolate); 1395 } 1396 } 1397 } else if (key->IsUndefined()) { 1398 key = isolate->factory()->undefined_string(); 1399 } 1400 return key; 1401 } 1402 1403 1404 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { 1405 State ic_state = target()->ic_state(); 1406 1407 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS 1408 // via megamorphic stubs, since they don't have a map in their relocation info 1409 // and so the stubs can't be harvested for the object needed for a map check. 1410 if (target()->type() != Code::NORMAL) { 1411 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); 1412 return generic_stub(); 1413 } 1414 1415 Handle<Map> receiver_map(receiver->map(), isolate()); 1416 MapHandleList target_receiver_maps; 1417 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { 1418 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state 1419 // yet will do so and stay there. 1420 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); 1421 } 1422 1423 if (target() == *string_stub()) { 1424 target_receiver_maps.Add(isolate()->factory()->string_map()); 1425 } else { 1426 GetReceiverMapsForStub(Handle<Code>(target(), isolate()), 1427 &target_receiver_maps); 1428 if (target_receiver_maps.length() == 0) { 1429 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); 1430 } 1431 } 1432 1433 // The first time a receiver is seen that is a transitioned version of the 1434 // previous monomorphic receiver type, assume the new ElementsKind is the 1435 // monomorphic type. This benefits global arrays that only transition 1436 // once, and all call sites accessing them are faster if they remain 1437 // monomorphic. If this optimistic assumption is not true, the IC will 1438 // miss again and it will become polymorphic and support both the 1439 // untransitioned and transitioned maps. 1440 if (ic_state == MONOMORPHIC && 1441 IsMoreGeneralElementsKindTransition( 1442 target_receiver_maps.at(0)->elements_kind(), 1443 receiver->GetElementsKind())) { 1444 return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map); 1445 } 1446 1447 ASSERT(ic_state != GENERIC); 1448 1449 // Determine the list of receiver maps that this call site has seen, 1450 // adding the map that was just encountered. 1451 if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) { 1452 // If the miss wasn't due to an unseen map, a polymorphic stub 1453 // won't help, use the generic stub. 1454 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); 1455 return generic_stub(); 1456 } 1457 1458 // If the maximum number of receiver maps has been exceeded, use the generic 1459 // version of the IC. 1460 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { 1461 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); 1462 return generic_stub(); 1463 } 1464 1465 return isolate()->stub_cache()->ComputeLoadElementPolymorphic( 1466 &target_receiver_maps); 1467 } 1468 1469 1470 MaybeObject* KeyedLoadIC::Load(State state, 1471 Handle<Object> object, 1472 Handle<Object> key, 1473 ICMissMode miss_mode) { 1474 // Check for values that can be converted into an internalized string directly 1475 // or is representable as a smi. 1476 key = TryConvertKey(key, isolate()); 1477 1478 if (key->IsInternalizedString()) { 1479 return LoadIC::Load(state, object, Handle<String>::cast(key)); 1480 } 1481 1482 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1483 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 1484 1485 if (use_ic) { 1486 Handle<Code> stub = generic_stub(); 1487 if (miss_mode != MISS_FORCE_GENERIC) { 1488 if (object->IsString() && key->IsNumber()) { 1489 if (state == UNINITIALIZED) { 1490 stub = string_stub(); 1491 } 1492 } else if (object->IsJSObject()) { 1493 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1494 if (receiver->map()->is_deprecated()) { 1495 JSObject::MigrateInstance(receiver); 1496 } 1497 1498 if (receiver->elements()->map() == 1499 isolate()->heap()->non_strict_arguments_elements_map()) { 1500 stub = non_strict_arguments_stub(); 1501 } else if (receiver->HasIndexedInterceptor()) { 1502 stub = indexed_interceptor_stub(); 1503 } else if (!key->ToSmi()->IsFailure() && 1504 (target() != *non_strict_arguments_stub())) { 1505 stub = LoadElementStub(receiver); 1506 } 1507 } 1508 } else { 1509 TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic"); 1510 } 1511 ASSERT(!stub.is_null()); 1512 set_target(*stub); 1513 TRACE_IC("KeyedLoadIC", key, state, target()); 1514 } 1515 1516 1517 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); 1518 } 1519 1520 1521 Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, 1522 Handle<JSObject> receiver, 1523 Handle<String> name) { 1524 // Bail out if we didn't find a result. 1525 if (!lookup->IsProperty()) return Handle<Code>::null(); 1526 1527 // Compute a monomorphic stub. 1528 Handle<JSObject> holder(lookup->holder(), isolate()); 1529 switch (lookup->type()) { 1530 case FIELD: 1531 return isolate()->stub_cache()->ComputeKeyedLoadField( 1532 name, receiver, holder, 1533 lookup->GetFieldIndex(), lookup->representation()); 1534 case CONSTANT: { 1535 Handle<Object> constant(lookup->GetConstant(), isolate()); 1536 // TODO(2803): Don't compute a stub for cons strings because they cannot 1537 // be embedded into code. 1538 if (constant->IsConsString()) return Handle<Code>::null(); 1539 return isolate()->stub_cache()->ComputeKeyedLoadConstant( 1540 name, receiver, holder, constant); 1541 } 1542 case CALLBACKS: { 1543 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate()); 1544 // TODO(dcarney): Handle DeclaredAccessorInfo correctly. 1545 if (!callback_object->IsExecutableAccessorInfo()) break; 1546 Handle<ExecutableAccessorInfo> callback = 1547 Handle<ExecutableAccessorInfo>::cast(callback_object); 1548 if (v8::ToCData<Address>(callback->getter()) == 0) break; 1549 if (!callback->IsCompatibleReceiver(*receiver)) break; 1550 return isolate()->stub_cache()->ComputeKeyedLoadCallback( 1551 name, receiver, holder, callback); 1552 } 1553 case INTERCEPTOR: 1554 ASSERT(HasInterceptorGetter(lookup->holder())); 1555 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( 1556 name, receiver, holder); 1557 default: 1558 // Always rewrite to the generic case so that we do not 1559 // repeatedly try to rewrite. 1560 return generic_stub(); 1561 } 1562 return Handle<Code>::null(); 1563 } 1564 1565 1566 static bool LookupForWrite(Handle<JSObject> receiver, 1567 Handle<String> name, 1568 Handle<Object> value, 1569 LookupResult* lookup, 1570 IC::State* state) { 1571 Handle<JSObject> holder = receiver; 1572 receiver->Lookup(*name, lookup); 1573 if (lookup->IsFound()) { 1574 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; 1575 1576 if (lookup->holder() == *receiver) { 1577 if (lookup->IsInterceptor() && 1578 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { 1579 receiver->LocalLookupRealNamedProperty(*name, lookup); 1580 return lookup->IsFound() && 1581 !lookup->IsReadOnly() && 1582 lookup->CanHoldValue(value) && 1583 lookup->IsCacheable(); 1584 } 1585 return lookup->CanHoldValue(value); 1586 } 1587 1588 if (lookup->IsPropertyCallbacks()) return true; 1589 1590 // Currently normal holders in the prototype chain are not supported. They 1591 // would require a runtime positive lookup and verification that the details 1592 // have not changed. 1593 if (lookup->IsInterceptor() || lookup->IsNormal()) return false; 1594 holder = Handle<JSObject>(lookup->holder(), lookup->isolate()); 1595 } 1596 1597 // While normally LookupTransition gets passed the receiver, in this case we 1598 // pass the holder of the property that we overwrite. This keeps the holder in 1599 // the LookupResult intact so we can later use it to generate a prototype 1600 // chain check. This avoids a double lookup, but requires us to pass in the 1601 // receiver when trying to fetch extra information from the transition. 1602 receiver->map()->LookupTransition(*holder, *name, lookup); 1603 if (!lookup->IsTransition()) return false; 1604 PropertyDetails target_details = 1605 lookup->GetTransitionDetails(receiver->map()); 1606 if (target_details.IsReadOnly()) return false; 1607 1608 // If the value that's being stored does not fit in the field that the 1609 // instance would transition to, create a new transition that fits the value. 1610 // This has to be done before generating the IC, since that IC will embed the 1611 // transition target. 1612 // Ensure the instance and its map were migrated before trying to update the 1613 // transition target. 1614 ASSERT(!receiver->map()->is_deprecated()); 1615 if (!value->FitsRepresentation(target_details.representation())) { 1616 Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); 1617 Map::GeneralizeRepresentation( 1618 target, target->LastAdded(), value->OptimalRepresentation()); 1619 // Lookup the transition again since the transition tree may have changed 1620 // entirely by the migration above. 1621 receiver->map()->LookupTransition(*holder, *name, lookup); 1622 if (!lookup->IsTransition()) return false; 1623 *state = MONOMORPHIC_PROTOTYPE_FAILURE; 1624 } 1625 return true; 1626 } 1627 1628 1629 MaybeObject* StoreIC::Store(State state, 1630 StrictModeFlag strict_mode, 1631 Handle<Object> object, 1632 Handle<String> name, 1633 Handle<Object> value, 1634 JSReceiver::StoreFromKeyed store_mode) { 1635 // Handle proxies. 1636 if (object->IsJSProxy()) { 1637 return JSReceiver::SetPropertyOrFail( 1638 Handle<JSReceiver>::cast(object), name, value, NONE, strict_mode); 1639 } 1640 1641 // If the object is undefined or null it's illegal to try to set any 1642 // properties on it; throw a TypeError in that case. 1643 if (object->IsUndefined() || object->IsNull()) { 1644 return TypeError("non_object_property_store", object, name); 1645 } 1646 1647 // The length property of string values is read-only. Throw in strict mode. 1648 if (strict_mode == kStrictMode && object->IsString() && 1649 name->Equals(isolate()->heap()->length_string())) { 1650 return TypeError("strict_read_only_property", object, name); 1651 } 1652 1653 // Ignore other stores where the receiver is not a JSObject. 1654 // TODO(1475): Must check prototype chains of object wrappers. 1655 if (!object->IsJSObject()) return *value; 1656 1657 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1658 1659 if (receiver->map()->is_deprecated()) { 1660 JSObject::MigrateInstance(receiver); 1661 } 1662 1663 // Check if the given name is an array index. 1664 uint32_t index; 1665 if (name->AsArrayIndex(&index)) { 1666 Handle<Object> result = 1667 JSObject::SetElement(receiver, index, value, NONE, strict_mode); 1668 RETURN_IF_EMPTY_HANDLE(isolate(), result); 1669 return *value; 1670 } 1671 1672 // Observed objects are always modified through the runtime. 1673 if (FLAG_harmony_observation && receiver->map()->is_observed()) { 1674 return JSReceiver::SetPropertyOrFail( 1675 receiver, name, value, NONE, strict_mode, store_mode); 1676 } 1677 1678 // Use specialized code for setting the length of arrays with fast 1679 // properties. Slow properties might indicate redefinition of the length 1680 // property. Note that when redefined using Object.freeze, it's possible 1681 // to have fast properties but a read-only length. 1682 if (FLAG_use_ic && 1683 receiver->IsJSArray() && 1684 name->Equals(isolate()->heap()->length_string()) && 1685 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && 1686 receiver->HasFastProperties() && 1687 !receiver->map()->is_frozen()) { 1688 Handle<Code> stub = 1689 StoreArrayLengthStub(kind(), strict_mode).GetCode(isolate()); 1690 set_target(*stub); 1691 TRACE_IC("StoreIC", name, state, *stub); 1692 return JSReceiver::SetPropertyOrFail( 1693 receiver, name, value, NONE, strict_mode, store_mode); 1694 } 1695 1696 if (receiver->IsJSGlobalProxy()) { 1697 if (FLAG_use_ic && kind() != Code::KEYED_STORE_IC) { 1698 // Generate a generic stub that goes to the runtime when we see a global 1699 // proxy as receiver. 1700 Handle<Code> stub = (strict_mode == kStrictMode) 1701 ? global_proxy_stub_strict() 1702 : global_proxy_stub(); 1703 set_target(*stub); 1704 TRACE_IC("StoreIC", name, state, *stub); 1705 } 1706 return JSReceiver::SetPropertyOrFail( 1707 receiver, name, value, NONE, strict_mode, store_mode); 1708 } 1709 1710 LookupResult lookup(isolate()); 1711 if (LookupForWrite(receiver, name, value, &lookup, &state)) { 1712 if (FLAG_use_ic) { 1713 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); 1714 } 1715 } else if (strict_mode == kStrictMode && 1716 !(lookup.IsProperty() && lookup.IsReadOnly()) && 1717 IsUndeclaredGlobal(object)) { 1718 // Strict mode doesn't allow setting non-existent global property. 1719 return ReferenceError("not_defined", name); 1720 } else if (FLAG_use_ic && 1721 (lookup.IsNormal() || 1722 (lookup.IsField() && lookup.CanHoldValue(value)))) { 1723 Handle<Code> stub = strict_mode == kStrictMode 1724 ? generic_stub_strict() : generic_stub(); 1725 set_target(*stub); 1726 } 1727 1728 // Set the property. 1729 return JSReceiver::SetPropertyOrFail( 1730 receiver, name, value, NONE, strict_mode, store_mode); 1731 } 1732 1733 1734 void StoreIC::UpdateCaches(LookupResult* lookup, 1735 State state, 1736 StrictModeFlag strict_mode, 1737 Handle<JSObject> receiver, 1738 Handle<String> name, 1739 Handle<Object> value) { 1740 ASSERT(!receiver->IsJSGlobalProxy()); 1741 ASSERT(lookup->IsFound()); 1742 1743 // These are not cacheable, so we never see such LookupResults here. 1744 ASSERT(!lookup->IsHandler()); 1745 1746 Handle<Code> code = ComputeStoreMonomorphic( 1747 lookup, strict_mode, receiver, name, value); 1748 if (code.is_null()) { 1749 Handle<Code> stub = strict_mode == kStrictMode 1750 ? generic_stub_strict() : generic_stub(); 1751 set_target(*stub); 1752 return; 1753 } 1754 1755 PatchCache(state, strict_mode, receiver, name, code); 1756 TRACE_IC("StoreIC", name, state, target()); 1757 } 1758 1759 1760 Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, 1761 StrictModeFlag strict_mode, 1762 Handle<JSObject> receiver, 1763 Handle<String> name, 1764 Handle<Object> value) { 1765 Handle<JSObject> holder(lookup->holder()); 1766 switch (lookup->type()) { 1767 case FIELD: 1768 return isolate()->stub_cache()->ComputeStoreField( 1769 name, receiver, lookup, strict_mode); 1770 case NORMAL: 1771 if (receiver->IsGlobalObject()) { 1772 // The stub generated for the global object picks the value directly 1773 // from the property cell. So the property must be directly on the 1774 // global object. 1775 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 1776 Handle<PropertyCell> cell( 1777 global->GetPropertyCell(lookup), isolate()); 1778 return isolate()->stub_cache()->ComputeStoreGlobal( 1779 name, global, cell, value, strict_mode); 1780 } 1781 ASSERT(holder.is_identical_to(receiver)); 1782 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); 1783 case CALLBACKS: { 1784 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); 1785 if (callback->IsExecutableAccessorInfo()) { 1786 Handle<ExecutableAccessorInfo> info = 1787 Handle<ExecutableAccessorInfo>::cast(callback); 1788 if (v8::ToCData<Address>(info->setter()) == 0) break; 1789 if (!holder->HasFastProperties()) break; 1790 if (!info->IsCompatibleReceiver(*receiver)) break; 1791 return isolate()->stub_cache()->ComputeStoreCallback( 1792 name, receiver, holder, info, strict_mode); 1793 } else if (callback->IsAccessorPair()) { 1794 Handle<Object> setter( 1795 Handle<AccessorPair>::cast(callback)->setter(), isolate()); 1796 if (!setter->IsJSFunction()) break; 1797 if (holder->IsGlobalObject()) break; 1798 if (!holder->HasFastProperties()) break; 1799 return isolate()->stub_cache()->ComputeStoreViaSetter( 1800 name, receiver, holder, Handle<JSFunction>::cast(setter), 1801 strict_mode); 1802 } 1803 // TODO(dcarney): Handle correctly. 1804 if (callback->IsDeclaredAccessorInfo()) break; 1805 ASSERT(callback->IsForeign()); 1806 // No IC support for old-style native accessors. 1807 break; 1808 } 1809 case INTERCEPTOR: 1810 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); 1811 return isolate()->stub_cache()->ComputeStoreInterceptor( 1812 name, receiver, strict_mode); 1813 case CONSTANT: 1814 break; 1815 case TRANSITION: { 1816 // Explicitly pass in the receiver map since LookupForWrite may have 1817 // stored something else than the receiver in the holder. 1818 Handle<Map> transition( 1819 lookup->GetTransitionTarget(receiver->map()), isolate()); 1820 int descriptor = transition->LastAdded(); 1821 1822 DescriptorArray* target_descriptors = transition->instance_descriptors(); 1823 PropertyDetails details = target_descriptors->GetDetails(descriptor); 1824 1825 if (details.type() == CALLBACKS || details.attributes() != NONE) break; 1826 1827 return isolate()->stub_cache()->ComputeStoreTransition( 1828 name, receiver, lookup, transition, strict_mode); 1829 } 1830 case NONEXISTENT: 1831 case HANDLER: 1832 UNREACHABLE(); 1833 break; 1834 } 1835 return Handle<Code>::null(); 1836 } 1837 1838 1839 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, 1840 KeyedAccessStoreMode store_mode, 1841 StrictModeFlag strict_mode) { 1842 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS 1843 // via megamorphic stubs, since they don't have a map in their relocation info 1844 // and so the stubs can't be harvested for the object needed for a map check. 1845 if (target()->type() != Code::NORMAL) { 1846 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); 1847 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); 1848 } 1849 1850 if (!FLAG_compiled_keyed_stores && 1851 (store_mode == STORE_NO_TRANSITION_HANDLE_COW || 1852 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS)) { 1853 // TODO(danno): We'll soon handle MONOMORPHIC ICs that also support 1854 // copying COW arrays and silently ignoring some OOB stores into external 1855 // arrays, but for now use the generic. 1856 TRACE_GENERIC_IC(isolate(), "KeyedIC", "COW/OOB external array"); 1857 return strict_mode == kStrictMode 1858 ? generic_stub_strict() 1859 : generic_stub(); 1860 } 1861 1862 State ic_state = target()->ic_state(); 1863 Handle<Map> receiver_map(receiver->map(), isolate()); 1864 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { 1865 // Optimistically assume that ICs that haven't reached the MONOMORPHIC state 1866 // yet will do so and stay there. 1867 Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode); 1868 store_mode = GetNonTransitioningStoreMode(store_mode); 1869 return isolate()->stub_cache()->ComputeKeyedStoreElement( 1870 monomorphic_map, strict_mode, store_mode); 1871 } 1872 1873 MapHandleList target_receiver_maps; 1874 target()->FindAllMaps(&target_receiver_maps); 1875 if (target_receiver_maps.length() == 0) { 1876 // In the case that there is a non-map-specific IC is installed (e.g. keyed 1877 // stores into properties in dictionary mode), then there will be not 1878 // receiver maps in the target. 1879 return strict_mode == kStrictMode 1880 ? generic_stub_strict() 1881 : generic_stub(); 1882 } 1883 1884 // There are several special cases where an IC that is MONOMORPHIC can still 1885 // transition to a different GetNonTransitioningStoreMode IC that handles a 1886 // superset of the original IC. Handle those here if the receiver map hasn't 1887 // changed or it has transitioned to a more general kind. 1888 KeyedAccessStoreMode old_store_mode = 1889 Code::GetKeyedAccessStoreMode(target()->extra_ic_state()); 1890 Handle<Map> previous_receiver_map = target_receiver_maps.at(0); 1891 if (ic_state == MONOMORPHIC) { 1892 // If the "old" and "new" maps are in the same elements map family, stay 1893 // MONOMORPHIC and use the map for the most generic ElementsKind. 1894 Handle<Map> transitioned_receiver_map = receiver_map; 1895 if (IsTransitionStoreMode(store_mode)) { 1896 transitioned_receiver_map = 1897 ComputeTransitionedMap(receiver, store_mode); 1898 } 1899 if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) { 1900 // Element family is the same, use the "worst" case map. 1901 store_mode = GetNonTransitioningStoreMode(store_mode); 1902 return isolate()->stub_cache()->ComputeKeyedStoreElement( 1903 transitioned_receiver_map, strict_mode, store_mode); 1904 } else if (*previous_receiver_map == receiver->map() && 1905 old_store_mode == STANDARD_STORE && 1906 (IsGrowStoreMode(store_mode) || 1907 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS || 1908 store_mode == STORE_NO_TRANSITION_HANDLE_COW)) { 1909 // A "normal" IC that handles stores can switch to a version that can 1910 // grow at the end of the array, handle OOB accesses or copy COW arrays 1911 // and still stay MONOMORPHIC. 1912 return isolate()->stub_cache()->ComputeKeyedStoreElement( 1913 receiver_map, strict_mode, store_mode); 1914 } 1915 } 1916 1917 ASSERT(ic_state != GENERIC); 1918 1919 bool map_added = 1920 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); 1921 1922 if (IsTransitionStoreMode(store_mode)) { 1923 Handle<Map> transitioned_receiver_map = 1924 ComputeTransitionedMap(receiver, store_mode); 1925 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, 1926 transitioned_receiver_map); 1927 } 1928 1929 if (!map_added) { 1930 // If the miss wasn't due to an unseen map, a polymorphic stub 1931 // won't help, use the generic stub. 1932 TRACE_GENERIC_IC(isolate(), "KeyedIC", "same map added twice"); 1933 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); 1934 } 1935 1936 // If the maximum number of receiver maps has been exceeded, use the generic 1937 // version of the IC. 1938 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { 1939 TRACE_GENERIC_IC(isolate(), "KeyedIC", "max polymorph exceeded"); 1940 return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub(); 1941 } 1942 1943 // Make sure all polymorphic handlers have the same store mode, otherwise the 1944 // generic stub must be used. 1945 store_mode = GetNonTransitioningStoreMode(store_mode); 1946 if (old_store_mode != STANDARD_STORE) { 1947 if (store_mode == STANDARD_STORE) { 1948 store_mode = old_store_mode; 1949 } else if (store_mode != old_store_mode) { 1950 TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch"); 1951 return strict_mode == kStrictMode 1952 ? generic_stub_strict() 1953 : generic_stub(); 1954 } 1955 } 1956 1957 // If the store mode isn't the standard mode, make sure that all polymorphic 1958 // receivers are either external arrays, or all "normal" arrays. Otherwise, 1959 // use the generic stub. 1960 if (store_mode != STANDARD_STORE) { 1961 int external_arrays = 0; 1962 for (int i = 0; i < target_receiver_maps.length(); ++i) { 1963 if (target_receiver_maps[i]->has_external_array_elements()) { 1964 external_arrays++; 1965 } 1966 } 1967 if (external_arrays != 0 && 1968 external_arrays != target_receiver_maps.length()) { 1969 TRACE_GENERIC_IC(isolate(), "KeyedIC", 1970 "unsupported combination of external and normal arrays"); 1971 return strict_mode == kStrictMode 1972 ? generic_stub_strict() 1973 : generic_stub(); 1974 } 1975 } 1976 1977 return isolate()->stub_cache()->ComputeStoreElementPolymorphic( 1978 &target_receiver_maps, store_mode, strict_mode); 1979 } 1980 1981 1982 Handle<Map> KeyedStoreIC::ComputeTransitionedMap( 1983 Handle<JSObject> receiver, 1984 KeyedAccessStoreMode store_mode) { 1985 switch (store_mode) { 1986 case STORE_TRANSITION_SMI_TO_OBJECT: 1987 case STORE_TRANSITION_DOUBLE_TO_OBJECT: 1988 case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: 1989 case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: 1990 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); 1991 case STORE_TRANSITION_SMI_TO_DOUBLE: 1992 case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: 1993 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); 1994 case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT: 1995 case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: 1996 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT: 1997 case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT: 1998 return JSObject::GetElementsTransitionMap(receiver, 1999 FAST_HOLEY_ELEMENTS); 2000 case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE: 2001 case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: 2002 return JSObject::GetElementsTransitionMap(receiver, 2003 FAST_HOLEY_DOUBLE_ELEMENTS); 2004 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: 2005 ASSERT(receiver->map()->has_external_array_elements()); 2006 // Fall through 2007 case STORE_NO_TRANSITION_HANDLE_COW: 2008 case STANDARD_STORE: 2009 case STORE_AND_GROW_NO_TRANSITION: 2010 return Handle<Map>(receiver->map(), isolate()); 2011 } 2012 return Handle<Map>::null(); 2013 } 2014 2015 2016 bool IsOutOfBoundsAccess(Handle<JSObject> receiver, 2017 int index) { 2018 if (receiver->IsJSArray()) { 2019 return JSArray::cast(*receiver)->length()->IsSmi() && 2020 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); 2021 } 2022 return index >= receiver->elements()->length(); 2023 } 2024 2025 2026 KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver, 2027 Handle<Object> key, 2028 Handle<Object> value) { 2029 ASSERT(!key->ToSmi()->IsFailure()); 2030 Smi* smi_key = NULL; 2031 key->ToSmi()->To(&smi_key); 2032 int index = smi_key->value(); 2033 bool oob_access = IsOutOfBoundsAccess(receiver, index); 2034 bool allow_growth = receiver->IsJSArray() && oob_access; 2035 if (allow_growth) { 2036 // Handle growing array in stub if necessary. 2037 if (receiver->HasFastSmiElements()) { 2038 if (value->IsHeapNumber()) { 2039 if (receiver->HasFastHoleyElements()) { 2040 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE; 2041 } else { 2042 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE; 2043 } 2044 } 2045 if (value->IsHeapObject()) { 2046 if (receiver->HasFastHoleyElements()) { 2047 return STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT; 2048 } else { 2049 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT; 2050 } 2051 } 2052 } else if (receiver->HasFastDoubleElements()) { 2053 if (!value->IsSmi() && !value->IsHeapNumber()) { 2054 if (receiver->HasFastHoleyElements()) { 2055 return STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT; 2056 } else { 2057 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT; 2058 } 2059 } 2060 } 2061 return STORE_AND_GROW_NO_TRANSITION; 2062 } else { 2063 // Handle only in-bounds elements accesses. 2064 if (receiver->HasFastSmiElements()) { 2065 if (value->IsHeapNumber()) { 2066 if (receiver->HasFastHoleyElements()) { 2067 return STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE; 2068 } else { 2069 return STORE_TRANSITION_SMI_TO_DOUBLE; 2070 } 2071 } else if (value->IsHeapObject()) { 2072 if (receiver->HasFastHoleyElements()) { 2073 return STORE_TRANSITION_HOLEY_SMI_TO_OBJECT; 2074 } else { 2075 return STORE_TRANSITION_SMI_TO_OBJECT; 2076 } 2077 } 2078 } else if (receiver->HasFastDoubleElements()) { 2079 if (!value->IsSmi() && !value->IsHeapNumber()) { 2080 if (receiver->HasFastHoleyElements()) { 2081 return STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT; 2082 } else { 2083 return STORE_TRANSITION_DOUBLE_TO_OBJECT; 2084 } 2085 } 2086 } 2087 if (!FLAG_trace_external_array_abuse && 2088 receiver->map()->has_external_array_elements() && oob_access) { 2089 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS; 2090 } 2091 Heap* heap = receiver->GetHeap(); 2092 if (receiver->elements()->map() == heap->fixed_cow_array_map()) { 2093 return STORE_NO_TRANSITION_HANDLE_COW; 2094 } else { 2095 return STANDARD_STORE; 2096 } 2097 } 2098 } 2099 2100 2101 MaybeObject* KeyedStoreIC::Store(State state, 2102 StrictModeFlag strict_mode, 2103 Handle<Object> object, 2104 Handle<Object> key, 2105 Handle<Object> value, 2106 ICMissMode miss_mode) { 2107 // Check for values that can be converted into an internalized string directly 2108 // or is representable as a smi. 2109 key = TryConvertKey(key, isolate()); 2110 2111 if (key->IsInternalizedString()) { 2112 return StoreIC::Store(state, 2113 strict_mode, 2114 object, 2115 Handle<String>::cast(key), 2116 value, 2117 JSReceiver::MAY_BE_STORE_FROM_KEYED); 2118 } 2119 2120 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && 2121 !(FLAG_harmony_observation && object->IsJSObject() && 2122 JSObject::cast(*object)->map()->is_observed()); 2123 if (use_ic && !object->IsSmi()) { 2124 // Don't use ICs for maps of the objects in Array's prototype chain. We 2125 // expect to be able to trap element sets to objects with those maps in the 2126 // runtime to enable optimization of element hole access. 2127 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 2128 if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false; 2129 } 2130 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 2131 2132 if (use_ic) { 2133 Handle<Code> stub = (strict_mode == kStrictMode) 2134 ? generic_stub_strict() 2135 : generic_stub(); 2136 if (miss_mode != MISS_FORCE_GENERIC) { 2137 if (object->IsJSObject()) { 2138 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 2139 if (receiver->map()->is_deprecated()) { 2140 JSObject::MigrateInstance(receiver); 2141 } 2142 bool key_is_smi_like = key->IsSmi() || 2143 (FLAG_compiled_keyed_stores && !key->ToSmi()->IsFailure()); 2144 if (receiver->elements()->map() == 2145 isolate()->heap()->non_strict_arguments_elements_map()) { 2146 stub = non_strict_arguments_stub(); 2147 } else if (key_is_smi_like && 2148 (target() != *non_strict_arguments_stub())) { 2149 KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value); 2150 stub = StoreElementStub(receiver, store_mode, strict_mode); 2151 } else { 2152 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number"); 2153 } 2154 } else { 2155 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object"); 2156 } 2157 } else { 2158 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic"); 2159 } 2160 ASSERT(!stub.is_null()); 2161 set_target(*stub); 2162 TRACE_IC("KeyedStoreIC", key, state, target()); 2163 } 2164 2165 return Runtime::SetObjectPropertyOrFail( 2166 isolate(), object , key, value, NONE, strict_mode); 2167 } 2168 2169 2170 Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, 2171 StrictModeFlag strict_mode, 2172 Handle<JSObject> receiver, 2173 Handle<String> name, 2174 Handle<Object> value) { 2175 // If the property has a non-field type allowing map transitions 2176 // where there is extra room in the object, we leave the IC in its 2177 // current state. 2178 switch (lookup->type()) { 2179 case FIELD: 2180 return isolate()->stub_cache()->ComputeKeyedStoreField( 2181 name, receiver, lookup, strict_mode); 2182 case TRANSITION: { 2183 // Explicitly pass in the receiver map since LookupForWrite may have 2184 // stored something else than the receiver in the holder. 2185 Handle<Map> transition( 2186 lookup->GetTransitionTarget(receiver->map()), isolate()); 2187 int descriptor = transition->LastAdded(); 2188 2189 DescriptorArray* target_descriptors = transition->instance_descriptors(); 2190 PropertyDetails details = target_descriptors->GetDetails(descriptor); 2191 2192 if (details.type() != CALLBACKS && details.attributes() == NONE) { 2193 return isolate()->stub_cache()->ComputeKeyedStoreTransition( 2194 name, receiver, lookup, transition, strict_mode); 2195 } 2196 // fall through. 2197 } 2198 case NORMAL: 2199 case CONSTANT: 2200 case CALLBACKS: 2201 case INTERCEPTOR: 2202 // Always rewrite to the generic case so that we do not 2203 // repeatedly try to rewrite. 2204 return (strict_mode == kStrictMode) 2205 ? generic_stub_strict() 2206 : generic_stub(); 2207 case HANDLER: 2208 case NONEXISTENT: 2209 UNREACHABLE(); 2210 break; 2211 } 2212 return Handle<Code>::null(); 2213 } 2214 2215 2216 #undef TRACE_IC 2217 2218 2219 // ---------------------------------------------------------------------------- 2220 // Static IC stub generators. 2221 // 2222 2223 // Used from ic-<arch>.cc. 2224 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { 2225 HandleScope scope(isolate); 2226 ASSERT(args.length() == 2); 2227 CallIC ic(isolate); 2228 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2229 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2230 MaybeObject* maybe_result = ic.LoadFunction(state, 2231 extra_ic_state, 2232 args.at<Object>(0), 2233 args.at<String>(1)); 2234 JSFunction* raw_function; 2235 if (!maybe_result->To(&raw_function)) return maybe_result; 2236 2237 // The first time the inline cache is updated may be the first time the 2238 // function it references gets called. If the function is lazily compiled 2239 // then the first call will trigger a compilation. We check for this case 2240 // and we do the compilation immediately, instead of waiting for the stub 2241 // currently attached to the JSFunction object to trigger compilation. 2242 if (raw_function->is_compiled()) return raw_function; 2243 2244 Handle<JSFunction> function(raw_function); 2245 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); 2246 return *function; 2247 } 2248 2249 2250 // Used from ic-<arch>.cc. 2251 RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { 2252 HandleScope scope(isolate); 2253 ASSERT(args.length() == 2); 2254 KeyedCallIC ic(isolate); 2255 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2256 MaybeObject* maybe_result = 2257 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); 2258 // Result could be a function or a failure. 2259 JSFunction* raw_function = NULL; 2260 if (!maybe_result->To(&raw_function)) return maybe_result; 2261 2262 if (raw_function->is_compiled()) return raw_function; 2263 2264 Handle<JSFunction> function(raw_function, isolate); 2265 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); 2266 return *function; 2267 } 2268 2269 2270 // Used from ic-<arch>.cc. 2271 RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { 2272 HandleScope scope(isolate); 2273 ASSERT(args.length() == 2); 2274 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); 2275 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2276 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); 2277 } 2278 2279 2280 // Used from ic-<arch>.cc 2281 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { 2282 HandleScope scope(isolate); 2283 ASSERT(args.length() == 2); 2284 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); 2285 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2286 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS); 2287 } 2288 2289 2290 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure) { 2291 HandleScope scope(isolate); 2292 ASSERT(args.length() == 2); 2293 KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate); 2294 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2295 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), MISS); 2296 } 2297 2298 2299 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { 2300 HandleScope scope(isolate); 2301 ASSERT(args.length() == 2); 2302 KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate); 2303 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2304 return ic.Load(state, 2305 args.at<Object>(0), 2306 args.at<Object>(1), 2307 MISS_FORCE_GENERIC); 2308 } 2309 2310 2311 // Used from ic-<arch>.cc. 2312 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { 2313 HandleScope scope(isolate); 2314 ASSERT(args.length() == 3); 2315 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); 2316 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2317 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2318 return ic.Store(state, 2319 Code::GetStrictMode(extra_ic_state), 2320 args.at<Object>(0), 2321 args.at<String>(1), 2322 args.at<Object>(2)); 2323 } 2324 2325 2326 RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) { 2327 HandleScope scope(isolate); 2328 ASSERT(args.length() == 3); 2329 StoreIC ic(IC::EXTRA_CALL_FRAME, isolate); 2330 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2331 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2332 return ic.Store(state, 2333 Code::GetStrictMode(extra_ic_state), 2334 args.at<Object>(0), 2335 args.at<String>(1), 2336 args.at<Object>(2)); 2337 } 2338 2339 2340 RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { 2341 SealHandleScope shs(isolate); 2342 2343 ASSERT(args.length() == 2); 2344 JSArray* receiver = JSArray::cast(args[0]); 2345 Object* len = args[1]; 2346 2347 // The generated code should filter out non-Smis before we get here. 2348 ASSERT(len->IsSmi()); 2349 2350 #ifdef DEBUG 2351 // The length property has to be a writable callback property. 2352 LookupResult debug_lookup(isolate); 2353 receiver->LocalLookup(isolate->heap()->length_string(), &debug_lookup); 2354 ASSERT(debug_lookup.IsPropertyCallbacks() && !debug_lookup.IsReadOnly()); 2355 #endif 2356 2357 Object* result; 2358 MaybeObject* maybe_result = receiver->SetElementsLength(len); 2359 if (!maybe_result->To(&result)) return maybe_result; 2360 2361 return len; 2362 } 2363 2364 2365 // Extend storage is called in a store inline cache when 2366 // it is necessary to extend the properties array of a 2367 // JSObject. 2368 RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) { 2369 SealHandleScope shs(isolate); 2370 ASSERT(args.length() == 3); 2371 2372 // Convert the parameters 2373 JSObject* object = JSObject::cast(args[0]); 2374 Map* transition = Map::cast(args[1]); 2375 Object* value = args[2]; 2376 2377 // Check the object has run out out property space. 2378 ASSERT(object->HasFastProperties()); 2379 ASSERT(object->map()->unused_property_fields() == 0); 2380 2381 // Expand the properties array. 2382 FixedArray* old_storage = object->properties(); 2383 int new_unused = transition->unused_property_fields(); 2384 int new_size = old_storage->length() + new_unused + 1; 2385 Object* result; 2386 MaybeObject* maybe_result = old_storage->CopySize(new_size); 2387 if (!maybe_result->ToObject(&result)) return maybe_result; 2388 2389 FixedArray* new_storage = FixedArray::cast(result); 2390 2391 Object* to_store = value; 2392 2393 if (FLAG_track_double_fields) { 2394 DescriptorArray* descriptors = transition->instance_descriptors(); 2395 PropertyDetails details = descriptors->GetDetails(transition->LastAdded()); 2396 if (details.representation().IsDouble()) { 2397 MaybeObject* maybe_storage = 2398 isolate->heap()->AllocateHeapNumber(value->Number()); 2399 if (!maybe_storage->To(&to_store)) return maybe_storage; 2400 } 2401 } 2402 2403 new_storage->set(old_storage->length(), to_store); 2404 2405 // Set the new property value and do the map transition. 2406 object->set_properties(new_storage); 2407 object->set_map(transition); 2408 2409 // Return the stored value. 2410 return value; 2411 } 2412 2413 2414 // Used from ic-<arch>.cc. 2415 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { 2416 HandleScope scope(isolate); 2417 ASSERT(args.length() == 3); 2418 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); 2419 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2420 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2421 return ic.Store(state, 2422 Code::GetStrictMode(extra_ic_state), 2423 args.at<Object>(0), 2424 args.at<Object>(1), 2425 args.at<Object>(2), 2426 MISS); 2427 } 2428 2429 2430 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure) { 2431 HandleScope scope(isolate); 2432 ASSERT(args.length() == 3); 2433 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); 2434 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2435 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2436 return ic.Store(state, 2437 Code::GetStrictMode(extra_ic_state), 2438 args.at<Object>(0), 2439 args.at<Object>(1), 2440 args.at<Object>(2), 2441 MISS); 2442 } 2443 2444 2445 RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) { 2446 SealHandleScope shs(isolate); 2447 ASSERT(args.length() == 3); 2448 StoreIC ic(IC::NO_EXTRA_FRAME, isolate); 2449 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2450 Handle<Object> object = args.at<Object>(0); 2451 Handle<Object> key = args.at<Object>(1); 2452 Handle<Object> value = args.at<Object>(2); 2453 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); 2454 return Runtime::SetObjectProperty(isolate, 2455 object, 2456 key, 2457 value, 2458 NONE, 2459 strict_mode); 2460 } 2461 2462 2463 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { 2464 SealHandleScope shs(isolate); 2465 ASSERT(args.length() == 3); 2466 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); 2467 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2468 Handle<Object> object = args.at<Object>(0); 2469 Handle<Object> key = args.at<Object>(1); 2470 Handle<Object> value = args.at<Object>(2); 2471 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); 2472 return Runtime::SetObjectProperty(isolate, 2473 object, 2474 key, 2475 value, 2476 NONE, 2477 strict_mode); 2478 } 2479 2480 2481 RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { 2482 HandleScope scope(isolate); 2483 ASSERT(args.length() == 3); 2484 KeyedStoreIC ic(IC::NO_EXTRA_FRAME, isolate); 2485 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2486 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2487 return ic.Store(state, 2488 Code::GetStrictMode(extra_ic_state), 2489 args.at<Object>(0), 2490 args.at<Object>(1), 2491 args.at<Object>(2), 2492 MISS_FORCE_GENERIC); 2493 } 2494 2495 2496 RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) { 2497 SealHandleScope scope(isolate); 2498 ASSERT(args.length() == 4); 2499 KeyedStoreIC ic(IC::EXTRA_CALL_FRAME, isolate); 2500 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2501 Handle<Object> value = args.at<Object>(0); 2502 Handle<Object> key = args.at<Object>(2); 2503 Handle<Object> object = args.at<Object>(3); 2504 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); 2505 return Runtime::SetObjectProperty(isolate, 2506 object, 2507 key, 2508 value, 2509 NONE, 2510 strict_mode); 2511 } 2512 2513 2514 void BinaryOpIC::patch(Code* code) { 2515 set_target(code); 2516 } 2517 2518 2519 const char* BinaryOpIC::GetName(TypeInfo type_info) { 2520 switch (type_info) { 2521 case UNINITIALIZED: return "Uninitialized"; 2522 case SMI: return "Smi"; 2523 case INT32: return "Int32"; 2524 case NUMBER: return "Number"; 2525 case ODDBALL: return "Oddball"; 2526 case STRING: return "String"; 2527 case GENERIC: return "Generic"; 2528 default: return "Invalid"; 2529 } 2530 } 2531 2532 2533 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { 2534 switch (type_info) { 2535 case UNINITIALIZED: 2536 return ::v8::internal::UNINITIALIZED; 2537 case SMI: 2538 case INT32: 2539 case NUMBER: 2540 case ODDBALL: 2541 case STRING: 2542 return MONOMORPHIC; 2543 case GENERIC: 2544 return ::v8::internal::GENERIC; 2545 } 2546 UNREACHABLE(); 2547 return ::v8::internal::UNINITIALIZED; 2548 } 2549 2550 2551 Handle<Type> BinaryOpIC::TypeInfoToType(BinaryOpIC::TypeInfo binary_type, 2552 Isolate* isolate) { 2553 switch (binary_type) { 2554 case UNINITIALIZED: 2555 return handle(Type::None(), isolate); 2556 case SMI: 2557 return handle(Type::Smi(), isolate); 2558 case INT32: 2559 return handle(Type::Signed32(), isolate); 2560 case NUMBER: 2561 return handle(Type::Number(), isolate); 2562 case ODDBALL: 2563 return handle(Type::Optional( 2564 handle(Type::Union( 2565 handle(Type::Number(), isolate), 2566 handle(Type::String(), isolate)), isolate)), isolate); 2567 case STRING: 2568 return handle(Type::String(), isolate); 2569 case GENERIC: 2570 return handle(Type::Any(), isolate); 2571 } 2572 UNREACHABLE(); 2573 return handle(Type::Any(), isolate); 2574 } 2575 2576 2577 void BinaryOpIC::StubInfoToType(int minor_key, 2578 Handle<Type>* left, 2579 Handle<Type>* right, 2580 Handle<Type>* result, 2581 Isolate* isolate) { 2582 TypeInfo left_typeinfo, right_typeinfo, result_typeinfo; 2583 BinaryOpStub::decode_types_from_minor_key( 2584 minor_key, &left_typeinfo, &right_typeinfo, &result_typeinfo); 2585 *left = TypeInfoToType(left_typeinfo, isolate); 2586 *right = TypeInfoToType(right_typeinfo, isolate); 2587 *result = TypeInfoToType(result_typeinfo, isolate); 2588 } 2589 2590 2591 static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, 2592 Token::Value op) { 2593 v8::internal::TypeInfo type = v8::internal::TypeInfo::FromValue(value); 2594 if (type.IsSmi()) return BinaryOpIC::SMI; 2595 if (type.IsInteger32()) { 2596 if (kSmiValueSize == 32) return BinaryOpIC::SMI; 2597 return BinaryOpIC::INT32; 2598 } 2599 if (type.IsNumber()) return BinaryOpIC::NUMBER; 2600 if (type.IsString()) return BinaryOpIC::STRING; 2601 if (value->IsUndefined()) { 2602 if (op == Token::BIT_AND || 2603 op == Token::BIT_OR || 2604 op == Token::BIT_XOR || 2605 op == Token::SAR || 2606 op == Token::SHL || 2607 op == Token::SHR) { 2608 if (kSmiValueSize == 32) return BinaryOpIC::SMI; 2609 return BinaryOpIC::INT32; 2610 } 2611 return BinaryOpIC::ODDBALL; 2612 } 2613 return BinaryOpIC::GENERIC; 2614 } 2615 2616 2617 static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, 2618 Handle<Object> value, 2619 Token::Value op) { 2620 BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); 2621 if (old_type == BinaryOpIC::STRING) { 2622 if (new_type == BinaryOpIC::STRING) return new_type; 2623 return BinaryOpIC::GENERIC; 2624 } 2625 return Max(old_type, new_type); 2626 } 2627 2628 2629 #ifdef DEBUG 2630 static void TraceBinaryOp(BinaryOpIC::TypeInfo left, 2631 BinaryOpIC::TypeInfo right, 2632 Maybe<int32_t> fixed_right_arg, 2633 BinaryOpIC::TypeInfo result) { 2634 PrintF("%s*%s", BinaryOpIC::GetName(left), BinaryOpIC::GetName(right)); 2635 if (fixed_right_arg.has_value) PrintF("{%d}", fixed_right_arg.value); 2636 PrintF("->%s", BinaryOpIC::GetName(result)); 2637 } 2638 #endif 2639 2640 2641 RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { 2642 ASSERT(args.length() == 3); 2643 2644 HandleScope scope(isolate); 2645 Handle<Object> left = args.at<Object>(0); 2646 Handle<Object> right = args.at<Object>(1); 2647 int key = args.smi_at(2); 2648 Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); 2649 2650 BinaryOpIC::TypeInfo previous_left, previous_right, previous_result; 2651 BinaryOpStub::decode_types_from_minor_key( 2652 key, &previous_left, &previous_right, &previous_result); 2653 2654 BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); 2655 BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); 2656 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; 2657 2658 // STRING is only used for ADD operations. 2659 if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && 2660 op != Token::ADD) { 2661 new_left = new_right = BinaryOpIC::GENERIC; 2662 } 2663 2664 BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); 2665 BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); 2666 2667 Maybe<int> previous_fixed_right_arg = 2668 BinaryOpStub::decode_fixed_right_arg_from_minor_key(key); 2669 2670 int32_t value; 2671 bool new_has_fixed_right_arg = 2672 op == Token::MOD && 2673 right->ToInt32(&value) && 2674 BinaryOpStub::can_encode_arg_value(value) && 2675 (previous_overall == BinaryOpIC::UNINITIALIZED || 2676 (previous_fixed_right_arg.has_value && 2677 previous_fixed_right_arg.value == value)); 2678 Maybe<int32_t> new_fixed_right_arg( 2679 new_has_fixed_right_arg, new_has_fixed_right_arg ? value : 1); 2680 2681 if (previous_fixed_right_arg.has_value == new_fixed_right_arg.has_value) { 2682 if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { 2683 if (op == Token::DIV || 2684 op == Token::MUL || 2685 op == Token::SHR || 2686 kSmiValueSize == 32) { 2687 // Arithmetic on two Smi inputs has yielded a heap number. 2688 // That is the only way to get here from the Smi stub. 2689 // With 32-bit Smis, all overflows give heap numbers, but with 2690 // 31-bit Smis, most operations overflow to int32 results. 2691 result_type = BinaryOpIC::NUMBER; 2692 } else { 2693 // Other operations on SMIs that overflow yield int32s. 2694 result_type = BinaryOpIC::INT32; 2695 } 2696 } 2697 if (new_overall == BinaryOpIC::INT32 && 2698 previous_overall == BinaryOpIC::INT32) { 2699 if (new_left == previous_left && new_right == previous_right) { 2700 result_type = BinaryOpIC::NUMBER; 2701 } 2702 } 2703 } 2704 2705 BinaryOpStub stub(key, new_left, new_right, result_type, new_fixed_right_arg); 2706 Handle<Code> code = stub.GetCode(isolate); 2707 if (!code.is_null()) { 2708 #ifdef DEBUG 2709 if (FLAG_trace_ic) { 2710 PrintF("[BinaryOpIC in "); 2711 JavaScriptFrame::PrintTop(isolate, stdout, false, true); 2712 PrintF(" "); 2713 TraceBinaryOp(previous_left, previous_right, previous_fixed_right_arg, 2714 previous_result); 2715 PrintF(" => "); 2716 TraceBinaryOp(new_left, new_right, new_fixed_right_arg, result_type); 2717 PrintF(" #%s @ %p]\n", Token::Name(op), static_cast<void*>(*code)); 2718 } 2719 #endif 2720 BinaryOpIC ic(isolate); 2721 ic.patch(*code); 2722 2723 // Activate inlined smi code. 2724 if (previous_overall == BinaryOpIC::UNINITIALIZED) { 2725 PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); 2726 } 2727 } 2728 2729 Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object()); 2730 Object* builtin = NULL; // Initialization calms down the compiler. 2731 switch (op) { 2732 case Token::ADD: 2733 builtin = builtins->javascript_builtin(Builtins::ADD); 2734 break; 2735 case Token::SUB: 2736 builtin = builtins->javascript_builtin(Builtins::SUB); 2737 break; 2738 case Token::MUL: 2739 builtin = builtins->javascript_builtin(Builtins::MUL); 2740 break; 2741 case Token::DIV: 2742 builtin = builtins->javascript_builtin(Builtins::DIV); 2743 break; 2744 case Token::MOD: 2745 builtin = builtins->javascript_builtin(Builtins::MOD); 2746 break; 2747 case Token::BIT_AND: 2748 builtin = builtins->javascript_builtin(Builtins::BIT_AND); 2749 break; 2750 case Token::BIT_OR: 2751 builtin = builtins->javascript_builtin(Builtins::BIT_OR); 2752 break; 2753 case Token::BIT_XOR: 2754 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); 2755 break; 2756 case Token::SHR: 2757 builtin = builtins->javascript_builtin(Builtins::SHR); 2758 break; 2759 case Token::SAR: 2760 builtin = builtins->javascript_builtin(Builtins::SAR); 2761 break; 2762 case Token::SHL: 2763 builtin = builtins->javascript_builtin(Builtins::SHL); 2764 break; 2765 default: 2766 UNREACHABLE(); 2767 } 2768 2769 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); 2770 2771 bool caught_exception; 2772 Handle<Object> builtin_args[] = { right }; 2773 Handle<Object> result = Execution::Call(builtin_function, 2774 left, 2775 ARRAY_SIZE(builtin_args), 2776 builtin_args, 2777 &caught_exception); 2778 if (caught_exception) { 2779 return Failure::Exception(); 2780 } 2781 return *result; 2782 } 2783 2784 2785 Code* CompareIC::GetRawUninitialized(Token::Value op) { 2786 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); 2787 Code* code = NULL; 2788 CHECK(stub.FindCodeInCache(&code, Isolate::Current())); 2789 return code; 2790 } 2791 2792 2793 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { 2794 ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); 2795 return stub.GetCode(isolate); 2796 } 2797 2798 2799 const char* CompareIC::GetStateName(State state) { 2800 switch (state) { 2801 case UNINITIALIZED: return "UNINITIALIZED"; 2802 case SMI: return "SMI"; 2803 case NUMBER: return "NUMBER"; 2804 case INTERNALIZED_STRING: return "INTERNALIZED_STRING"; 2805 case STRING: return "STRING"; 2806 case UNIQUE_NAME: return "UNIQUE_NAME"; 2807 case OBJECT: return "OBJECT"; 2808 case KNOWN_OBJECT: return "KNOWN_OBJECT"; 2809 case GENERIC: return "GENERIC"; 2810 } 2811 UNREACHABLE(); 2812 return NULL; 2813 } 2814 2815 2816 Handle<Type> CompareIC::StateToType( 2817 Isolate* isolate, 2818 CompareIC::State state, 2819 Handle<Map> map) { 2820 switch (state) { 2821 case CompareIC::UNINITIALIZED: 2822 return handle(Type::None(), isolate); 2823 case CompareIC::SMI: 2824 return handle(Type::Smi(), isolate); 2825 case CompareIC::NUMBER: 2826 return handle(Type::Number(), isolate); 2827 case CompareIC::STRING: 2828 return handle(Type::String(), isolate); 2829 case CompareIC::INTERNALIZED_STRING: 2830 return handle(Type::InternalizedString(), isolate); 2831 case CompareIC::UNIQUE_NAME: 2832 return handle(Type::UniqueName(), isolate); 2833 case CompareIC::OBJECT: 2834 return handle(Type::Receiver(), isolate); 2835 case CompareIC::KNOWN_OBJECT: 2836 return handle( 2837 map.is_null() ? Type::Receiver() : Type::Class(map), isolate); 2838 case CompareIC::GENERIC: 2839 return handle(Type::Any(), isolate); 2840 } 2841 UNREACHABLE(); 2842 return Handle<Type>(); 2843 } 2844 2845 2846 void CompareIC::StubInfoToType(int stub_minor_key, 2847 Handle<Type>* left_type, 2848 Handle<Type>* right_type, 2849 Handle<Type>* overall_type, 2850 Handle<Map> map, 2851 Isolate* isolate) { 2852 State left_state, right_state, handler_state; 2853 ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state, 2854 &handler_state, NULL); 2855 *left_type = StateToType(isolate, left_state); 2856 *right_type = StateToType(isolate, right_state); 2857 *overall_type = StateToType(isolate, handler_state, map); 2858 } 2859 2860 2861 CompareIC::State CompareIC::NewInputState(State old_state, 2862 Handle<Object> value) { 2863 switch (old_state) { 2864 case UNINITIALIZED: 2865 if (value->IsSmi()) return SMI; 2866 if (value->IsHeapNumber()) return NUMBER; 2867 if (value->IsInternalizedString()) return INTERNALIZED_STRING; 2868 if (value->IsString()) return STRING; 2869 if (value->IsSymbol()) return UNIQUE_NAME; 2870 if (value->IsJSObject()) return OBJECT; 2871 break; 2872 case SMI: 2873 if (value->IsSmi()) return SMI; 2874 if (value->IsHeapNumber()) return NUMBER; 2875 break; 2876 case NUMBER: 2877 if (value->IsNumber()) return NUMBER; 2878 break; 2879 case INTERNALIZED_STRING: 2880 if (value->IsInternalizedString()) return INTERNALIZED_STRING; 2881 if (value->IsString()) return STRING; 2882 if (value->IsSymbol()) return UNIQUE_NAME; 2883 break; 2884 case STRING: 2885 if (value->IsString()) return STRING; 2886 break; 2887 case UNIQUE_NAME: 2888 if (value->IsUniqueName()) return UNIQUE_NAME; 2889 break; 2890 case OBJECT: 2891 if (value->IsJSObject()) return OBJECT; 2892 break; 2893 case GENERIC: 2894 break; 2895 case KNOWN_OBJECT: 2896 UNREACHABLE(); 2897 break; 2898 } 2899 return GENERIC; 2900 } 2901 2902 2903 CompareIC::State CompareIC::TargetState(State old_state, 2904 State old_left, 2905 State old_right, 2906 bool has_inlined_smi_code, 2907 Handle<Object> x, 2908 Handle<Object> y) { 2909 switch (old_state) { 2910 case UNINITIALIZED: 2911 if (x->IsSmi() && y->IsSmi()) return SMI; 2912 if (x->IsNumber() && y->IsNumber()) return NUMBER; 2913 if (Token::IsOrderedRelationalCompareOp(op_)) { 2914 // Ordered comparisons treat undefined as NaN, so the 2915 // NUMBER stub will do the right thing. 2916 if ((x->IsNumber() && y->IsUndefined()) || 2917 (y->IsNumber() && x->IsUndefined())) { 2918 return NUMBER; 2919 } 2920 } 2921 if (x->IsInternalizedString() && y->IsInternalizedString()) { 2922 // We compare internalized strings as plain ones if we need to determine 2923 // the order in a non-equality compare. 2924 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING; 2925 } 2926 if (x->IsString() && y->IsString()) return STRING; 2927 if (!Token::IsEqualityOp(op_)) return GENERIC; 2928 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME; 2929 if (x->IsJSObject() && y->IsJSObject()) { 2930 if (Handle<JSObject>::cast(x)->map() == 2931 Handle<JSObject>::cast(y)->map()) { 2932 return KNOWN_OBJECT; 2933 } else { 2934 return OBJECT; 2935 } 2936 } 2937 return GENERIC; 2938 case SMI: 2939 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC; 2940 case INTERNALIZED_STRING: 2941 ASSERT(Token::IsEqualityOp(op_)); 2942 if (x->IsString() && y->IsString()) return STRING; 2943 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME; 2944 return GENERIC; 2945 case NUMBER: 2946 // If the failure was due to one side changing from smi to heap number, 2947 // then keep the state (if other changed at the same time, we will get 2948 // a second miss and then go to generic). 2949 if (old_left == SMI && x->IsHeapNumber()) return NUMBER; 2950 if (old_right == SMI && y->IsHeapNumber()) return NUMBER; 2951 return GENERIC; 2952 case KNOWN_OBJECT: 2953 ASSERT(Token::IsEqualityOp(op_)); 2954 if (x->IsJSObject() && y->IsJSObject()) return OBJECT; 2955 return GENERIC; 2956 case STRING: 2957 case UNIQUE_NAME: 2958 case OBJECT: 2959 case GENERIC: 2960 return GENERIC; 2961 } 2962 UNREACHABLE(); 2963 return GENERIC; // Make the compiler happy. 2964 } 2965 2966 2967 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { 2968 HandleScope scope(isolate()); 2969 State previous_left, previous_right, previous_state; 2970 ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left, 2971 &previous_right, &previous_state, NULL); 2972 State new_left = NewInputState(previous_left, x); 2973 State new_right = NewInputState(previous_right, y); 2974 State state = TargetState(previous_state, previous_left, previous_right, 2975 HasInlinedSmiCode(address()), x, y); 2976 ICCompareStub stub(op_, new_left, new_right, state); 2977 if (state == KNOWN_OBJECT) { 2978 stub.set_known_map( 2979 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); 2980 } 2981 set_target(*stub.GetCode(isolate())); 2982 2983 #ifdef DEBUG 2984 if (FLAG_trace_ic) { 2985 PrintF("[CompareIC in "); 2986 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); 2987 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", 2988 GetStateName(previous_left), 2989 GetStateName(previous_right), 2990 GetStateName(previous_state), 2991 GetStateName(new_left), 2992 GetStateName(new_right), 2993 GetStateName(state), 2994 Token::Name(op_), 2995 static_cast<void*>(*stub.GetCode(isolate()))); 2996 } 2997 #endif 2998 2999 // Activate inlined smi code. 3000 if (previous_state == UNINITIALIZED) { 3001 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); 3002 } 3003 } 3004 3005 3006 // Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. 3007 RUNTIME_FUNCTION(Code*, CompareIC_Miss) { 3008 SealHandleScope shs(isolate); 3009 ASSERT(args.length() == 3); 3010 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); 3011 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); 3012 return ic.target(); 3013 } 3014 3015 3016 void CompareNilIC::Clear(Address address, Code* target) { 3017 if (target->ic_state() == UNINITIALIZED) return; 3018 Code::ExtraICState state = target->extended_extra_ic_state(); 3019 3020 CompareNilICStub stub(state, HydrogenCodeStub::UNINITIALIZED); 3021 stub.ClearState(); 3022 3023 Code* code = NULL; 3024 CHECK(stub.FindCodeInCache(&code, target->GetIsolate())); 3025 3026 SetTargetAtAddress(address, code); 3027 } 3028 3029 3030 MaybeObject* CompareNilIC::DoCompareNilSlow(NilValue nil, 3031 Handle<Object> object) { 3032 if (object->IsNull() || object->IsUndefined()) { 3033 return Smi::FromInt(true); 3034 } 3035 return Smi::FromInt(object->IsUndetectableObject()); 3036 } 3037 3038 3039 MaybeObject* CompareNilIC::CompareNil(Handle<Object> object) { 3040 Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state(); 3041 3042 CompareNilICStub stub(extra_ic_state); 3043 3044 // Extract the current supported types from the patched IC and calculate what 3045 // types must be supported as a result of the miss. 3046 bool already_monomorphic = stub.IsMonomorphic(); 3047 3048 stub.UpdateStatus(object); 3049 3050 NilValue nil = stub.GetNilValue(); 3051 3052 // Find or create the specialized stub to support the new set of types. 3053 Handle<Code> code; 3054 if (stub.IsMonomorphic()) { 3055 Handle<Map> monomorphic_map(already_monomorphic 3056 ? target()->FindFirstMap() 3057 : HeapObject::cast(*object)->map()); 3058 code = isolate()->stub_cache()->ComputeCompareNil(monomorphic_map, stub); 3059 } else { 3060 code = stub.GetCode(isolate()); 3061 } 3062 set_target(*code); 3063 return DoCompareNilSlow(nil, object); 3064 } 3065 3066 3067 RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss) { 3068 HandleScope scope(isolate); 3069 Handle<Object> object = args.at<Object>(0); 3070 CompareNilIC ic(isolate); 3071 return ic.CompareNil(object); 3072 } 3073 3074 3075 RUNTIME_FUNCTION(MaybeObject*, Unreachable) { 3076 UNREACHABLE(); 3077 CHECK(false); 3078 return isolate->heap()->undefined_value(); 3079 } 3080 3081 3082 MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object, 3083 Code::ExtraICState extra_ic_state) { 3084 ToBooleanStub stub(extra_ic_state); 3085 bool to_boolean_value = stub.UpdateStatus(object); 3086 Handle<Code> code = stub.GetCode(isolate()); 3087 set_target(*code); 3088 return Smi::FromInt(to_boolean_value ? 1 : 0); 3089 } 3090 3091 3092 RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss) { 3093 ASSERT(args.length() == 1); 3094 HandleScope scope(isolate); 3095 Handle<Object> object = args.at<Object>(0); 3096 ToBooleanIC ic(isolate); 3097 Code::ExtraICState ic_state = ic.target()->extended_extra_ic_state(); 3098 return ic.ToBoolean(object, ic_state); 3099 } 3100 3101 3102 static const Address IC_utilities[] = { 3103 #define ADDR(name) FUNCTION_ADDR(name), 3104 IC_UTIL_LIST(ADDR) 3105 NULL 3106 #undef ADDR 3107 }; 3108 3109 3110 Address IC::AddressFromUtilityId(IC::UtilityId id) { 3111 return IC_utilities[id]; 3112 } 3113 3114 3115 } } // namespace v8::internal 3116