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 39namespace v8 { 40namespace internal { 41 42#ifdef DEBUG 43char IC::TransitionMarkFromState(IC::State state) { 44 switch (state) { 45 case UNINITIALIZED: return '0'; 46 case PREMONOMORPHIC: return 'P'; 47 case MONOMORPHIC: return '1'; 48 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; 49 case MEGAMORPHIC: return IsGeneric() ? 'G' : 'N'; 50 51 // We never see the debugger states here, because the state is 52 // computed from the original code - not the patched code. Let 53 // these cases fall through to the unreachable code below. 54 case DEBUG_BREAK: break; 55 case DEBUG_PREPARE_STEP_IN: break; 56 } 57 UNREACHABLE(); 58 return 0; 59} 60 61void IC::TraceIC(const char* type, 62 Handle<Object> name, 63 State old_state, 64 Code* new_target) { 65 if (FLAG_trace_ic) { 66 State new_state = StateFrom(new_target, 67 HEAP->undefined_value(), 68 HEAP->undefined_value()); 69 PrintF("[%s in ", type); 70 StackFrameIterator it; 71 while (it.frame()->fp() != this->fp()) it.Advance(); 72 StackFrame* raw_frame = it.frame(); 73 if (raw_frame->is_internal()) { 74 Isolate* isolate = new_target->GetIsolate(); 75 Code* apply_builtin = isolate->builtins()->builtin( 76 Builtins::kFunctionApply); 77 if (raw_frame->unchecked_code() == apply_builtin) { 78 PrintF("apply from "); 79 it.Advance(); 80 raw_frame = it.frame(); 81 } 82 } 83 JavaScriptFrame::PrintTop(stdout, false, true); 84 bool new_can_grow = 85 Code::GetKeyedAccessGrowMode(new_target->extra_ic_state()) == 86 ALLOW_JSARRAY_GROWTH; 87 PrintF(" (%c->%c%s)", 88 TransitionMarkFromState(old_state), 89 TransitionMarkFromState(new_state), 90 new_can_grow ? ".GROW" : ""); 91 name->Print(); 92 PrintF("]\n"); 93 } 94} 95 96#define TRACE_GENERIC_IC(type, reason) \ 97 do { \ 98 if (FLAG_trace_ic) { \ 99 PrintF("[%s patching generic stub in ", type); \ 100 JavaScriptFrame::PrintTop(stdout, false, true); \ 101 PrintF(" (%s)]\n", reason); \ 102 } \ 103 } while (false) 104 105#else 106#define TRACE_GENERIC_IC(type, reason) 107#endif // DEBUG 108 109#define TRACE_IC(type, name, old_state, new_target) \ 110 ASSERT((TraceIC(type, name, old_state, new_target), true)) 111 112IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) { 113 ASSERT(isolate == Isolate::Current()); 114 // To improve the performance of the (much used) IC code, we unfold 115 // a few levels of the stack frame iteration code. This yields a 116 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. 117 const Address entry = 118 Isolate::c_entry_fp(isolate->thread_local_top()); 119 Address* pc_address = 120 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); 121 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 122 // If there's another JavaScript frame on the stack, we need to look 123 // one frame further down the stack to find the frame pointer and 124 // the return address stack slot. 125 if (depth == EXTRA_CALL_FRAME) { 126 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; 127 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); 128 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); 129 } 130#ifdef DEBUG 131 StackFrameIterator it; 132 for (int i = 0; i < depth + 1; i++) it.Advance(); 133 StackFrame* frame = it.frame(); 134 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); 135#endif 136 fp_ = fp; 137 pc_address_ = pc_address; 138} 139 140 141#ifdef ENABLE_DEBUGGER_SUPPORT 142Address IC::OriginalCodeAddress() const { 143 HandleScope scope; 144 // Compute the JavaScript frame for the frame pointer of this IC 145 // structure. We need this to be able to find the function 146 // corresponding to the frame. 147 StackFrameIterator it; 148 while (it.frame()->fp() != this->fp()) it.Advance(); 149 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 150 // Find the function on the stack and both the active code for the 151 // function and the original code. 152 JSFunction* function = JSFunction::cast(frame->function()); 153 Handle<SharedFunctionInfo> shared(function->shared()); 154 Code* code = shared->code(); 155 ASSERT(Debug::HasDebugInfo(shared)); 156 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); 157 ASSERT(original_code->IsCode()); 158 // Get the address of the call site in the active code. This is the 159 // place where the call to DebugBreakXXX is and where the IC 160 // normally would be. 161 Address addr = pc() - Assembler::kCallTargetAddressOffset; 162 // Return the address in the original code. This is the place where 163 // the call which has been overwritten by the DebugBreakXXX resides 164 // and the place where the inline cache system should look. 165 intptr_t delta = 166 original_code->instruction_start() - code->instruction_start(); 167 return addr + delta; 168} 169#endif 170 171 172static bool HasNormalObjectsInPrototypeChain(Isolate* isolate, 173 LookupResult* lookup, 174 Object* receiver) { 175 Object* end = lookup->IsProperty() 176 ? lookup->holder() : Object::cast(isolate->heap()->null_value()); 177 for (Object* current = receiver; 178 current != end; 179 current = current->GetPrototype()) { 180 if (current->IsJSObject() && 181 !JSObject::cast(current)->HasFastProperties() && 182 !current->IsJSGlobalProxy() && 183 !current->IsJSGlobalObject()) { 184 return true; 185 } 186 } 187 188 return false; 189} 190 191 192static bool TryRemoveInvalidPrototypeDependentStub(Code* target, 193 Object* receiver, 194 Object* name) { 195 InlineCacheHolderFlag cache_holder = 196 Code::ExtractCacheHolderFromFlags(target->flags()); 197 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()->IsNull()) { 204 // IC::GetCodeCacheHolder is not applicable. 205 return false; 206 } 207 Map* map = IC::GetCodeCacheHolder(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 return true; 221 } 222 223 return false; 224} 225 226 227IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { 228 IC::State state = target->ic_state(); 229 230 if (state != MONOMORPHIC || !name->IsString()) return state; 231 if (receiver->IsUndefined() || receiver->IsNull()) return state; 232 233 // For keyed load/store/call, the most likely cause of cache failure is 234 // that the key has changed. We do not distinguish between 235 // prototype and non-prototype failures for keyed access. 236 Code::Kind kind = target->kind(); 237 if (kind == Code::KEYED_LOAD_IC || 238 kind == Code::KEYED_STORE_IC || 239 kind == Code::KEYED_CALL_IC) { 240 return MONOMORPHIC; 241 } 242 243 // Remove the target from the code cache if it became invalid 244 // because of changes in the prototype chain to avoid hitting it 245 // again. 246 // Call stubs handle this later to allow extra IC state 247 // transitions. 248 if (kind != Code::CALL_IC && 249 TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { 250 return MONOMORPHIC_PROTOTYPE_FAILURE; 251 } 252 253 // The builtins object is special. It only changes when JavaScript 254 // builtins are loaded lazily. It is important to keep inline 255 // caches for the builtins object monomorphic. Therefore, if we get 256 // an inline cache miss for the builtins object after lazily loading 257 // JavaScript builtins, we return uninitialized as the state to 258 // force the inline cache back to monomorphic state. 259 if (receiver->IsJSBuiltinsObject()) { 260 return UNINITIALIZED; 261 } 262 263 return MONOMORPHIC; 264} 265 266 267RelocInfo::Mode IC::ComputeMode() { 268 Address addr = address(); 269 Code* code = Code::cast(isolate()->heap()->FindCodeObject(addr)); 270 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); 271 !it.done(); it.next()) { 272 RelocInfo* info = it.rinfo(); 273 if (info->pc() == addr) return info->rmode(); 274 } 275 UNREACHABLE(); 276 return RelocInfo::NONE; 277} 278 279 280Failure* IC::TypeError(const char* type, 281 Handle<Object> object, 282 Handle<Object> key) { 283 HandleScope scope(isolate()); 284 Handle<Object> args[2] = { key, object }; 285 Handle<Object> error = isolate()->factory()->NewTypeError( 286 type, HandleVector(args, 2)); 287 return isolate()->Throw(*error); 288} 289 290 291Failure* IC::ReferenceError(const char* type, Handle<String> name) { 292 HandleScope scope(isolate()); 293 Handle<Object> error = isolate()->factory()->NewReferenceError( 294 type, HandleVector(&name, 1)); 295 return isolate()->Throw(*error); 296} 297 298 299static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) { 300 bool was_uninitialized = 301 old_state == UNINITIALIZED || old_state == PREMONOMORPHIC; 302 bool is_uninitialized = 303 new_state == UNINITIALIZED || new_state == PREMONOMORPHIC; 304 return (was_uninitialized && !is_uninitialized) ? 1 : 305 (!was_uninitialized && is_uninitialized) ? -1 : 0; 306} 307 308 309void IC::PostPatching(Address address, Code* target, Code* old_target) { 310 if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { 311 return; 312 } 313 Code* host = target->GetHeap()->isolate()-> 314 inner_pointer_to_code_cache()->GetCacheEntry(address)->code; 315 if (host->kind() != Code::FUNCTION) return; 316 317 if (FLAG_type_info_threshold > 0 && 318 old_target->is_inline_cache_stub() && 319 target->is_inline_cache_stub()) { 320 int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), 321 target->ic_state()); 322 // Not all Code objects have TypeFeedbackInfo. 323 if (delta != 0 && host->type_feedback_info()->IsTypeFeedbackInfo()) { 324 TypeFeedbackInfo* info = 325 TypeFeedbackInfo::cast(host->type_feedback_info()); 326 info->set_ic_with_type_info_count( 327 info->ic_with_type_info_count() + delta); 328 } 329 } 330 if (FLAG_watch_ic_patching) { 331 host->set_profiler_ticks(0); 332 Isolate::Current()->runtime_profiler()->NotifyICChanged(); 333 } 334 // TODO(2029): When an optimized function is patched, it would 335 // be nice to propagate the corresponding type information to its 336 // unoptimized version for the benefit of later inlining. 337} 338 339 340void IC::Clear(Address address) { 341 Code* target = GetTargetAtAddress(address); 342 343 // Don't clear debug break inline cache as it will remove the break point. 344 if (target->ic_state() == DEBUG_BREAK) return; 345 346 switch (target->kind()) { 347 case Code::LOAD_IC: return LoadIC::Clear(address, target); 348 case Code::KEYED_LOAD_IC: 349 return KeyedLoadIC::Clear(address, target); 350 case Code::STORE_IC: return StoreIC::Clear(address, target); 351 case Code::KEYED_STORE_IC: 352 return KeyedStoreIC::Clear(address, target); 353 case Code::CALL_IC: return CallIC::Clear(address, target); 354 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); 355 case Code::UNARY_OP_IC: 356 case Code::BINARY_OP_IC: 357 case Code::COMPARE_IC: 358 case Code::TO_BOOLEAN_IC: 359 // Clearing these is tricky and does not 360 // make any performance difference. 361 return; 362 default: UNREACHABLE(); 363 } 364} 365 366 367void CallICBase::Clear(Address address, Code* target) { 368 bool contextual = CallICBase::Contextual::decode(target->extra_ic_state()); 369 State state = target->ic_state(); 370 if (state == UNINITIALIZED) return; 371 Code* code = 372 Isolate::Current()->stub_cache()->FindCallInitialize( 373 target->arguments_count(), 374 contextual ? RelocInfo::CODE_TARGET_CONTEXT : RelocInfo::CODE_TARGET, 375 target->kind()); 376 SetTargetAtAddress(address, code); 377} 378 379 380void KeyedLoadIC::Clear(Address address, Code* target) { 381 if (target->ic_state() == UNINITIALIZED) return; 382 // Make sure to also clear the map used in inline fast cases. If we 383 // do not clear these maps, cached code can keep objects alive 384 // through the embedded maps. 385 SetTargetAtAddress(address, initialize_stub()); 386} 387 388 389void LoadIC::Clear(Address address, Code* target) { 390 if (target->ic_state() == UNINITIALIZED) return; 391 SetTargetAtAddress(address, initialize_stub()); 392} 393 394 395void StoreIC::Clear(Address address, Code* target) { 396 if (target->ic_state() == UNINITIALIZED) return; 397 SetTargetAtAddress(address, 398 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) 399 ? initialize_stub_strict() 400 : initialize_stub()); 401} 402 403 404void KeyedStoreIC::Clear(Address address, Code* target) { 405 if (target->ic_state() == UNINITIALIZED) return; 406 SetTargetAtAddress(address, 407 (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) 408 ? initialize_stub_strict() 409 : initialize_stub()); 410} 411 412 413static bool HasInterceptorGetter(JSObject* object) { 414 return !object->GetNamedInterceptor()->getter()->IsUndefined(); 415} 416 417 418static void LookupForRead(Handle<Object> object, 419 Handle<String> name, 420 LookupResult* lookup) { 421 // Skip all the objects with named interceptors, but 422 // without actual getter. 423 while (true) { 424 object->Lookup(*name, lookup); 425 // Besides normal conditions (property not found or it's not 426 // an interceptor), bail out if lookup is not cacheable: we won't 427 // be able to IC it anyway and regular lookup should work fine. 428 if (!lookup->IsFound() 429 || (lookup->type() != INTERCEPTOR) 430 || !lookup->IsCacheable()) { 431 return; 432 } 433 434 Handle<JSObject> holder(lookup->holder()); 435 if (HasInterceptorGetter(*holder)) { 436 return; 437 } 438 439 holder->LocalLookupRealNamedProperty(*name, lookup); 440 if (lookup->IsProperty()) { 441 ASSERT(lookup->type() != INTERCEPTOR); 442 return; 443 } 444 445 Handle<Object> proto(holder->GetPrototype()); 446 if (proto->IsNull()) { 447 lookup->NotFound(); 448 return; 449 } 450 451 object = proto; 452 } 453} 454 455 456Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) { 457 Handle<Object> delegate = Execution::GetFunctionDelegate(object); 458 459 if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) { 460 // Patch the receiver and use the delegate as the function to 461 // invoke. This is used for invoking objects as if they were functions. 462 const int argc = target()->arguments_count(); 463 StackFrameLocator locator; 464 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 465 int index = frame->ComputeExpressionsCount() - (argc + 1); 466 frame->SetExpression(index, *object); 467 } 468 469 return delegate; 470} 471 472 473void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee, 474 Handle<Object> object) { 475 while (callee->IsJSFunctionProxy()) { 476 callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap()); 477 } 478 479 if (callee->IsJSFunction()) { 480 Handle<JSFunction> function = Handle<JSFunction>::cast(callee); 481 if (!function->shared()->is_classic_mode() || function->IsBuiltin()) { 482 // Do not wrap receiver for strict mode functions or for builtins. 483 return; 484 } 485 } 486 487 // And only wrap string, number or boolean. 488 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 489 // Change the receiver to the result of calling ToObject on it. 490 const int argc = this->target()->arguments_count(); 491 StackFrameLocator locator; 492 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 493 int index = frame->ComputeExpressionsCount() - (argc + 1); 494 frame->SetExpression(index, *isolate()->factory()->ToObject(object)); 495 } 496} 497 498 499MaybeObject* CallICBase::LoadFunction(State state, 500 Code::ExtraICState extra_ic_state, 501 Handle<Object> object, 502 Handle<String> name) { 503 // If the object is undefined or null it's illegal to try to get any 504 // of its properties; throw a TypeError in that case. 505 if (object->IsUndefined() || object->IsNull()) { 506 return TypeError("non_object_property_call", object, name); 507 } 508 509 // Check if the name is trivially convertible to an index and get 510 // the element if so. 511 uint32_t index; 512 if (name->AsArrayIndex(&index)) { 513 Handle<Object> result = Object::GetElement(object, index); 514 RETURN_IF_EMPTY_HANDLE(isolate(), result); 515 if (result->IsJSFunction()) return *result; 516 517 // Try to find a suitable function delegate for the object at hand. 518 result = TryCallAsFunction(result); 519 if (result->IsJSFunction()) return *result; 520 521 // Otherwise, it will fail in the lookup step. 522 } 523 524 // Lookup the property in the object. 525 LookupResult lookup(isolate()); 526 LookupForRead(object, name, &lookup); 527 528 if (!lookup.IsProperty()) { 529 // If the object does not have the requested property, check which 530 // exception we need to throw. 531 return IsContextual(object) 532 ? ReferenceError("not_defined", name) 533 : TypeError("undefined_method", object, name); 534 } 535 536 // Lookup is valid: Update inline cache and stub cache. 537 if (FLAG_use_ic) { 538 UpdateCaches(&lookup, state, extra_ic_state, object, name); 539 } 540 541 // Get the property. 542 PropertyAttributes attr; 543 Handle<Object> result = 544 Object::GetProperty(object, object, &lookup, name, &attr); 545 RETURN_IF_EMPTY_HANDLE(isolate(), result); 546 547 if (lookup.type() == INTERCEPTOR && attr == ABSENT) { 548 // If the object does not have the requested property, check which 549 // exception we need to throw. 550 return IsContextual(object) 551 ? ReferenceError("not_defined", name) 552 : TypeError("undefined_method", object, name); 553 } 554 555 ASSERT(!result->IsTheHole()); 556 557 // Make receiver an object if the callee requires it. Strict mode or builtin 558 // functions do not wrap the receiver, non-strict functions and objects 559 // called as functions do. 560 ReceiverToObjectIfRequired(result, object); 561 562 if (result->IsJSFunction()) { 563 Handle<JSFunction> function = Handle<JSFunction>::cast(result); 564#ifdef ENABLE_DEBUGGER_SUPPORT 565 // Handle stepping into a function if step into is active. 566 Debug* debug = isolate()->debug(); 567 if (debug->StepInActive()) { 568 // Protect the result in a handle as the debugger can allocate and might 569 // cause GC. 570 debug->HandleStepIn(function, object, fp(), false); 571 } 572#endif 573 return *function; 574 } 575 576 // Try to find a suitable function delegate for the object at hand. 577 result = TryCallAsFunction(result); 578 if (result->IsJSFunction()) return *result; 579 580 return TypeError("property_not_function", object, name); 581} 582 583 584bool CallICBase::TryUpdateExtraICState(LookupResult* lookup, 585 Handle<Object> object, 586 Code::ExtraICState* extra_ic_state) { 587 ASSERT(kind_ == Code::CALL_IC); 588 if (lookup->type() != CONSTANT_FUNCTION) return false; 589 JSFunction* function = lookup->GetConstantFunction(); 590 if (!function->shared()->HasBuiltinFunctionId()) return false; 591 592 // Fetch the arguments passed to the called function. 593 const int argc = target()->arguments_count(); 594 Address entry = isolate()->c_entry_fp(isolate()->thread_local_top()); 595 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 596 Arguments args(argc + 1, 597 &Memory::Object_at(fp + 598 StandardFrameConstants::kCallerSPOffset + 599 argc * kPointerSize)); 600 switch (function->shared()->builtin_function_id()) { 601 case kStringCharCodeAt: 602 case kStringCharAt: 603 if (object->IsString()) { 604 String* string = String::cast(*object); 605 // Check there's the right string value or wrapper in the receiver slot. 606 ASSERT(string == args[0] || string == JSValue::cast(args[0])->value()); 607 // If we're in the default (fastest) state and the index is 608 // out of bounds, update the state to record this fact. 609 if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB && 610 argc >= 1 && args[1]->IsNumber()) { 611 double index = DoubleToInteger(args.number_at(1)); 612 if (index < 0 || index >= string->length()) { 613 *extra_ic_state = 614 StringStubState::update(*extra_ic_state, 615 STRING_INDEX_OUT_OF_BOUNDS); 616 return true; 617 } 618 } 619 } 620 break; 621 default: 622 return false; 623 } 624 return false; 625} 626 627 628Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, 629 State state, 630 Code::ExtraICState extra_state, 631 Handle<Object> object, 632 Handle<String> name) { 633 int argc = target()->arguments_count(); 634 Handle<JSObject> holder(lookup->holder()); 635 switch (lookup->type()) { 636 case FIELD: { 637 int index = lookup->GetFieldIndex(); 638 return isolate()->stub_cache()->ComputeCallField( 639 argc, kind_, extra_state, name, object, holder, index); 640 } 641 case CONSTANT_FUNCTION: { 642 // Get the constant function and compute the code stub for this 643 // call; used for rewriting to monomorphic state and making sure 644 // that the code stub is in the stub cache. 645 Handle<JSFunction> function(lookup->GetConstantFunction()); 646 return isolate()->stub_cache()->ComputeCallConstant( 647 argc, kind_, extra_state, name, object, holder, function); 648 } 649 case NORMAL: { 650 // If we return a null handle, the IC will not be patched. 651 if (!object->IsJSObject()) return Handle<Code>::null(); 652 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 653 654 if (holder->IsGlobalObject()) { 655 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 656 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); 657 if (!cell->value()->IsJSFunction()) return Handle<Code>::null(); 658 Handle<JSFunction> function(JSFunction::cast(cell->value())); 659 return isolate()->stub_cache()->ComputeCallGlobal( 660 argc, kind_, extra_state, name, receiver, global, cell, function); 661 } else { 662 // There is only one shared stub for calling normalized 663 // properties. It does not traverse the prototype chain, so the 664 // property must be found in the receiver for the stub to be 665 // applicable. 666 if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); 667 return isolate()->stub_cache()->ComputeCallNormal( 668 argc, kind_, extra_state); 669 } 670 break; 671 } 672 case INTERCEPTOR: 673 ASSERT(HasInterceptorGetter(*holder)); 674 return isolate()->stub_cache()->ComputeCallInterceptor( 675 argc, kind_, extra_state, name, object, holder); 676 default: 677 return Handle<Code>::null(); 678 } 679} 680 681 682void CallICBase::UpdateCaches(LookupResult* lookup, 683 State state, 684 Code::ExtraICState extra_ic_state, 685 Handle<Object> object, 686 Handle<String> name) { 687 // Bail out if we didn't find a result. 688 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; 689 690 if (lookup->holder() != *object && 691 HasNormalObjectsInPrototypeChain( 692 isolate(), lookup, object->GetPrototype())) { 693 // Suppress optimization for prototype chains with slow properties objects 694 // in the middle. 695 return; 696 } 697 698 // Compute the number of arguments. 699 int argc = target()->arguments_count(); 700 bool had_proto_failure = false; 701 Handle<Code> code; 702 if (state == UNINITIALIZED) { 703 // This is the first time we execute this inline cache. 704 // Set the target to the pre monomorphic stub to delay 705 // setting the monomorphic state. 706 code = isolate()->stub_cache()->ComputeCallPreMonomorphic( 707 argc, kind_, extra_ic_state); 708 } else if (state == MONOMORPHIC) { 709 if (kind_ == Code::CALL_IC && 710 TryUpdateExtraICState(lookup, object, &extra_ic_state)) { 711 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 712 object, name); 713 } else if (kind_ == Code::CALL_IC && 714 TryRemoveInvalidPrototypeDependentStub(target(), 715 *object, 716 *name)) { 717 had_proto_failure = true; 718 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 719 object, name); 720 } else { 721 code = isolate()->stub_cache()->ComputeCallMegamorphic( 722 argc, kind_, extra_ic_state); 723 } 724 } else { 725 code = ComputeMonomorphicStub(lookup, state, extra_ic_state, 726 object, name); 727 } 728 729 // If there's no appropriate stub we simply avoid updating the caches. 730 if (code.is_null()) return; 731 732 // Patch the call site depending on the state of the cache. 733 if (state == UNINITIALIZED || 734 state == PREMONOMORPHIC || 735 state == MONOMORPHIC || 736 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 737 set_target(*code); 738 } else if (state == MEGAMORPHIC) { 739 // Cache code holding map should be consistent with 740 // GenerateMonomorphicCacheProbe. It is not the map which holds the stub. 741 Handle<JSObject> cache_object = object->IsJSObject() 742 ? Handle<JSObject>::cast(object) 743 : Handle<JSObject>(JSObject::cast(object->GetPrototype())); 744 // Update the stub cache. 745 isolate()->stub_cache()->Set(*name, cache_object->map(), *code); 746 } 747 748 if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE; 749 TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", 750 name, state, target()); 751} 752 753 754MaybeObject* KeyedCallIC::LoadFunction(State state, 755 Handle<Object> object, 756 Handle<Object> key) { 757 if (key->IsSymbol()) { 758 return CallICBase::LoadFunction(state, 759 Code::kNoExtraICState, 760 object, 761 Handle<String>::cast(key)); 762 } 763 764 if (object->IsUndefined() || object->IsNull()) { 765 return TypeError("non_object_property_call", object, key); 766 } 767 768 if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) { 769 int argc = target()->arguments_count(); 770 Handle<Map> map = 771 isolate()->factory()->non_strict_arguments_elements_map(); 772 if (object->IsJSObject() && 773 Handle<JSObject>::cast(object)->elements()->map() == *map) { 774 Handle<Code> code = isolate()->stub_cache()->ComputeCallArguments( 775 argc, Code::KEYED_CALL_IC); 776 set_target(*code); 777 TRACE_IC("KeyedCallIC", key, state, target()); 778 } else if (!object->IsAccessCheckNeeded()) { 779 Handle<Code> code = isolate()->stub_cache()->ComputeCallMegamorphic( 780 argc, Code::KEYED_CALL_IC, Code::kNoExtraICState); 781 set_target(*code); 782 TRACE_IC("KeyedCallIC", key, state, target()); 783 } 784 } 785 786 Handle<Object> result = GetProperty(object, key); 787 RETURN_IF_EMPTY_HANDLE(isolate(), result); 788 789 // Make receiver an object if the callee requires it. Strict mode or builtin 790 // functions do not wrap the receiver, non-strict functions and objects 791 // called as functions do. 792 ReceiverToObjectIfRequired(result, object); 793 if (result->IsJSFunction()) return *result; 794 795 result = TryCallAsFunction(result); 796 if (result->IsJSFunction()) return *result; 797 798 return TypeError("property_not_function", object, key); 799} 800 801 802MaybeObject* LoadIC::Load(State state, 803 Handle<Object> object, 804 Handle<String> name) { 805 // If the object is undefined or null it's illegal to try to get any 806 // of its properties; throw a TypeError in that case. 807 if (object->IsUndefined() || object->IsNull()) { 808 return TypeError("non_object_property_load", object, name); 809 } 810 811 if (FLAG_use_ic) { 812 // Use specialized code for getting the length of strings and 813 // string wrapper objects. The length property of string wrapper 814 // objects is read-only and therefore always returns the length of 815 // the underlying string value. See ECMA-262 15.5.5.1. 816 if ((object->IsString() || object->IsStringWrapper()) && 817 name->Equals(isolate()->heap()->length_symbol())) { 818 Handle<Code> stub; 819 if (state == UNINITIALIZED) { 820 stub = pre_monomorphic_stub(); 821 } else if (state == PREMONOMORPHIC) { 822 stub = object->IsString() 823 ? isolate()->builtins()->LoadIC_StringLength() 824 : isolate()->builtins()->LoadIC_StringWrapperLength(); 825 } else if (state == MONOMORPHIC && object->IsStringWrapper()) { 826 stub = isolate()->builtins()->LoadIC_StringWrapperLength(); 827 } else if (state != MEGAMORPHIC) { 828 stub = megamorphic_stub(); 829 } 830 if (!stub.is_null()) { 831 set_target(*stub); 832#ifdef DEBUG 833 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); 834#endif 835 } 836 // Get the string if we have a string wrapper object. 837 Handle<Object> string = object->IsJSValue() 838 ? Handle<Object>(Handle<JSValue>::cast(object)->value()) 839 : object; 840 return Smi::FromInt(String::cast(*string)->length()); 841 } 842 843 // Use specialized code for getting the length of arrays. 844 if (object->IsJSArray() && 845 name->Equals(isolate()->heap()->length_symbol())) { 846 Handle<Code> stub; 847 if (state == UNINITIALIZED) { 848 stub = pre_monomorphic_stub(); 849 } else if (state == PREMONOMORPHIC) { 850 stub = isolate()->builtins()->LoadIC_ArrayLength(); 851 } else if (state != MEGAMORPHIC) { 852 stub = megamorphic_stub(); 853 } 854 if (!stub.is_null()) { 855 set_target(*stub); 856#ifdef DEBUG 857 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); 858#endif 859 } 860 return JSArray::cast(*object)->length(); 861 } 862 863 // Use specialized code for getting prototype of functions. 864 if (object->IsJSFunction() && 865 name->Equals(isolate()->heap()->prototype_symbol()) && 866 Handle<JSFunction>::cast(object)->should_have_prototype()) { 867 Handle<Code> stub; 868 if (state == UNINITIALIZED) { 869 stub = pre_monomorphic_stub(); 870 } else if (state == PREMONOMORPHIC) { 871 stub = isolate()->builtins()->LoadIC_FunctionPrototype(); 872 } else if (state != MEGAMORPHIC) { 873 stub = megamorphic_stub(); 874 } 875 if (!stub.is_null()) { 876 set_target(*stub); 877#ifdef DEBUG 878 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); 879#endif 880 } 881 return Accessors::FunctionGetPrototype(*object, 0); 882 } 883 } 884 885 // Check if the name is trivially convertible to an index and get 886 // the element if so. 887 uint32_t index; 888 if (name->AsArrayIndex(&index)) return object->GetElement(index); 889 890 // Named lookup in the object. 891 LookupResult lookup(isolate()); 892 LookupForRead(object, name, &lookup); 893 894 // If we did not find a property, check if we need to throw an exception. 895 if (!lookup.IsProperty()) { 896 if (IsContextual(object)) { 897 return ReferenceError("not_defined", name); 898 } 899 LOG(isolate(), SuspectReadEvent(*name, *object)); 900 } 901 902 // Update inline cache and stub cache. 903 if (FLAG_use_ic) { 904 UpdateCaches(&lookup, state, object, name); 905 } 906 907 PropertyAttributes attr; 908 if (lookup.IsFound() && 909 (lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) { 910 // Get the property. 911 Handle<Object> result = 912 Object::GetProperty(object, object, &lookup, name, &attr); 913 RETURN_IF_EMPTY_HANDLE(isolate(), result); 914 // If the property is not present, check if we need to throw an 915 // exception. 916 if (attr == ABSENT && IsContextual(object)) { 917 return ReferenceError("not_defined", name); 918 } 919 return *result; 920 } 921 922 // Get the property. 923 return object->GetProperty(*object, &lookup, *name, &attr); 924} 925 926 927void LoadIC::UpdateCaches(LookupResult* lookup, 928 State state, 929 Handle<Object> object, 930 Handle<String> name) { 931 // Bail out if the result is not cacheable. 932 if (!lookup->IsCacheable()) return; 933 934 // Loading properties from values is not common, so don't try to 935 // deal with non-JS objects here. 936 if (!object->IsJSObject()) return; 937 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 938 939 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; 940 941 // Compute the code stub for this load. 942 Handle<Code> code; 943 if (state == UNINITIALIZED) { 944 // This is the first time we execute this inline cache. 945 // Set the target to the pre monomorphic stub to delay 946 // setting the monomorphic state. 947 code = pre_monomorphic_stub(); 948 } else if (!lookup->IsProperty()) { 949 // Nonexistent property. The result is undefined. 950 code = isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); 951 } else { 952 // Compute monomorphic stub. 953 Handle<JSObject> holder(lookup->holder()); 954 switch (lookup->type()) { 955 case FIELD: 956 code = isolate()->stub_cache()->ComputeLoadField( 957 name, receiver, holder, lookup->GetFieldIndex()); 958 break; 959 case CONSTANT_FUNCTION: { 960 Handle<JSFunction> constant(lookup->GetConstantFunction()); 961 code = isolate()->stub_cache()->ComputeLoadConstant( 962 name, receiver, holder, constant); 963 break; 964 } 965 case NORMAL: 966 if (holder->IsGlobalObject()) { 967 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); 968 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); 969 code = isolate()->stub_cache()->ComputeLoadGlobal( 970 name, receiver, global, cell, lookup->IsDontDelete()); 971 } else { 972 // There is only one shared stub for loading normalized 973 // properties. It does not traverse the prototype chain, so the 974 // property must be found in the receiver for the stub to be 975 // applicable. 976 if (!holder.is_identical_to(receiver)) return; 977 code = isolate()->stub_cache()->ComputeLoadNormal(); 978 } 979 break; 980 case CALLBACKS: { 981 Handle<Object> callback_object(lookup->GetCallbackObject()); 982 if (!callback_object->IsAccessorInfo()) return; 983 Handle<AccessorInfo> callback = 984 Handle<AccessorInfo>::cast(callback_object); 985 if (v8::ToCData<Address>(callback->getter()) == 0) return; 986 code = isolate()->stub_cache()->ComputeLoadCallback( 987 name, receiver, holder, callback); 988 break; 989 } 990 case INTERCEPTOR: 991 ASSERT(HasInterceptorGetter(*holder)); 992 code = isolate()->stub_cache()->ComputeLoadInterceptor( 993 name, receiver, holder); 994 break; 995 default: 996 return; 997 } 998 } 999 1000 // Patch the call site depending on the state of the cache. 1001 if (state == UNINITIALIZED || 1002 state == PREMONOMORPHIC || 1003 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 1004 set_target(*code); 1005 } else if (state == MONOMORPHIC) { 1006 // We are transitioning from monomorphic to megamorphic case. 1007 // Place the current monomorphic stub and stub compiled for 1008 // the receiver into stub cache. 1009 Map* map = target()->FindFirstMap(); 1010 if (map != NULL) { 1011 isolate()->stub_cache()->Set(*name, map, target()); 1012 } 1013 isolate()->stub_cache()->Set(*name, receiver->map(), *code); 1014 1015 set_target(*megamorphic_stub()); 1016 } else if (state == MEGAMORPHIC) { 1017 // Cache code holding map should be consistent with 1018 // GenerateMonomorphicCacheProbe. 1019 isolate()->stub_cache()->Set(*name, receiver->map(), *code); 1020 } 1021 1022 TRACE_IC("LoadIC", name, state, target()); 1023} 1024 1025 1026Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck( 1027 bool is_js_array, 1028 ElementsKind elements_kind, 1029 KeyedAccessGrowMode grow_mode) { 1030 ASSERT(grow_mode == DO_NOT_ALLOW_JSARRAY_GROWTH); 1031 return KeyedLoadElementStub(elements_kind).GetCode(); 1032} 1033 1034 1035Handle<Code> KeyedLoadIC::ComputePolymorphicStub( 1036 MapHandleList* receiver_maps, 1037 StrictModeFlag strict_mode, 1038 KeyedAccessGrowMode growth_mode) { 1039 CodeHandleList handler_ics(receiver_maps->length()); 1040 for (int i = 0; i < receiver_maps->length(); ++i) { 1041 Handle<Map> receiver_map = receiver_maps->at(i); 1042 Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck( 1043 receiver_map, strict_mode, growth_mode); 1044 handler_ics.Add(cached_stub); 1045 } 1046 KeyedLoadStubCompiler compiler(isolate()); 1047 Handle<Code> code = compiler.CompileLoadPolymorphic( 1048 receiver_maps, &handler_ics); 1049 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); 1050 PROFILE(isolate(), 1051 CodeCreateEvent(Logger::KEYED_LOAD_MEGAMORPHIC_IC_TAG, *code, 0)); 1052 return code; 1053} 1054 1055 1056MaybeObject* KeyedLoadIC::Load(State state, 1057 Handle<Object> object, 1058 Handle<Object> key, 1059 bool force_generic_stub) { 1060 // Check for values that can be converted into a symbol. 1061 // TODO(1295): Remove this code. 1062 if (key->IsHeapNumber() && 1063 isnan(Handle<HeapNumber>::cast(key)->value())) { 1064 key = isolate()->factory()->nan_symbol(); 1065 } else if (key->IsUndefined()) { 1066 key = isolate()->factory()->undefined_symbol(); 1067 } 1068 1069 if (key->IsSymbol()) { 1070 Handle<String> name = Handle<String>::cast(key); 1071 1072 // If the object is undefined or null it's illegal to try to get any 1073 // of its properties; throw a TypeError in that case. 1074 if (object->IsUndefined() || object->IsNull()) { 1075 return TypeError("non_object_property_load", object, name); 1076 } 1077 1078 if (FLAG_use_ic) { 1079 // TODO(1073): don't ignore the current stub state. 1080 1081 // Use specialized code for getting the length of strings. 1082 if (object->IsString() && 1083 name->Equals(isolate()->heap()->length_symbol())) { 1084 Handle<String> string = Handle<String>::cast(object); 1085 Handle<Code> code = 1086 isolate()->stub_cache()->ComputeKeyedLoadStringLength(name, string); 1087 ASSERT(!code.is_null()); 1088 set_target(*code); 1089 TRACE_IC("KeyedLoadIC", name, state, target()); 1090 return Smi::FromInt(string->length()); 1091 } 1092 1093 // Use specialized code for getting the length of arrays. 1094 if (object->IsJSArray() && 1095 name->Equals(isolate()->heap()->length_symbol())) { 1096 Handle<JSArray> array = Handle<JSArray>::cast(object); 1097 Handle<Code> code = 1098 isolate()->stub_cache()->ComputeKeyedLoadArrayLength(name, array); 1099 ASSERT(!code.is_null()); 1100 set_target(*code); 1101 TRACE_IC("KeyedLoadIC", name, state, target()); 1102 return array->length(); 1103 } 1104 1105 // Use specialized code for getting prototype of functions. 1106 if (object->IsJSFunction() && 1107 name->Equals(isolate()->heap()->prototype_symbol()) && 1108 Handle<JSFunction>::cast(object)->should_have_prototype()) { 1109 Handle<JSFunction> function = Handle<JSFunction>::cast(object); 1110 Handle<Code> code = 1111 isolate()->stub_cache()->ComputeKeyedLoadFunctionPrototype( 1112 name, function); 1113 ASSERT(!code.is_null()); 1114 set_target(*code); 1115 TRACE_IC("KeyedLoadIC", name, state, target()); 1116 return Accessors::FunctionGetPrototype(*object, 0); 1117 } 1118 } 1119 1120 // Check if the name is trivially convertible to an index and get 1121 // the element or char if so. 1122 uint32_t index = 0; 1123 if (name->AsArrayIndex(&index)) { 1124 // Rewrite to the generic keyed load stub. 1125 if (FLAG_use_ic) set_target(*generic_stub()); 1126 return Runtime::GetElementOrCharAt(isolate(), object, index); 1127 } 1128 1129 // Named lookup. 1130 LookupResult lookup(isolate()); 1131 LookupForRead(object, name, &lookup); 1132 1133 // If we did not find a property, check if we need to throw an exception. 1134 if (!lookup.IsProperty() && IsContextual(object)) { 1135 return ReferenceError("not_defined", name); 1136 } 1137 1138 if (FLAG_use_ic) { 1139 UpdateCaches(&lookup, state, object, name); 1140 } 1141 1142 PropertyAttributes attr; 1143 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) { 1144 // Get the property. 1145 Handle<Object> result = 1146 Object::GetProperty(object, object, &lookup, name, &attr); 1147 RETURN_IF_EMPTY_HANDLE(isolate(), result); 1148 // If the property is not present, check if we need to throw an 1149 // exception. 1150 if (attr == ABSENT && IsContextual(object)) { 1151 return ReferenceError("not_defined", name); 1152 } 1153 return *result; 1154 } 1155 1156 return object->GetProperty(*object, &lookup, *name, &attr); 1157 } 1158 1159 // Do not use ICs for objects that require access checks (including 1160 // the global object). 1161 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1162 1163 if (use_ic) { 1164 Handle<Code> stub = generic_stub(); 1165 if (!force_generic_stub) { 1166 if (object->IsString() && key->IsNumber()) { 1167 if (state == UNINITIALIZED) { 1168 stub = string_stub(); 1169 } 1170 } else if (object->IsJSObject()) { 1171 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1172 if (receiver->elements()->map() == 1173 isolate()->heap()->non_strict_arguments_elements_map()) { 1174 stub = non_strict_arguments_stub(); 1175 } else if (receiver->HasIndexedInterceptor()) { 1176 stub = indexed_interceptor_stub(); 1177 } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { 1178 stub = ComputeStub(receiver, LOAD, kNonStrictMode, stub); 1179 } 1180 } 1181 } else { 1182 TRACE_GENERIC_IC("KeyedLoadIC", "force generic"); 1183 } 1184 if (!stub.is_null()) set_target(*stub); 1185 } 1186 1187 TRACE_IC("KeyedLoadIC", key, state, target()); 1188 1189 // Get the property. 1190 return Runtime::GetObjectProperty(isolate(), object, key); 1191} 1192 1193 1194void KeyedLoadIC::UpdateCaches(LookupResult* lookup, 1195 State state, 1196 Handle<Object> object, 1197 Handle<String> name) { 1198 // Bail out if we didn't find a result. 1199 if (!lookup->IsProperty() || !lookup->IsCacheable()) return; 1200 1201 if (!object->IsJSObject()) return; 1202 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1203 1204 if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; 1205 1206 // Compute the code stub for this load. 1207 Handle<Code> code; 1208 1209 if (state == UNINITIALIZED) { 1210 // This is the first time we execute this inline cache. 1211 // Set the target to the pre monomorphic stub to delay 1212 // setting the monomorphic state. 1213 code = pre_monomorphic_stub(); 1214 } else { 1215 // Compute a monomorphic stub. 1216 Handle<JSObject> holder(lookup->holder()); 1217 switch (lookup->type()) { 1218 case FIELD: 1219 code = isolate()->stub_cache()->ComputeKeyedLoadField( 1220 name, receiver, holder, lookup->GetFieldIndex()); 1221 break; 1222 case CONSTANT_FUNCTION: { 1223 Handle<JSFunction> constant(lookup->GetConstantFunction()); 1224 code = isolate()->stub_cache()->ComputeKeyedLoadConstant( 1225 name, receiver, holder, constant); 1226 break; 1227 } 1228 case CALLBACKS: { 1229 Handle<Object> callback_object(lookup->GetCallbackObject()); 1230 if (!callback_object->IsAccessorInfo()) return; 1231 Handle<AccessorInfo> callback = 1232 Handle<AccessorInfo>::cast(callback_object); 1233 if (v8::ToCData<Address>(callback->getter()) == 0) return; 1234 code = isolate()->stub_cache()->ComputeKeyedLoadCallback( 1235 name, receiver, holder, callback); 1236 break; 1237 } 1238 case INTERCEPTOR: 1239 ASSERT(HasInterceptorGetter(lookup->holder())); 1240 code = isolate()->stub_cache()->ComputeKeyedLoadInterceptor( 1241 name, receiver, holder); 1242 break; 1243 default: 1244 // Always rewrite to the generic case so that we do not 1245 // repeatedly try to rewrite. 1246 code = generic_stub(); 1247 break; 1248 } 1249 } 1250 1251 // Patch the call site depending on the state of the cache. Make 1252 // sure to always rewrite from monomorphic to megamorphic. 1253 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); 1254 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { 1255 set_target(*code); 1256 } else if (state == MONOMORPHIC) { 1257 set_target(*megamorphic_stub()); 1258 } 1259 1260 TRACE_IC("KeyedLoadIC", name, state, target()); 1261} 1262 1263 1264static bool StoreICableLookup(LookupResult* lookup) { 1265 // Bail out if we didn't find a result. 1266 if (!lookup->IsFound() || lookup->type() == NULL_DESCRIPTOR) return false; 1267 1268 // Bail out if inline caching is not allowed. 1269 if (!lookup->IsCacheable()) return false; 1270 1271 // If the property is read-only, we leave the IC in its current state. 1272 if (lookup->IsReadOnly()) return false; 1273 1274 return true; 1275} 1276 1277 1278static bool LookupForWrite(Handle<JSObject> receiver, 1279 Handle<String> name, 1280 LookupResult* lookup) { 1281 receiver->LocalLookup(*name, lookup); 1282 if (!StoreICableLookup(lookup)) { 1283 return false; 1284 } 1285 1286 if (lookup->type() == INTERCEPTOR && 1287 receiver->GetNamedInterceptor()->setter()->IsUndefined()) { 1288 receiver->LocalLookupRealNamedProperty(*name, lookup); 1289 return StoreICableLookup(lookup); 1290 } 1291 1292 return true; 1293} 1294 1295 1296MaybeObject* StoreIC::Store(State state, 1297 StrictModeFlag strict_mode, 1298 Handle<Object> object, 1299 Handle<String> name, 1300 Handle<Object> value) { 1301 if (!object->IsJSObject()) { 1302 // Handle proxies. 1303 if (object->IsJSProxy()) { 1304 return JSProxy::cast(*object)-> 1305 SetProperty(*name, *value, NONE, strict_mode); 1306 } 1307 1308 // If the object is undefined or null it's illegal to try to set any 1309 // properties on it; throw a TypeError in that case. 1310 if (object->IsUndefined() || object->IsNull()) { 1311 return TypeError("non_object_property_store", object, name); 1312 } 1313 1314 // The length property of string values is read-only. Throw in strict mode. 1315 if (strict_mode == kStrictMode && object->IsString() && 1316 name->Equals(isolate()->heap()->length_symbol())) { 1317 return TypeError("strict_read_only_property", object, name); 1318 } 1319 // Ignore other stores where the receiver is not a JSObject. 1320 // TODO(1475): Must check prototype chains of object wrappers. 1321 return *value; 1322 } 1323 1324 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1325 1326 // Check if the given name is an array index. 1327 uint32_t index; 1328 if (name->AsArrayIndex(&index)) { 1329 Handle<Object> result = 1330 JSObject::SetElement(receiver, index, value, NONE, strict_mode); 1331 RETURN_IF_EMPTY_HANDLE(isolate(), result); 1332 return *value; 1333 } 1334 1335 // Use specialized code for setting the length of arrays with fast 1336 // properties. Slow properties might indicate redefinition of the 1337 // length property. 1338 if (receiver->IsJSArray() && 1339 name->Equals(isolate()->heap()->length_symbol()) && 1340 Handle<JSArray>::cast(receiver)->AllowsSetElementsLength() && 1341 receiver->HasFastProperties()) { 1342#ifdef DEBUG 1343 if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n"); 1344#endif 1345 Handle<Code> stub = (strict_mode == kStrictMode) 1346 ? isolate()->builtins()->StoreIC_ArrayLength_Strict() 1347 : isolate()->builtins()->StoreIC_ArrayLength(); 1348 set_target(*stub); 1349 return receiver->SetProperty(*name, *value, NONE, strict_mode); 1350 } 1351 1352 // Lookup the property locally in the receiver. 1353 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { 1354 LookupResult lookup(isolate()); 1355 1356 if (LookupForWrite(receiver, name, &lookup)) { 1357 // Generate a stub for this store. 1358 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); 1359 } else { 1360 // Strict mode doesn't allow setting non-existent global property 1361 // or an assignment to a read only property. 1362 if (strict_mode == kStrictMode) { 1363 if (lookup.IsProperty() && lookup.IsReadOnly()) { 1364 return TypeError("strict_read_only_property", object, name); 1365 } else if (IsContextual(object)) { 1366 return ReferenceError("not_defined", name); 1367 } 1368 } 1369 } 1370 } 1371 1372 if (receiver->IsJSGlobalProxy()) { 1373 // TODO(ulan): find out why we patch this site even with --no-use-ic 1374 // Generate a generic stub that goes to the runtime when we see a global 1375 // proxy as receiver. 1376 Handle<Code> stub = (strict_mode == kStrictMode) 1377 ? global_proxy_stub_strict() 1378 : global_proxy_stub(); 1379 if (target() != *stub) { 1380 set_target(*stub); 1381 TRACE_IC("StoreIC", name, state, target()); 1382 } 1383 } 1384 1385 // Set the property. 1386 return receiver->SetProperty(*name, *value, NONE, strict_mode); 1387} 1388 1389 1390void StoreIC::UpdateCaches(LookupResult* lookup, 1391 State state, 1392 StrictModeFlag strict_mode, 1393 Handle<JSObject> receiver, 1394 Handle<String> name, 1395 Handle<Object> value) { 1396 ASSERT(!receiver->IsJSGlobalProxy()); 1397 ASSERT(StoreICableLookup(lookup)); 1398 // These are not cacheable, so we never see such LookupResults here. 1399 ASSERT(lookup->type() != HANDLER); 1400 // We get only called for properties or transitions, see StoreICableLookup. 1401 ASSERT(lookup->type() != NULL_DESCRIPTOR); 1402 1403 // If the property has a non-field type allowing map transitions 1404 // where there is extra room in the object, we leave the IC in its 1405 // current state. 1406 PropertyType type = lookup->type(); 1407 1408 // Compute the code stub for this store; used for rewriting to 1409 // monomorphic state and making sure that the code stub is in the 1410 // stub cache. 1411 Handle<Code> code; 1412 switch (type) { 1413 case FIELD: 1414 code = isolate()->stub_cache()->ComputeStoreField(name, 1415 receiver, 1416 lookup->GetFieldIndex(), 1417 Handle<Map>::null(), 1418 strict_mode); 1419 break; 1420 case MAP_TRANSITION: { 1421 if (lookup->GetAttributes() != NONE) return; 1422 Handle<Map> transition(lookup->GetTransitionMap()); 1423 int index = transition->PropertyIndexFor(*name); 1424 code = isolate()->stub_cache()->ComputeStoreField( 1425 name, receiver, index, transition, strict_mode); 1426 break; 1427 } 1428 case NORMAL: 1429 if (receiver->IsGlobalObject()) { 1430 // The stub generated for the global object picks the value directly 1431 // from the property cell. So the property must be directly on the 1432 // global object. 1433 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 1434 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); 1435 code = isolate()->stub_cache()->ComputeStoreGlobal( 1436 name, global, cell, strict_mode); 1437 } else { 1438 if (lookup->holder() != *receiver) return; 1439 code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); 1440 } 1441 break; 1442 case CALLBACKS: { 1443 Handle<Object> callback_object(lookup->GetCallbackObject()); 1444 if (!callback_object->IsAccessorInfo()) return; 1445 Handle<AccessorInfo> callback = 1446 Handle<AccessorInfo>::cast(callback_object); 1447 if (v8::ToCData<Address>(callback->setter()) == 0) return; 1448 code = isolate()->stub_cache()->ComputeStoreCallback( 1449 name, receiver, callback, strict_mode); 1450 break; 1451 } 1452 case INTERCEPTOR: 1453 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); 1454 code = isolate()->stub_cache()->ComputeStoreInterceptor( 1455 name, receiver, strict_mode); 1456 break; 1457 case CONSTANT_FUNCTION: 1458 case CONSTANT_TRANSITION: 1459 case ELEMENTS_TRANSITION: 1460 return; 1461 case HANDLER: 1462 case NULL_DESCRIPTOR: 1463 UNREACHABLE(); 1464 return; 1465 } 1466 1467 // Patch the call site depending on the state of the cache. 1468 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { 1469 set_target(*code); 1470 } else if (state == MONOMORPHIC) { 1471 // Only move to megamorphic if the target changes. 1472 if (target() != *code) { 1473 set_target((strict_mode == kStrictMode) 1474 ? megamorphic_stub_strict() 1475 : megamorphic_stub()); 1476 } 1477 } else if (state == MEGAMORPHIC) { 1478 // Update the stub cache. 1479 isolate()->stub_cache()->Set(*name, receiver->map(), *code); 1480 } 1481 1482 TRACE_IC("StoreIC", name, state, target()); 1483} 1484 1485 1486static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, 1487 Handle<Map> new_receiver_map) { 1488 ASSERT(!new_receiver_map.is_null()); 1489 for (int current = 0; current < receiver_maps->length(); ++current) { 1490 if (!receiver_maps->at(current).is_null() && 1491 receiver_maps->at(current).is_identical_to(new_receiver_map)) { 1492 return false; 1493 } 1494 } 1495 receiver_maps->Add(new_receiver_map); 1496 return true; 1497} 1498 1499 1500void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub, 1501 MapHandleList* result) { 1502 ASSERT(stub->is_inline_cache_stub()); 1503 if (!string_stub().is_null() && stub.is_identical_to(string_stub())) { 1504 return result->Add(isolate()->factory()->string_map()); 1505 } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) { 1506 if (stub->ic_state() == MONOMORPHIC) { 1507 result->Add(Handle<Map>(stub->FindFirstMap())); 1508 } else { 1509 ASSERT(stub->ic_state() == MEGAMORPHIC); 1510 AssertNoAllocation no_allocation; 1511 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 1512 for (RelocIterator it(*stub, mask); !it.done(); it.next()) { 1513 RelocInfo* info = it.rinfo(); 1514 Handle<Object> object(info->target_object()); 1515 ASSERT(object->IsMap()); 1516 AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); 1517 } 1518 } 1519 } 1520} 1521 1522 1523Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, 1524 StubKind stub_kind, 1525 StrictModeFlag strict_mode, 1526 Handle<Code> generic_stub) { 1527 State ic_state = target()->ic_state(); 1528 KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind) 1529 ? ALLOW_JSARRAY_GROWTH 1530 : DO_NOT_ALLOW_JSARRAY_GROWTH; 1531 1532 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS 1533 // via megamorphic stubs, since they don't have a map in their relocation info 1534 // and so the stubs can't be harvested for the object needed for a map check. 1535 if (target()->type() != NORMAL) { 1536 TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type"); 1537 return generic_stub; 1538 } 1539 1540 bool monomorphic = false; 1541 MapHandleList target_receiver_maps; 1542 if (ic_state != UNINITIALIZED && ic_state != PREMONOMORPHIC) { 1543 GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps); 1544 } 1545 if (!IsTransitionStubKind(stub_kind)) { 1546 if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { 1547 monomorphic = true; 1548 } else { 1549 if (ic_state == MONOMORPHIC) { 1550 // The first time a receiver is seen that is a transitioned version of 1551 // the previous monomorphic receiver type, assume the new ElementsKind 1552 // is the monomorphic type. This benefits global arrays that only 1553 // transition once, and all call sites accessing them are faster if they 1554 // remain monomorphic. If this optimistic assumption is not true, the IC 1555 // will miss again and it will become polymorphic and support both the 1556 // untransitioned and transitioned maps. 1557 monomorphic = IsMoreGeneralElementsKindTransition( 1558 target_receiver_maps.at(0)->elements_kind(), 1559 receiver->GetElementsKind()); 1560 } 1561 } 1562 } 1563 1564 if (monomorphic) { 1565 return ComputeMonomorphicStub( 1566 receiver, stub_kind, strict_mode, generic_stub); 1567 } 1568 ASSERT(target() != *generic_stub); 1569 1570 // Determine the list of receiver maps that this call site has seen, 1571 // adding the map that was just encountered. 1572 Handle<Map> receiver_map(receiver->map()); 1573 bool map_added = 1574 AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map); 1575 if (IsTransitionStubKind(stub_kind)) { 1576 Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind); 1577 map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); 1578 } 1579 if (!map_added) { 1580 // If the miss wasn't due to an unseen map, a polymorphic stub 1581 // won't help, use the generic stub. 1582 TRACE_GENERIC_IC("KeyedIC", "same map added twice"); 1583 return generic_stub; 1584 } 1585 1586 // If the maximum number of receiver maps has been exceeded, use the generic 1587 // version of the IC. 1588 if (target_receiver_maps.length() > kMaxKeyedPolymorphism) { 1589 TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded"); 1590 return generic_stub; 1591 } 1592 1593 if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) == 1594 ALLOW_JSARRAY_GROWTH)) { 1595 grow_mode = ALLOW_JSARRAY_GROWTH; 1596 } 1597 1598 Handle<PolymorphicCodeCache> cache = 1599 isolate()->factory()->polymorphic_code_cache(); 1600 Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode, 1601 strict_mode); 1602 Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, extra_state); 1603 Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); 1604 if (probe->IsCode()) return Handle<Code>::cast(probe); 1605 1606 Handle<Code> stub = 1607 ComputePolymorphicStub(&target_receiver_maps, strict_mode, grow_mode); 1608 PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub); 1609 return stub; 1610} 1611 1612 1613Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck( 1614 Handle<Map> receiver_map, 1615 StrictModeFlag strict_mode, 1616 KeyedAccessGrowMode grow_mode) { 1617 if ((receiver_map->instance_type() & kNotStringTag) == 0) { 1618 ASSERT(!string_stub().is_null()); 1619 return string_stub(); 1620 } else { 1621 ASSERT(receiver_map->has_dictionary_elements() || 1622 receiver_map->has_fast_elements() || 1623 receiver_map->has_fast_smi_only_elements() || 1624 receiver_map->has_fast_double_elements() || 1625 receiver_map->has_external_array_elements()); 1626 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 1627 return GetElementStubWithoutMapCheck(is_js_array, 1628 receiver_map->elements_kind(), 1629 grow_mode); 1630 } 1631} 1632 1633 1634Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<JSObject> receiver, 1635 StubKind stub_kind, 1636 StrictModeFlag strict_mode, 1637 Handle<Code> generic_stub) { 1638 if (receiver->HasFastElements() || 1639 receiver->HasFastSmiOnlyElements() || 1640 receiver->HasExternalArrayElements() || 1641 receiver->HasFastDoubleElements() || 1642 receiver->HasDictionaryElements()) { 1643 return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( 1644 receiver, stub_kind, strict_mode); 1645 } else { 1646 return generic_stub; 1647 } 1648} 1649 1650 1651Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver, 1652 StubKind stub_kind) { 1653 switch (stub_kind) { 1654 case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: 1655 case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: 1656 case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: 1657 case KeyedIC::STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: 1658 return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); 1659 break; 1660 case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: 1661 case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: 1662 return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); 1663 break; 1664 default: 1665 UNREACHABLE(); 1666 return Handle<Map>::null(); 1667 } 1668} 1669 1670 1671Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck( 1672 bool is_js_array, 1673 ElementsKind elements_kind, 1674 KeyedAccessGrowMode grow_mode) { 1675 return KeyedStoreElementStub(is_js_array, elements_kind, grow_mode).GetCode(); 1676} 1677 1678 1679Handle<Code> KeyedStoreIC::ComputePolymorphicStub( 1680 MapHandleList* receiver_maps, 1681 StrictModeFlag strict_mode, 1682 KeyedAccessGrowMode grow_mode) { 1683 // Collect MONOMORPHIC stubs for all target_receiver_maps. 1684 CodeHandleList handler_ics(receiver_maps->length()); 1685 MapHandleList transitioned_maps(receiver_maps->length()); 1686 for (int i = 0; i < receiver_maps->length(); ++i) { 1687 Handle<Map> receiver_map(receiver_maps->at(i)); 1688 Handle<Code> cached_stub; 1689 Handle<Map> transitioned_map = 1690 receiver_map->FindTransitionedMap(receiver_maps); 1691 if (!transitioned_map.is_null()) { 1692 cached_stub = ElementsTransitionAndStoreStub( 1693 receiver_map->elements_kind(), // original elements_kind 1694 transitioned_map->elements_kind(), 1695 receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array 1696 strict_mode, grow_mode).GetCode(); 1697 } else { 1698 cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map, 1699 strict_mode, 1700 grow_mode); 1701 } 1702 ASSERT(!cached_stub.is_null()); 1703 handler_ics.Add(cached_stub); 1704 transitioned_maps.Add(transitioned_map); 1705 } 1706 KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode); 1707 Handle<Code> code = compiler.CompileStorePolymorphic( 1708 receiver_maps, &handler_ics, &transitioned_maps); 1709 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); 1710 PROFILE(isolate(), 1711 CodeCreateEvent(Logger::KEYED_STORE_MEGAMORPHIC_IC_TAG, *code, 0)); 1712 return code; 1713} 1714 1715 1716KeyedIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver, 1717 Handle<Object> key, 1718 Handle<Object> value) { 1719 ASSERT(key->IsSmi()); 1720 int index = Smi::cast(*key)->value(); 1721 bool allow_growth = receiver->IsJSArray() && 1722 JSArray::cast(*receiver)->length()->IsSmi() && 1723 index >= Smi::cast(JSArray::cast(*receiver)->length())->value(); 1724 1725 if (allow_growth) { 1726 // Handle growing array in stub if necessary. 1727 if (receiver->HasFastSmiOnlyElements()) { 1728 if (value->IsHeapNumber()) { 1729 return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE; 1730 } 1731 if (value->IsHeapObject()) { 1732 return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT; 1733 } 1734 } else if (receiver->HasFastDoubleElements()) { 1735 if (!value->IsSmi() && !value->IsHeapNumber()) { 1736 return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT; 1737 } 1738 } 1739 return STORE_AND_GROW_NO_TRANSITION; 1740 } else { 1741 // Handle only in-bounds elements accesses. 1742 if (receiver->HasFastSmiOnlyElements()) { 1743 if (value->IsHeapNumber()) { 1744 return STORE_TRANSITION_SMI_TO_DOUBLE; 1745 } else if (value->IsHeapObject()) { 1746 return STORE_TRANSITION_SMI_TO_OBJECT; 1747 } 1748 } else if (receiver->HasFastDoubleElements()) { 1749 if (!value->IsSmi() && !value->IsHeapNumber()) { 1750 return STORE_TRANSITION_DOUBLE_TO_OBJECT; 1751 } 1752 } 1753 return STORE_NO_TRANSITION; 1754 } 1755} 1756 1757 1758MaybeObject* KeyedStoreIC::Store(State state, 1759 StrictModeFlag strict_mode, 1760 Handle<Object> object, 1761 Handle<Object> key, 1762 Handle<Object> value, 1763 bool force_generic) { 1764 if (key->IsSymbol()) { 1765 Handle<String> name = Handle<String>::cast(key); 1766 1767 // Handle proxies. 1768 if (object->IsJSProxy()) { 1769 return JSProxy::cast(*object)->SetProperty( 1770 *name, *value, NONE, strict_mode); 1771 } 1772 1773 // If the object is undefined or null it's illegal to try to set any 1774 // properties on it; throw a TypeError in that case. 1775 if (object->IsUndefined() || object->IsNull()) { 1776 return TypeError("non_object_property_store", object, name); 1777 } 1778 1779 // Ignore stores where the receiver is not a JSObject. 1780 if (!object->IsJSObject()) return *value; 1781 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1782 1783 // Check if the given name is an array index. 1784 uint32_t index; 1785 if (name->AsArrayIndex(&index)) { 1786 Handle<Object> result = 1787 JSObject::SetElement(receiver, index, value, NONE, strict_mode); 1788 RETURN_IF_EMPTY_HANDLE(isolate(), result); 1789 return *value; 1790 } 1791 1792 // Update inline cache and stub cache. 1793 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { 1794 LookupResult lookup(isolate()); 1795 if (LookupForWrite(receiver, name, &lookup)) { 1796 UpdateCaches(&lookup, state, strict_mode, receiver, name, value); 1797 } 1798 } 1799 1800 // Set the property. 1801 return receiver->SetProperty(*name, *value, NONE, strict_mode); 1802 } 1803 1804 // Do not use ICs for objects that require access checks (including 1805 // the global object). 1806 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1807 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 1808 1809 if (use_ic) { 1810 Handle<Code> stub = (strict_mode == kStrictMode) 1811 ? generic_stub_strict() 1812 : generic_stub(); 1813 if (object->IsJSObject()) { 1814 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1815 if (receiver->elements()->map() == 1816 isolate()->heap()->non_strict_arguments_elements_map()) { 1817 stub = non_strict_arguments_stub(); 1818 } else if (!force_generic) { 1819 if (key->IsSmi() && (target() != *non_strict_arguments_stub())) { 1820 StubKind stub_kind = GetStubKind(receiver, key, value); 1821 stub = ComputeStub(receiver, stub_kind, strict_mode, stub); 1822 } 1823 } else { 1824 TRACE_GENERIC_IC("KeyedStoreIC", "force generic"); 1825 } 1826 } 1827 if (!stub.is_null()) set_target(*stub); 1828 } 1829 1830 TRACE_IC("KeyedStoreIC", key, state, target()); 1831 1832 // Set the property. 1833 return Runtime::SetObjectProperty( 1834 isolate(), object , key, value, NONE, strict_mode); 1835} 1836 1837 1838void KeyedStoreIC::UpdateCaches(LookupResult* lookup, 1839 State state, 1840 StrictModeFlag strict_mode, 1841 Handle<JSObject> receiver, 1842 Handle<String> name, 1843 Handle<Object> value) { 1844 ASSERT(!receiver->IsJSGlobalProxy()); 1845 ASSERT(StoreICableLookup(lookup)); 1846 // These are not cacheable, so we never see such LookupResults here. 1847 ASSERT(lookup->type() != HANDLER); 1848 // We get only called for properties or transitions, see StoreICableLookup. 1849 ASSERT(lookup->type() != NULL_DESCRIPTOR); 1850 1851 // If the property has a non-field type allowing map transitions 1852 // where there is extra room in the object, we leave the IC in its 1853 // current state. 1854 PropertyType type = lookup->type(); 1855 1856 // Compute the code stub for this store; used for rewriting to 1857 // monomorphic state and making sure that the code stub is in the 1858 // stub cache. 1859 Handle<Code> code; 1860 1861 switch (type) { 1862 case FIELD: 1863 code = isolate()->stub_cache()->ComputeKeyedStoreField( 1864 name, receiver, lookup->GetFieldIndex(), 1865 Handle<Map>::null(), strict_mode); 1866 break; 1867 case MAP_TRANSITION: 1868 if (lookup->GetAttributes() == NONE) { 1869 Handle<Map> transition(lookup->GetTransitionMap()); 1870 int index = transition->PropertyIndexFor(*name); 1871 code = isolate()->stub_cache()->ComputeKeyedStoreField( 1872 name, receiver, index, transition, strict_mode); 1873 break; 1874 } 1875 // fall through. 1876 case NORMAL: 1877 case CONSTANT_FUNCTION: 1878 case CALLBACKS: 1879 case INTERCEPTOR: 1880 case CONSTANT_TRANSITION: 1881 case ELEMENTS_TRANSITION: 1882 // Always rewrite to the generic case so that we do not 1883 // repeatedly try to rewrite. 1884 code = (strict_mode == kStrictMode) 1885 ? generic_stub_strict() 1886 : generic_stub(); 1887 break; 1888 case HANDLER: 1889 case NULL_DESCRIPTOR: 1890 UNREACHABLE(); 1891 return; 1892 } 1893 1894 ASSERT(!code.is_null()); 1895 1896 // Patch the call site depending on the state of the cache. Make 1897 // sure to always rewrite from monomorphic to megamorphic. 1898 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); 1899 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { 1900 set_target(*code); 1901 } else if (state == MONOMORPHIC) { 1902 set_target((strict_mode == kStrictMode) 1903 ? *megamorphic_stub_strict() 1904 : *megamorphic_stub()); 1905 } 1906 1907 TRACE_IC("KeyedStoreIC", name, state, target()); 1908} 1909 1910 1911#undef TRACE_IC 1912 1913 1914// ---------------------------------------------------------------------------- 1915// Static IC stub generators. 1916// 1917 1918// Used from ic-<arch>.cc. 1919RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { 1920 HandleScope scope(isolate); 1921 ASSERT(args.length() == 2); 1922 CallIC ic(isolate); 1923 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1924 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 1925 MaybeObject* maybe_result = ic.LoadFunction(state, 1926 extra_ic_state, 1927 args.at<Object>(0), 1928 args.at<String>(1)); 1929 // Result could be a function or a failure. 1930 JSFunction* raw_function = NULL; 1931 if (!maybe_result->To(&raw_function)) return maybe_result; 1932 1933 // The first time the inline cache is updated may be the first time the 1934 // function it references gets called. If the function is lazily compiled 1935 // then the first call will trigger a compilation. We check for this case 1936 // and we do the compilation immediately, instead of waiting for the stub 1937 // currently attached to the JSFunction object to trigger compilation. 1938 if (raw_function->is_compiled()) return raw_function; 1939 1940 Handle<JSFunction> function(raw_function); 1941 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); 1942 return *function; 1943} 1944 1945 1946// Used from ic-<arch>.cc. 1947RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) { 1948 HandleScope scope(isolate); 1949 ASSERT(args.length() == 2); 1950 KeyedCallIC ic(isolate); 1951 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1952 MaybeObject* maybe_result = 1953 ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); 1954 // Result could be a function or a failure. 1955 JSFunction* raw_function = NULL; 1956 if (!maybe_result->To(&raw_function)) return maybe_result; 1957 1958 if (raw_function->is_compiled()) return raw_function; 1959 1960 Handle<JSFunction> function(raw_function); 1961 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); 1962 return *function; 1963} 1964 1965 1966// Used from ic-<arch>.cc. 1967RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { 1968 HandleScope scope(isolate); 1969 ASSERT(args.length() == 2); 1970 LoadIC ic(isolate); 1971 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1972 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); 1973} 1974 1975 1976// Used from ic-<arch>.cc 1977RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss) { 1978 HandleScope scope(isolate); 1979 ASSERT(args.length() == 2); 1980 KeyedLoadIC ic(isolate); 1981 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1982 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), false); 1983} 1984 1985 1986RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissForceGeneric) { 1987 HandleScope scope(isolate); 1988 ASSERT(args.length() == 2); 1989 KeyedLoadIC ic(isolate); 1990 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 1991 return ic.Load(state, args.at<Object>(0), args.at<Object>(1), true); 1992} 1993 1994 1995// Used from ic-<arch>.cc. 1996RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { 1997 HandleScope scope; 1998 ASSERT(args.length() == 3); 1999 StoreIC ic(isolate); 2000 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2001 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2002 return ic.Store(state, 2003 Code::GetStrictMode(extra_ic_state), 2004 args.at<Object>(0), 2005 args.at<String>(1), 2006 args.at<Object>(2)); 2007} 2008 2009 2010RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) { 2011 NoHandleAllocation nha; 2012 2013 ASSERT(args.length() == 2); 2014 JSArray* receiver = JSArray::cast(args[0]); 2015 Object* len = args[1]; 2016 2017 // The generated code should filter out non-Smis before we get here. 2018 ASSERT(len->IsSmi()); 2019 2020#ifdef DEBUG 2021 // The length property has to be a writable callback property. 2022 LookupResult debug_lookup(isolate); 2023 receiver->LocalLookup(isolate->heap()->length_symbol(), &debug_lookup); 2024 ASSERT(debug_lookup.type() == CALLBACKS && !debug_lookup.IsReadOnly()); 2025#endif 2026 2027 Object* result; 2028 { MaybeObject* maybe_result = receiver->SetElementsLength(len); 2029 if (!maybe_result->ToObject(&result)) return maybe_result; 2030 } 2031 return len; 2032} 2033 2034 2035// Extend storage is called in a store inline cache when 2036// it is necessary to extend the properties array of a 2037// JSObject. 2038RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) { 2039 NoHandleAllocation na; 2040 ASSERT(args.length() == 3); 2041 2042 // Convert the parameters 2043 JSObject* object = JSObject::cast(args[0]); 2044 Map* transition = Map::cast(args[1]); 2045 Object* value = args[2]; 2046 2047 // Check the object has run out out property space. 2048 ASSERT(object->HasFastProperties()); 2049 ASSERT(object->map()->unused_property_fields() == 0); 2050 2051 // Expand the properties array. 2052 FixedArray* old_storage = object->properties(); 2053 int new_unused = transition->unused_property_fields(); 2054 int new_size = old_storage->length() + new_unused + 1; 2055 Object* result; 2056 { MaybeObject* maybe_result = old_storage->CopySize(new_size); 2057 if (!maybe_result->ToObject(&result)) return maybe_result; 2058 } 2059 FixedArray* new_storage = FixedArray::cast(result); 2060 new_storage->set(old_storage->length(), value); 2061 2062 // Set the new property value and do the map transition. 2063 object->set_properties(new_storage); 2064 object->set_map(transition); 2065 2066 // Return the stored value. 2067 return value; 2068} 2069 2070 2071// Used from ic-<arch>.cc. 2072RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { 2073 HandleScope scope(isolate); 2074 ASSERT(args.length() == 3); 2075 KeyedStoreIC ic(isolate); 2076 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2077 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2078 return ic.Store(state, 2079 Code::GetStrictMode(extra_ic_state), 2080 args.at<Object>(0), 2081 args.at<Object>(1), 2082 args.at<Object>(2), 2083 false); 2084} 2085 2086 2087RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { 2088 NoHandleAllocation na; 2089 ASSERT(args.length() == 3); 2090 KeyedStoreIC ic(isolate); 2091 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2092 Handle<Object> object = args.at<Object>(0); 2093 Handle<Object> key = args.at<Object>(1); 2094 Handle<Object> value = args.at<Object>(2); 2095 StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); 2096 return Runtime::SetObjectProperty(isolate, 2097 object, 2098 key, 2099 value, 2100 NONE, 2101 strict_mode); 2102} 2103 2104 2105RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { 2106 HandleScope scope(isolate); 2107 ASSERT(args.length() == 3); 2108 KeyedStoreIC ic(isolate); 2109 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); 2110 Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); 2111 return ic.Store(state, 2112 Code::GetStrictMode(extra_ic_state), 2113 args.at<Object>(0), 2114 args.at<Object>(1), 2115 args.at<Object>(2), 2116 true); 2117} 2118 2119 2120void UnaryOpIC::patch(Code* code) { 2121 set_target(code); 2122} 2123 2124 2125const char* UnaryOpIC::GetName(TypeInfo type_info) { 2126 switch (type_info) { 2127 case UNINITIALIZED: return "Uninitialized"; 2128 case SMI: return "Smi"; 2129 case HEAP_NUMBER: return "HeapNumbers"; 2130 case GENERIC: return "Generic"; 2131 default: return "Invalid"; 2132 } 2133} 2134 2135 2136UnaryOpIC::State UnaryOpIC::ToState(TypeInfo type_info) { 2137 switch (type_info) { 2138 case UNINITIALIZED: 2139 return ::v8::internal::UNINITIALIZED; 2140 case SMI: 2141 case HEAP_NUMBER: 2142 return MONOMORPHIC; 2143 case GENERIC: 2144 return MEGAMORPHIC; 2145 } 2146 UNREACHABLE(); 2147 return ::v8::internal::UNINITIALIZED; 2148} 2149 2150UnaryOpIC::TypeInfo UnaryOpIC::GetTypeInfo(Handle<Object> operand) { 2151 ::v8::internal::TypeInfo operand_type = 2152 ::v8::internal::TypeInfo::TypeFromValue(operand); 2153 if (operand_type.IsSmi()) { 2154 return SMI; 2155 } else if (operand_type.IsNumber()) { 2156 return HEAP_NUMBER; 2157 } else { 2158 return GENERIC; 2159 } 2160} 2161 2162 2163UnaryOpIC::TypeInfo UnaryOpIC::ComputeNewType( 2164 UnaryOpIC::TypeInfo current_type, 2165 UnaryOpIC::TypeInfo previous_type) { 2166 switch (previous_type) { 2167 case UnaryOpIC::UNINITIALIZED: 2168 return current_type; 2169 case UnaryOpIC::SMI: 2170 return (current_type == UnaryOpIC::GENERIC) 2171 ? UnaryOpIC::GENERIC 2172 : UnaryOpIC::HEAP_NUMBER; 2173 case UnaryOpIC::HEAP_NUMBER: 2174 return UnaryOpIC::GENERIC; 2175 case UnaryOpIC::GENERIC: 2176 // We should never do patching if we are in GENERIC state. 2177 UNREACHABLE(); 2178 return UnaryOpIC::GENERIC; 2179 } 2180 UNREACHABLE(); 2181 return UnaryOpIC::GENERIC; 2182} 2183 2184 2185void BinaryOpIC::patch(Code* code) { 2186 set_target(code); 2187} 2188 2189 2190const char* BinaryOpIC::GetName(TypeInfo type_info) { 2191 switch (type_info) { 2192 case UNINITIALIZED: return "Uninitialized"; 2193 case SMI: return "SMI"; 2194 case INT32: return "Int32s"; 2195 case HEAP_NUMBER: return "HeapNumbers"; 2196 case ODDBALL: return "Oddball"; 2197 case BOTH_STRING: return "BothStrings"; 2198 case STRING: return "Strings"; 2199 case GENERIC: return "Generic"; 2200 default: return "Invalid"; 2201 } 2202} 2203 2204 2205BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { 2206 switch (type_info) { 2207 case UNINITIALIZED: 2208 return ::v8::internal::UNINITIALIZED; 2209 case SMI: 2210 case INT32: 2211 case HEAP_NUMBER: 2212 case ODDBALL: 2213 case BOTH_STRING: 2214 case STRING: 2215 return MONOMORPHIC; 2216 case GENERIC: 2217 return MEGAMORPHIC; 2218 } 2219 UNREACHABLE(); 2220 return ::v8::internal::UNINITIALIZED; 2221} 2222 2223 2224BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x, 2225 BinaryOpIC::TypeInfo y) { 2226 if (x == UNINITIALIZED) return y; 2227 if (y == UNINITIALIZED) return x; 2228 if (x == y) return x; 2229 if (x == BOTH_STRING && y == STRING) return STRING; 2230 if (x == STRING && y == BOTH_STRING) return STRING; 2231 if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) { 2232 return GENERIC; 2233 } 2234 if (x > y) return x; 2235 return y; 2236} 2237 2238 2239BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left, 2240 Handle<Object> right) { 2241 ::v8::internal::TypeInfo left_type = 2242 ::v8::internal::TypeInfo::TypeFromValue(left); 2243 ::v8::internal::TypeInfo right_type = 2244 ::v8::internal::TypeInfo::TypeFromValue(right); 2245 2246 if (left_type.IsSmi() && right_type.IsSmi()) { 2247 return SMI; 2248 } 2249 2250 if (left_type.IsInteger32() && right_type.IsInteger32()) { 2251 // Platforms with 32-bit Smis have no distinct INT32 type. 2252 if (kSmiValueSize == 32) return SMI; 2253 return INT32; 2254 } 2255 2256 if (left_type.IsNumber() && right_type.IsNumber()) { 2257 return HEAP_NUMBER; 2258 } 2259 2260 // Patching for fast string ADD makes sense even if only one of the 2261 // arguments is a string. 2262 if (left_type.IsString()) { 2263 return right_type.IsString() ? BOTH_STRING : STRING; 2264 } else if (right_type.IsString()) { 2265 return STRING; 2266 } 2267 2268 // Check for oddball objects. 2269 if (left->IsUndefined() && right->IsNumber()) return ODDBALL; 2270 if (left->IsNumber() && right->IsUndefined()) return ODDBALL; 2271 2272 return GENERIC; 2273} 2274 2275 2276RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { 2277 ASSERT(args.length() == 4); 2278 2279 HandleScope scope(isolate); 2280 Handle<Object> operand = args.at<Object>(0); 2281 Token::Value op = static_cast<Token::Value>(args.smi_at(1)); 2282 UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2)); 2283 UnaryOpIC::TypeInfo previous_type = 2284 static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3)); 2285 2286 UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand); 2287 type = UnaryOpIC::ComputeNewType(type, previous_type); 2288 2289 UnaryOpStub stub(op, mode, type); 2290 Handle<Code> code = stub.GetCode(); 2291 if (!code.is_null()) { 2292 if (FLAG_trace_ic) { 2293 PrintF("[UnaryOpIC (%s->%s)#%s]\n", 2294 UnaryOpIC::GetName(previous_type), 2295 UnaryOpIC::GetName(type), 2296 Token::Name(op)); 2297 } 2298 UnaryOpIC ic(isolate); 2299 ic.patch(*code); 2300 } 2301 2302 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( 2303 isolate->thread_local_top()->context_->builtins(), isolate); 2304 Object* builtin = NULL; // Initialization calms down the compiler. 2305 switch (op) { 2306 case Token::SUB: 2307 builtin = builtins->javascript_builtin(Builtins::UNARY_MINUS); 2308 break; 2309 case Token::BIT_NOT: 2310 builtin = builtins->javascript_builtin(Builtins::BIT_NOT); 2311 break; 2312 default: 2313 UNREACHABLE(); 2314 } 2315 2316 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); 2317 2318 bool caught_exception; 2319 Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL, 2320 &caught_exception); 2321 if (caught_exception) { 2322 return Failure::Exception(); 2323 } 2324 return *result; 2325} 2326 2327RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { 2328 ASSERT(args.length() == 5); 2329 2330 HandleScope scope(isolate); 2331 Handle<Object> left = args.at<Object>(0); 2332 Handle<Object> right = args.at<Object>(1); 2333 int key = args.smi_at(2); 2334 Token::Value op = static_cast<Token::Value>(args.smi_at(3)); 2335 BinaryOpIC::TypeInfo previous_type = 2336 static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4)); 2337 2338 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); 2339 type = BinaryOpIC::JoinTypes(type, previous_type); 2340 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; 2341 if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && 2342 op != Token::ADD) { 2343 type = BinaryOpIC::GENERIC; 2344 } 2345 if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { 2346 if (op == Token::DIV || 2347 op == Token::MUL || 2348 op == Token::SHR || 2349 kSmiValueSize == 32) { 2350 // Arithmetic on two Smi inputs has yielded a heap number. 2351 // That is the only way to get here from the Smi stub. 2352 // With 32-bit Smis, all overflows give heap numbers, but with 2353 // 31-bit Smis, most operations overflow to int32 results. 2354 result_type = BinaryOpIC::HEAP_NUMBER; 2355 } else { 2356 // Other operations on SMIs that overflow yield int32s. 2357 result_type = BinaryOpIC::INT32; 2358 } 2359 } 2360 if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { 2361 // We must be here because an operation on two INT32 types overflowed. 2362 result_type = BinaryOpIC::HEAP_NUMBER; 2363 } 2364 2365 BinaryOpStub stub(key, type, result_type); 2366 Handle<Code> code = stub.GetCode(); 2367 if (!code.is_null()) { 2368 if (FLAG_trace_ic) { 2369 PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", 2370 BinaryOpIC::GetName(previous_type), 2371 BinaryOpIC::GetName(type), 2372 BinaryOpIC::GetName(result_type), 2373 Token::Name(op)); 2374 } 2375 BinaryOpIC ic(isolate); 2376 ic.patch(*code); 2377 2378 // Activate inlined smi code. 2379 if (previous_type == BinaryOpIC::UNINITIALIZED) { 2380 PatchInlinedSmiCode(ic.address()); 2381 } 2382 } 2383 2384 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( 2385 isolate->thread_local_top()->context_->builtins(), isolate); 2386 Object* builtin = NULL; // Initialization calms down the compiler. 2387 switch (op) { 2388 case Token::ADD: 2389 builtin = builtins->javascript_builtin(Builtins::ADD); 2390 break; 2391 case Token::SUB: 2392 builtin = builtins->javascript_builtin(Builtins::SUB); 2393 break; 2394 case Token::MUL: 2395 builtin = builtins->javascript_builtin(Builtins::MUL); 2396 break; 2397 case Token::DIV: 2398 builtin = builtins->javascript_builtin(Builtins::DIV); 2399 break; 2400 case Token::MOD: 2401 builtin = builtins->javascript_builtin(Builtins::MOD); 2402 break; 2403 case Token::BIT_AND: 2404 builtin = builtins->javascript_builtin(Builtins::BIT_AND); 2405 break; 2406 case Token::BIT_OR: 2407 builtin = builtins->javascript_builtin(Builtins::BIT_OR); 2408 break; 2409 case Token::BIT_XOR: 2410 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); 2411 break; 2412 case Token::SHR: 2413 builtin = builtins->javascript_builtin(Builtins::SHR); 2414 break; 2415 case Token::SAR: 2416 builtin = builtins->javascript_builtin(Builtins::SAR); 2417 break; 2418 case Token::SHL: 2419 builtin = builtins->javascript_builtin(Builtins::SHL); 2420 break; 2421 default: 2422 UNREACHABLE(); 2423 } 2424 2425 Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); 2426 2427 bool caught_exception; 2428 Handle<Object> builtin_args[] = { right }; 2429 Handle<Object> result = Execution::Call(builtin_function, 2430 left, 2431 ARRAY_SIZE(builtin_args), 2432 builtin_args, 2433 &caught_exception); 2434 if (caught_exception) { 2435 return Failure::Exception(); 2436 } 2437 return *result; 2438} 2439 2440 2441Handle<Code> CompareIC::GetUninitialized(Token::Value op) { 2442 ICCompareStub stub(op, UNINITIALIZED); 2443 return stub.GetCode(); 2444} 2445 2446 2447CompareIC::State CompareIC::ComputeState(Code* target) { 2448 int key = target->major_key(); 2449 if (key == CodeStub::Compare) return GENERIC; 2450 ASSERT(key == CodeStub::CompareIC); 2451 return static_cast<State>(target->compare_state()); 2452} 2453 2454 2455const char* CompareIC::GetStateName(State state) { 2456 switch (state) { 2457 case UNINITIALIZED: return "UNINITIALIZED"; 2458 case SMIS: return "SMIS"; 2459 case HEAP_NUMBERS: return "HEAP_NUMBERS"; 2460 case OBJECTS: return "OBJECTS"; 2461 case KNOWN_OBJECTS: return "OBJECTS"; 2462 case SYMBOLS: return "SYMBOLS"; 2463 case STRINGS: return "STRINGS"; 2464 case GENERIC: return "GENERIC"; 2465 default: 2466 UNREACHABLE(); 2467 return NULL; 2468 } 2469} 2470 2471 2472CompareIC::State CompareIC::TargetState(State state, 2473 bool has_inlined_smi_code, 2474 Handle<Object> x, 2475 Handle<Object> y) { 2476 switch (state) { 2477 case UNINITIALIZED: 2478 if (x->IsSmi() && y->IsSmi()) return SMIS; 2479 if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; 2480 if (Token::IsOrderedRelationalCompareOp(op_)) { 2481 // Ordered comparisons treat undefined as NaN, so the 2482 // HEAP_NUMBER stub will do the right thing. 2483 if ((x->IsNumber() && y->IsUndefined()) || 2484 (y->IsNumber() && x->IsUndefined())) { 2485 return HEAP_NUMBERS; 2486 } 2487 } 2488 if (x->IsSymbol() && y->IsSymbol()) { 2489 // We compare symbols as strings if we need to determine 2490 // the order in a non-equality compare. 2491 return Token::IsEqualityOp(op_) ? SYMBOLS : STRINGS; 2492 } 2493 if (x->IsString() && y->IsString()) return STRINGS; 2494 if (!Token::IsEqualityOp(op_)) return GENERIC; 2495 if (x->IsJSObject() && y->IsJSObject()) { 2496 if (Handle<JSObject>::cast(x)->map() == 2497 Handle<JSObject>::cast(y)->map() && 2498 Token::IsEqualityOp(op_)) { 2499 return KNOWN_OBJECTS; 2500 } else { 2501 return OBJECTS; 2502 } 2503 } 2504 return GENERIC; 2505 case SMIS: 2506 return has_inlined_smi_code && x->IsNumber() && y->IsNumber() 2507 ? HEAP_NUMBERS 2508 : GENERIC; 2509 case SYMBOLS: 2510 ASSERT(Token::IsEqualityOp(op_)); 2511 return x->IsString() && y->IsString() ? STRINGS : GENERIC; 2512 case HEAP_NUMBERS: 2513 case STRINGS: 2514 case OBJECTS: 2515 case KNOWN_OBJECTS: 2516 case GENERIC: 2517 return GENERIC; 2518 } 2519 UNREACHABLE(); 2520 return GENERIC; 2521} 2522 2523 2524// Used from ic_<arch>.cc. 2525RUNTIME_FUNCTION(Code*, CompareIC_Miss) { 2526 NoHandleAllocation na; 2527 ASSERT(args.length() == 3); 2528 CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2))); 2529 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); 2530 return ic.target(); 2531} 2532 2533 2534RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) { 2535 ASSERT(args.length() == 3); 2536 2537 HandleScope scope(isolate); 2538 Handle<Object> object = args.at<Object>(0); 2539 Register tos = Register::from_code(args.smi_at(1)); 2540 ToBooleanStub::Types old_types(args.smi_at(2)); 2541 2542 ToBooleanStub::Types new_types(old_types); 2543 bool to_boolean_value = new_types.Record(object); 2544 old_types.TraceTransition(new_types); 2545 2546 ToBooleanStub stub(tos, new_types); 2547 Handle<Code> code = stub.GetCode(); 2548 ToBooleanIC ic(isolate); 2549 ic.patch(*code); 2550 return Smi::FromInt(to_boolean_value ? 1 : 0); 2551} 2552 2553 2554void ToBooleanIC::patch(Code* code) { 2555 set_target(code); 2556} 2557 2558 2559static const Address IC_utilities[] = { 2560#define ADDR(name) FUNCTION_ADDR(name), 2561 IC_UTIL_LIST(ADDR) 2562 NULL 2563#undef ADDR 2564}; 2565 2566 2567Address IC::AddressFromUtilityId(IC::UtilityId id) { 2568 return IC_utilities[id]; 2569} 2570 2571 2572} } // namespace v8::internal 2573