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