ic.cc revision 3ce2e2076e8e3e60cf1810eec160ea2d8557e9e7
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 "execution.h" 34#include "ic-inl.h" 35#include "runtime.h" 36#include "stub-cache.h" 37 38namespace v8 { 39namespace internal { 40 41#ifdef DEBUG 42static char TransitionMarkFromState(IC::State state) { 43 switch (state) { 44 case UNINITIALIZED: return '0'; 45 case PREMONOMORPHIC: return 'P'; 46 case MONOMORPHIC: return '1'; 47 case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; 48 case MEGAMORPHIC: return 'N'; 49 50 // We never see the debugger states here, because the state is 51 // computed from the original code - not the patched code. Let 52 // these cases fall through to the unreachable code below. 53 case DEBUG_BREAK: break; 54 case DEBUG_PREPARE_STEP_IN: break; 55 } 56 UNREACHABLE(); 57 return 0; 58} 59 60void IC::TraceIC(const char* type, 61 Handle<String> name, 62 State old_state, 63 Code* new_target, 64 const char* extra_info) { 65 if (FLAG_trace_ic) { 66 State new_state = StateFrom(new_target, Heap::undefined_value()); 67 PrintF("[%s (%c->%c)%s", type, 68 TransitionMarkFromState(old_state), 69 TransitionMarkFromState(new_state), 70 extra_info); 71 name->Print(); 72 PrintF("]\n"); 73 } 74} 75#endif 76 77 78IC::IC(FrameDepth depth) { 79 // To improve the performance of the (much used) IC code, we unfold 80 // a few levels of the stack frame iteration code. This yields a 81 // ~35% speedup when running DeltaBlue with the '--nouse-ic' flag. 82 const Address entry = Top::c_entry_fp(Top::GetCurrentThread()); 83 Address* pc_address = 84 reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset); 85 Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset); 86 // If there's another JavaScript frame on the stack, we need to look 87 // one frame further down the stack to find the frame pointer and 88 // the return address stack slot. 89 if (depth == EXTRA_CALL_FRAME) { 90 const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset; 91 pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset); 92 fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset); 93 } 94#ifdef DEBUG 95 StackFrameIterator it; 96 for (int i = 0; i < depth + 1; i++) it.Advance(); 97 StackFrame* frame = it.frame(); 98 ASSERT(fp == frame->fp() && pc_address == frame->pc_address()); 99#endif 100 fp_ = fp; 101 pc_address_ = pc_address; 102} 103 104 105#ifdef ENABLE_DEBUGGER_SUPPORT 106Address IC::OriginalCodeAddress() { 107 HandleScope scope; 108 // Compute the JavaScript frame for the frame pointer of this IC 109 // structure. We need this to be able to find the function 110 // corresponding to the frame. 111 StackFrameIterator it; 112 while (it.frame()->fp() != this->fp()) it.Advance(); 113 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 114 // Find the function on the stack and both the active code for the 115 // function and the original code. 116 JSFunction* function = JSFunction::cast(frame->function()); 117 Handle<SharedFunctionInfo> shared(function->shared()); 118 Code* code = shared->code(); 119 ASSERT(Debug::HasDebugInfo(shared)); 120 Code* original_code = Debug::GetDebugInfo(shared)->original_code(); 121 ASSERT(original_code->IsCode()); 122 // Get the address of the call site in the active code. This is the 123 // place where the call to DebugBreakXXX is and where the IC 124 // normally would be. 125 Address addr = pc() - Assembler::kCallTargetAddressOffset; 126 // Return the address in the original code. This is the place where 127 // the call which has been overwritten by the DebugBreakXXX resides 128 // and the place where the inline cache system should look. 129 int delta = original_code->instruction_start() - code->instruction_start(); 130 return addr + delta; 131} 132#endif 133 134IC::State IC::StateFrom(Code* target, Object* receiver) { 135 IC::State state = target->ic_state(); 136 137 if (state != MONOMORPHIC) return state; 138 if (receiver->IsUndefined() || receiver->IsNull()) return state; 139 140 Map* map = GetCodeCacheMapForObject(receiver); 141 142 // Decide whether the inline cache failed because of changes to the 143 // receiver itself or changes to one of its prototypes. 144 // 145 // If there are changes to the receiver itself, the map of the 146 // receiver will have changed and the current target will not be in 147 // the receiver map's code cache. Therefore, if the current target 148 // is in the receiver map's code cache, the inline cache failed due 149 // to prototype check failure. 150 int index = map->IndexInCodeCache(target); 151 if (index >= 0) { 152 // For keyed load/store, the most likely cause of cache failure is 153 // that the key has changed. We do not distinguish between 154 // prototype and non-prototype failures for keyed access. 155 Code::Kind kind = target->kind(); 156 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { 157 return MONOMORPHIC; 158 } 159 160 // Remove the target from the code cache to avoid hitting the same 161 // invalid stub again. 162 map->RemoveFromCodeCache(index); 163 164 return MONOMORPHIC_PROTOTYPE_FAILURE; 165 } 166 167 // The builtins object is special. It only changes when JavaScript 168 // builtins are loaded lazily. It is important to keep inline 169 // caches for the builtins object monomorphic. Therefore, if we get 170 // an inline cache miss for the builtins object after lazily loading 171 // JavaScript builtins, we return uninitialized as the state to 172 // force the inline cache back to monomorphic state. 173 if (receiver->IsJSBuiltinsObject()) { 174 return UNINITIALIZED; 175 } 176 177 return MONOMORPHIC; 178} 179 180 181RelocInfo::Mode IC::ComputeMode() { 182 Address addr = address(); 183 Code* code = Code::cast(Heap::FindCodeObject(addr)); 184 for (RelocIterator it(code, RelocInfo::kCodeTargetMask); 185 !it.done(); it.next()) { 186 RelocInfo* info = it.rinfo(); 187 if (info->pc() == addr) return info->rmode(); 188 } 189 UNREACHABLE(); 190 return RelocInfo::NONE; 191} 192 193 194Failure* IC::TypeError(const char* type, 195 Handle<Object> object, 196 Handle<String> name) { 197 HandleScope scope; 198 Handle<Object> args[2] = { name, object }; 199 Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2)); 200 return Top::Throw(*error); 201} 202 203 204Failure* IC::ReferenceError(const char* type, Handle<String> name) { 205 HandleScope scope; 206 Handle<Object> error = 207 Factory::NewReferenceError(type, HandleVector(&name, 1)); 208 return Top::Throw(*error); 209} 210 211 212void IC::Clear(Address address) { 213 Code* target = GetTargetAtAddress(address); 214 215 // Don't clear debug break inline cache as it will remove the break point. 216 if (target->ic_state() == DEBUG_BREAK) return; 217 218 switch (target->kind()) { 219 case Code::LOAD_IC: return LoadIC::Clear(address, target); 220 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); 221 case Code::STORE_IC: return StoreIC::Clear(address, target); 222 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); 223 case Code::CALL_IC: return CallIC::Clear(address, target); 224 default: UNREACHABLE(); 225 } 226} 227 228 229void CallIC::Clear(Address address, Code* target) { 230 State state = target->ic_state(); 231 InLoopFlag in_loop = target->ic_in_loop(); 232 if (state == UNINITIALIZED) return; 233 Code* code = 234 StubCache::FindCallInitialize(target->arguments_count(), in_loop); 235 SetTargetAtAddress(address, code); 236} 237 238 239void KeyedLoadIC::Clear(Address address, Code* target) { 240 if (target->ic_state() == UNINITIALIZED) return; 241 // Make sure to also clear the map used in inline fast cases. If we 242 // do not clear these maps, cached code can keep objects alive 243 // through the embedded maps. 244 ClearInlinedVersion(address); 245 SetTargetAtAddress(address, initialize_stub()); 246} 247 248 249void LoadIC::Clear(Address address, Code* target) { 250 if (target->ic_state() == UNINITIALIZED) return; 251 ClearInlinedVersion(address); 252 SetTargetAtAddress(address, initialize_stub()); 253} 254 255 256void StoreIC::Clear(Address address, Code* target) { 257 if (target->ic_state() == UNINITIALIZED) return; 258 SetTargetAtAddress(address, initialize_stub()); 259} 260 261 262void KeyedStoreIC::Clear(Address address, Code* target) { 263 if (target->ic_state() == UNINITIALIZED) return; 264 SetTargetAtAddress(address, initialize_stub()); 265} 266 267 268Code* KeyedLoadIC::external_array_stub(JSObject::ElementsKind elements_kind) { 269 switch (elements_kind) { 270 case JSObject::EXTERNAL_BYTE_ELEMENTS: 271 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalByteArray); 272 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 273 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedByteArray); 274 case JSObject::EXTERNAL_SHORT_ELEMENTS: 275 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalShortArray); 276 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 277 return Builtins::builtin( 278 Builtins::KeyedLoadIC_ExternalUnsignedShortArray); 279 case JSObject::EXTERNAL_INT_ELEMENTS: 280 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalIntArray); 281 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: 282 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalUnsignedIntArray); 283 case JSObject::EXTERNAL_FLOAT_ELEMENTS: 284 return Builtins::builtin(Builtins::KeyedLoadIC_ExternalFloatArray); 285 default: 286 UNREACHABLE(); 287 return NULL; 288 } 289} 290 291 292Code* KeyedStoreIC::external_array_stub(JSObject::ElementsKind elements_kind) { 293 switch (elements_kind) { 294 case JSObject::EXTERNAL_BYTE_ELEMENTS: 295 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalByteArray); 296 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 297 return Builtins::builtin( 298 Builtins::KeyedStoreIC_ExternalUnsignedByteArray); 299 case JSObject::EXTERNAL_SHORT_ELEMENTS: 300 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalShortArray); 301 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 302 return Builtins::builtin( 303 Builtins::KeyedStoreIC_ExternalUnsignedShortArray); 304 case JSObject::EXTERNAL_INT_ELEMENTS: 305 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalIntArray); 306 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: 307 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalUnsignedIntArray); 308 case JSObject::EXTERNAL_FLOAT_ELEMENTS: 309 return Builtins::builtin(Builtins::KeyedStoreIC_ExternalFloatArray); 310 default: 311 UNREACHABLE(); 312 return NULL; 313 } 314} 315 316 317static bool HasInterceptorGetter(JSObject* object) { 318 return !object->GetNamedInterceptor()->getter()->IsUndefined(); 319} 320 321 322static void LookupForRead(Object* object, 323 String* name, 324 LookupResult* lookup) { 325 AssertNoAllocation no_gc; // pointers must stay valid 326 327 // Skip all the objects with named interceptors, but 328 // without actual getter. 329 while (true) { 330 object->Lookup(name, lookup); 331 // Besides normal conditions (property not found or it's not 332 // an interceptor), bail out of lookup is not cacheable: we won't 333 // be able to IC it anyway and regular lookup should work fine. 334 if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR || 335 !lookup->IsCacheable()) { 336 return; 337 } 338 339 JSObject* holder = lookup->holder(); 340 if (HasInterceptorGetter(holder)) { 341 return; 342 } 343 344 holder->LocalLookupRealNamedProperty(name, lookup); 345 if (lookup->IsValid()) { 346 ASSERT(lookup->type() != INTERCEPTOR); 347 return; 348 } 349 350 Object* proto = holder->GetPrototype(); 351 if (proto->IsNull()) { 352 lookup->NotFound(); 353 return; 354 } 355 356 object = proto; 357 } 358} 359 360 361Object* CallIC::TryCallAsFunction(Object* object) { 362 HandleScope scope; 363 Handle<Object> target(object); 364 Handle<Object> delegate = Execution::GetFunctionDelegate(target); 365 366 if (delegate->IsJSFunction()) { 367 // Patch the receiver and use the delegate as the function to 368 // invoke. This is used for invoking objects as if they were 369 // functions. 370 const int argc = this->target()->arguments_count(); 371 StackFrameLocator locator; 372 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 373 int index = frame->ComputeExpressionsCount() - (argc + 1); 374 frame->SetExpression(index, *target); 375 } 376 377 return *delegate; 378} 379 380 381Object* CallIC::LoadFunction(State state, 382 Handle<Object> object, 383 Handle<String> name) { 384 // If the object is undefined or null it's illegal to try to get any 385 // of its properties; throw a TypeError in that case. 386 if (object->IsUndefined() || object->IsNull()) { 387 return TypeError("non_object_property_call", object, name); 388 } 389 390 // Check if the name is trivially convertible to an index and get 391 // the element if so. 392 uint32_t index; 393 if (name->AsArrayIndex(&index)) { 394 Object* result = object->GetElement(index); 395 if (result->IsJSFunction()) return result; 396 397 // Try to find a suitable function delegate for the object at hand. 398 result = TryCallAsFunction(result); 399 if (result->IsJSFunction()) return result; 400 401 // Otherwise, it will fail in the lookup step. 402 } 403 404 // Lookup the property in the object. 405 LookupResult lookup; 406 LookupForRead(*object, *name, &lookup); 407 408 if (!lookup.IsValid()) { 409 // If the object does not have the requested property, check which 410 // exception we need to throw. 411 if (is_contextual()) { 412 return ReferenceError("not_defined", name); 413 } 414 return TypeError("undefined_method", object, name); 415 } 416 417 // Lookup is valid: Update inline cache and stub cache. 418 if (FLAG_use_ic && lookup.IsLoaded()) { 419 UpdateCaches(&lookup, state, object, name); 420 } 421 422 // Get the property. 423 PropertyAttributes attr; 424 Object* result = object->GetProperty(*object, &lookup, *name, &attr); 425 if (result->IsFailure()) return result; 426 if (lookup.type() == INTERCEPTOR) { 427 // If the object does not have the requested property, check which 428 // exception we need to throw. 429 if (attr == ABSENT) { 430 if (is_contextual()) { 431 return ReferenceError("not_defined", name); 432 } 433 return TypeError("undefined_method", object, name); 434 } 435 } 436 437 ASSERT(result != Heap::the_hole_value()); 438 439 if (result->IsJSFunction()) { 440 // Check if there is an optimized (builtin) version of the function. 441 // Ignored this will degrade performance for Array.prototype.{push,pop}. 442 // Please note we only return the optimized function iff 443 // the JSObject has FastElements. 444 if (object->IsJSObject() && JSObject::cast(*object)->HasFastElements()) { 445 Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object), 446 lookup.holder(), 447 JSFunction::cast(result)); 448 if (opt->IsJSFunction()) return opt; 449 } 450 451#ifdef ENABLE_DEBUGGER_SUPPORT 452 // Handle stepping into a function if step into is active. 453 if (Debug::StepInActive()) { 454 // Protect the result in a handle as the debugger can allocate and might 455 // cause GC. 456 HandleScope scope; 457 Handle<JSFunction> function(JSFunction::cast(result)); 458 Debug::HandleStepIn(function, object, fp(), false); 459 return *function; 460 } 461#endif 462 463 return result; 464 } 465 466 // Try to find a suitable function delegate for the object at hand. 467 result = TryCallAsFunction(result); 468 return result->IsJSFunction() ? 469 result : TypeError("property_not_function", object, name); 470} 471 472 473void CallIC::UpdateCaches(LookupResult* lookup, 474 State state, 475 Handle<Object> object, 476 Handle<String> name) { 477 ASSERT(lookup->IsLoaded()); 478 // Bail out if we didn't find a result. 479 if (!lookup->IsValid() || !lookup->IsCacheable()) return; 480 481 // Compute the number of arguments. 482 int argc = target()->arguments_count(); 483 InLoopFlag in_loop = target()->ic_in_loop(); 484 Object* code = NULL; 485 486 if (state == UNINITIALIZED) { 487 // This is the first time we execute this inline cache. 488 // Set the target to the pre monomorphic stub to delay 489 // setting the monomorphic state. 490 code = StubCache::ComputeCallPreMonomorphic(argc, in_loop); 491 } else if (state == MONOMORPHIC) { 492 code = StubCache::ComputeCallMegamorphic(argc, in_loop); 493 } else { 494 // Compute monomorphic stub. 495 switch (lookup->type()) { 496 case FIELD: { 497 int index = lookup->GetFieldIndex(); 498 code = StubCache::ComputeCallField(argc, in_loop, *name, *object, 499 lookup->holder(), index); 500 break; 501 } 502 case CONSTANT_FUNCTION: { 503 // Get the constant function and compute the code stub for this 504 // call; used for rewriting to monomorphic state and making sure 505 // that the code stub is in the stub cache. 506 JSFunction* function = lookup->GetConstantFunction(); 507 code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object, 508 lookup->holder(), function); 509 break; 510 } 511 case NORMAL: { 512 if (!object->IsJSObject()) return; 513 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 514 515 if (lookup->holder()->IsGlobalObject()) { 516 GlobalObject* global = GlobalObject::cast(lookup->holder()); 517 JSGlobalPropertyCell* cell = 518 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); 519 if (!cell->value()->IsJSFunction()) return; 520 JSFunction* function = JSFunction::cast(cell->value()); 521 code = StubCache::ComputeCallGlobal(argc, 522 in_loop, 523 *name, 524 *receiver, 525 global, 526 cell, 527 function); 528 } else { 529 // There is only one shared stub for calling normalized 530 // properties. It does not traverse the prototype chain, so the 531 // property must be found in the receiver for the stub to be 532 // applicable. 533 if (lookup->holder() != *receiver) return; 534 code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); 535 } 536 break; 537 } 538 case INTERCEPTOR: { 539 ASSERT(HasInterceptorGetter(lookup->holder())); 540 code = StubCache::ComputeCallInterceptor(argc, *name, *object, 541 lookup->holder()); 542 break; 543 } 544 default: 545 return; 546 } 547 } 548 549 // If we're unable to compute the stub (not enough memory left), we 550 // simply avoid updating the caches. 551 if (code == NULL || code->IsFailure()) return; 552 553 // Patch the call site depending on the state of the cache. 554 if (state == UNINITIALIZED || 555 state == PREMONOMORPHIC || 556 state == MONOMORPHIC || 557 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 558 set_target(Code::cast(code)); 559 } 560 561#ifdef DEBUG 562 TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : ""); 563#endif 564} 565 566 567Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { 568 // If the object is undefined or null it's illegal to try to get any 569 // of its properties; throw a TypeError in that case. 570 if (object->IsUndefined() || object->IsNull()) { 571 return TypeError("non_object_property_load", object, name); 572 } 573 574 if (FLAG_use_ic) { 575 // Use specialized code for getting the length of strings and 576 // string wrapper objects. The length property of string wrapper 577 // objects is read-only and therefore always returns the length of 578 // the underlying string value. See ECMA-262 15.5.5.1. 579 if ((object->IsString() || object->IsStringWrapper()) && 580 name->Equals(Heap::length_symbol())) { 581 HandleScope scope; 582 // Get the string if we have a string wrapper object. 583 if (object->IsJSValue()) { 584 object = Handle<Object>(Handle<JSValue>::cast(object)->value()); 585 } 586#ifdef DEBUG 587 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n"); 588#endif 589 Code* target = NULL; 590 target = Builtins::builtin(Builtins::LoadIC_StringLength); 591 set_target(target); 592 StubCache::Set(*name, HeapObject::cast(*object)->map(), target); 593 return Smi::FromInt(String::cast(*object)->length()); 594 } 595 596 // Use specialized code for getting the length of arrays. 597 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { 598#ifdef DEBUG 599 if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n"); 600#endif 601 Code* target = Builtins::builtin(Builtins::LoadIC_ArrayLength); 602 set_target(target); 603 StubCache::Set(*name, HeapObject::cast(*object)->map(), target); 604 return JSArray::cast(*object)->length(); 605 } 606 607 // Use specialized code for getting prototype of functions. 608 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { 609#ifdef DEBUG 610 if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n"); 611#endif 612 Code* target = Builtins::builtin(Builtins::LoadIC_FunctionPrototype); 613 set_target(target); 614 StubCache::Set(*name, HeapObject::cast(*object)->map(), target); 615 return Accessors::FunctionGetPrototype(*object, 0); 616 } 617 } 618 619 // Check if the name is trivially convertible to an index and get 620 // the element if so. 621 uint32_t index; 622 if (name->AsArrayIndex(&index)) return object->GetElement(index); 623 624 // Named lookup in the object. 625 LookupResult lookup; 626 LookupForRead(*object, *name, &lookup); 627 628 // If lookup is invalid, check if we need to throw an exception. 629 if (!lookup.IsValid()) { 630 if (FLAG_strict || is_contextual()) { 631 return ReferenceError("not_defined", name); 632 } 633 LOG(SuspectReadEvent(*name, *object)); 634 } 635 636 bool can_be_inlined = 637 FLAG_use_ic && 638 state == PREMONOMORPHIC && 639 lookup.IsValid() && 640 lookup.IsLoaded() && 641 lookup.IsCacheable() && 642 lookup.holder() == *object && 643 lookup.type() == FIELD && 644 !object->IsAccessCheckNeeded(); 645 646 if (can_be_inlined) { 647 Map* map = lookup.holder()->map(); 648 // Property's index in the properties array. If negative we have 649 // an inobject property. 650 int index = lookup.GetFieldIndex() - map->inobject_properties(); 651 if (index < 0) { 652 // Index is an offset from the end of the object. 653 int offset = map->instance_size() + (index * kPointerSize); 654 if (PatchInlinedLoad(address(), map, offset)) { 655 set_target(megamorphic_stub()); 656 return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex()); 657 } 658 } 659 } 660 661 // Update inline cache and stub cache. 662 if (FLAG_use_ic && lookup.IsLoaded()) { 663 UpdateCaches(&lookup, state, object, name); 664 } 665 666 PropertyAttributes attr; 667 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { 668 // Get the property. 669 Object* result = object->GetProperty(*object, &lookup, *name, &attr); 670 if (result->IsFailure()) return result; 671 // If the property is not present, check if we need to throw an 672 // exception. 673 if (attr == ABSENT && is_contextual()) { 674 return ReferenceError("not_defined", name); 675 } 676 return result; 677 } 678 679 // Get the property. 680 return object->GetProperty(*object, &lookup, *name, &attr); 681} 682 683 684void LoadIC::UpdateCaches(LookupResult* lookup, 685 State state, 686 Handle<Object> object, 687 Handle<String> name) { 688 ASSERT(lookup->IsLoaded()); 689 // Bail out if we didn't find a result. 690 if (!lookup->IsValid() || !lookup->IsCacheable()) return; 691 692 // Loading properties from values is not common, so don't try to 693 // deal with non-JS objects here. 694 if (!object->IsJSObject()) return; 695 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 696 697 // Compute the code stub for this load. 698 Object* code = NULL; 699 if (state == UNINITIALIZED) { 700 // This is the first time we execute this inline cache. 701 // Set the target to the pre monomorphic stub to delay 702 // setting the monomorphic state. 703 code = pre_monomorphic_stub(); 704 } else { 705 // Compute monomorphic stub. 706 switch (lookup->type()) { 707 case FIELD: { 708 code = StubCache::ComputeLoadField(*name, *receiver, 709 lookup->holder(), 710 lookup->GetFieldIndex()); 711 break; 712 } 713 case CONSTANT_FUNCTION: { 714 Object* constant = lookup->GetConstantFunction(); 715 code = StubCache::ComputeLoadConstant(*name, *receiver, 716 lookup->holder(), constant); 717 break; 718 } 719 case NORMAL: { 720 if (lookup->holder()->IsGlobalObject()) { 721 GlobalObject* global = GlobalObject::cast(lookup->holder()); 722 JSGlobalPropertyCell* cell = 723 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); 724 code = StubCache::ComputeLoadGlobal(*name, 725 *receiver, 726 global, 727 cell, 728 lookup->IsDontDelete()); 729 } else { 730 // There is only one shared stub for loading normalized 731 // properties. It does not traverse the prototype chain, so the 732 // property must be found in the receiver for the stub to be 733 // applicable. 734 if (lookup->holder() != *receiver) return; 735 code = StubCache::ComputeLoadNormal(*name, *receiver); 736 } 737 break; 738 } 739 case CALLBACKS: { 740 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; 741 AccessorInfo* callback = 742 AccessorInfo::cast(lookup->GetCallbackObject()); 743 if (v8::ToCData<Address>(callback->getter()) == 0) return; 744 code = StubCache::ComputeLoadCallback(*name, *receiver, 745 lookup->holder(), callback); 746 break; 747 } 748 case INTERCEPTOR: { 749 ASSERT(HasInterceptorGetter(lookup->holder())); 750 code = StubCache::ComputeLoadInterceptor(*name, *receiver, 751 lookup->holder()); 752 break; 753 } 754 default: 755 return; 756 } 757 } 758 759 // If we're unable to compute the stub (not enough memory left), we 760 // simply avoid updating the caches. 761 if (code == NULL || code->IsFailure()) return; 762 763 // Patch the call site depending on the state of the cache. 764 if (state == UNINITIALIZED || state == PREMONOMORPHIC || 765 state == MONOMORPHIC_PROTOTYPE_FAILURE) { 766 set_target(Code::cast(code)); 767 } else if (state == MONOMORPHIC) { 768 set_target(megamorphic_stub()); 769 } 770 771#ifdef DEBUG 772 TraceIC("LoadIC", name, state, target()); 773#endif 774} 775 776 777Object* KeyedLoadIC::Load(State state, 778 Handle<Object> object, 779 Handle<Object> key) { 780 if (key->IsSymbol()) { 781 Handle<String> name = Handle<String>::cast(key); 782 783 // If the object is undefined or null it's illegal to try to get any 784 // of its properties; throw a TypeError in that case. 785 if (object->IsUndefined() || object->IsNull()) { 786 return TypeError("non_object_property_load", object, name); 787 } 788 789 if (FLAG_use_ic) { 790 // Use specialized code for getting the length of strings. 791 if (object->IsString() && name->Equals(Heap::length_symbol())) { 792 Handle<String> string = Handle<String>::cast(object); 793 Object* code = NULL; 794 code = StubCache::ComputeKeyedLoadStringLength(*name, *string); 795 if (code->IsFailure()) return code; 796 set_target(Code::cast(code)); 797#ifdef DEBUG 798 TraceIC("KeyedLoadIC", name, state, target()); 799#endif // DEBUG 800 return Smi::FromInt(string->length()); 801 } 802 803 // Use specialized code for getting the length of arrays. 804 if (object->IsJSArray() && name->Equals(Heap::length_symbol())) { 805 Handle<JSArray> array = Handle<JSArray>::cast(object); 806 Object* code = StubCache::ComputeKeyedLoadArrayLength(*name, *array); 807 if (code->IsFailure()) return code; 808 set_target(Code::cast(code)); 809#ifdef DEBUG 810 TraceIC("KeyedLoadIC", name, state, target()); 811#endif // DEBUG 812 return JSArray::cast(*object)->length(); 813 } 814 815 // Use specialized code for getting prototype of functions. 816 if (object->IsJSFunction() && name->Equals(Heap::prototype_symbol())) { 817 Handle<JSFunction> function = Handle<JSFunction>::cast(object); 818 Object* code = 819 StubCache::ComputeKeyedLoadFunctionPrototype(*name, *function); 820 if (code->IsFailure()) return code; 821 set_target(Code::cast(code)); 822#ifdef DEBUG 823 TraceIC("KeyedLoadIC", name, state, target()); 824#endif // DEBUG 825 return Accessors::FunctionGetPrototype(*object, 0); 826 } 827 } 828 829 // Check if the name is trivially convertible to an index and get 830 // the element or char if so. 831 uint32_t index = 0; 832 if (name->AsArrayIndex(&index)) { 833 HandleScope scope; 834 // Rewrite to the generic keyed load stub. 835 if (FLAG_use_ic) set_target(generic_stub()); 836 return Runtime::GetElementOrCharAt(object, index); 837 } 838 839 // Named lookup. 840 LookupResult lookup; 841 LookupForRead(*object, *name, &lookup); 842 843 // If lookup is invalid, check if we need to throw an exception. 844 if (!lookup.IsValid()) { 845 if (FLAG_strict || is_contextual()) { 846 return ReferenceError("not_defined", name); 847 } 848 } 849 850 if (FLAG_use_ic && lookup.IsLoaded()) { 851 UpdateCaches(&lookup, state, object, name); 852 } 853 854 PropertyAttributes attr; 855 if (lookup.IsValid() && lookup.type() == INTERCEPTOR) { 856 // Get the property. 857 Object* result = object->GetProperty(*object, &lookup, *name, &attr); 858 if (result->IsFailure()) return result; 859 // If the property is not present, check if we need to throw an 860 // exception. 861 if (attr == ABSENT && is_contextual()) { 862 return ReferenceError("not_defined", name); 863 } 864 return result; 865 } 866 867 return object->GetProperty(*object, &lookup, *name, &attr); 868 } 869 870 // Do not use ICs for objects that require access checks (including 871 // the global object). 872 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 873 874 if (use_ic) { 875 Code* stub = generic_stub(); 876 if (object->IsJSObject()) { 877 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 878 if (receiver->HasExternalArrayElements()) { 879 stub = external_array_stub(receiver->GetElementsKind()); 880 } 881 } 882 set_target(stub); 883 // For JSObjects that are not value wrappers and that do not have 884 // indexed interceptors, we initialize the inlined fast case (if 885 // present) by patching the inlined map check. 886 if (object->IsJSObject() && 887 !object->IsJSValue() && 888 !JSObject::cast(*object)->HasIndexedInterceptor()) { 889 Map* map = JSObject::cast(*object)->map(); 890 PatchInlinedLoad(address(), map); 891 } 892 } 893 894 // Get the property. 895 return Runtime::GetObjectProperty(object, key); 896} 897 898 899void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, 900 Handle<Object> object, Handle<String> name) { 901 ASSERT(lookup->IsLoaded()); 902 // Bail out if we didn't find a result. 903 if (!lookup->IsValid() || !lookup->IsCacheable()) return; 904 905 if (!object->IsJSObject()) return; 906 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 907 908 // Compute the code stub for this load. 909 Object* code = NULL; 910 911 if (state == UNINITIALIZED) { 912 // This is the first time we execute this inline cache. 913 // Set the target to the pre monomorphic stub to delay 914 // setting the monomorphic state. 915 code = pre_monomorphic_stub(); 916 } else { 917 // Compute a monomorphic stub. 918 switch (lookup->type()) { 919 case FIELD: { 920 code = StubCache::ComputeKeyedLoadField(*name, *receiver, 921 lookup->holder(), 922 lookup->GetFieldIndex()); 923 break; 924 } 925 case CONSTANT_FUNCTION: { 926 Object* constant = lookup->GetConstantFunction(); 927 code = StubCache::ComputeKeyedLoadConstant(*name, *receiver, 928 lookup->holder(), constant); 929 break; 930 } 931 case CALLBACKS: { 932 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; 933 AccessorInfo* callback = 934 AccessorInfo::cast(lookup->GetCallbackObject()); 935 if (v8::ToCData<Address>(callback->getter()) == 0) return; 936 code = StubCache::ComputeKeyedLoadCallback(*name, *receiver, 937 lookup->holder(), callback); 938 break; 939 } 940 case INTERCEPTOR: { 941 ASSERT(HasInterceptorGetter(lookup->holder())); 942 code = StubCache::ComputeKeyedLoadInterceptor(*name, *receiver, 943 lookup->holder()); 944 break; 945 } 946 default: { 947 // Always rewrite to the generic case so that we do not 948 // repeatedly try to rewrite. 949 code = generic_stub(); 950 break; 951 } 952 } 953 } 954 955 // If we're unable to compute the stub (not enough memory left), we 956 // simply avoid updating the caches. 957 if (code == NULL || code->IsFailure()) return; 958 959 // Patch the call site depending on the state of the cache. Make 960 // sure to always rewrite from monomorphic to megamorphic. 961 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); 962 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { 963 set_target(Code::cast(code)); 964 } else if (state == MONOMORPHIC) { 965 set_target(megamorphic_stub()); 966 } 967 968#ifdef DEBUG 969 TraceIC("KeyedLoadIC", name, state, target()); 970#endif 971} 972 973 974static bool StoreICableLookup(LookupResult* lookup) { 975 // Bail out if we didn't find a result. 976 if (!lookup->IsValid() || !lookup->IsCacheable()) return false; 977 978 // If the property is read-only, we leave the IC in its current 979 // state. 980 if (lookup->IsReadOnly()) return false; 981 982 if (!lookup->IsLoaded()) return false; 983 984 return true; 985} 986 987 988static bool LookupForWrite(JSObject* object, 989 String* name, 990 LookupResult* lookup) { 991 object->LocalLookup(name, lookup); 992 if (!StoreICableLookup(lookup)) { 993 return false; 994 } 995 996 if (lookup->type() == INTERCEPTOR) { 997 if (object->GetNamedInterceptor()->setter()->IsUndefined()) { 998 object->LocalLookupRealNamedProperty(name, lookup); 999 return StoreICableLookup(lookup); 1000 } 1001 } 1002 1003 return true; 1004} 1005 1006 1007Object* StoreIC::Store(State state, 1008 Handle<Object> object, 1009 Handle<String> name, 1010 Handle<Object> value) { 1011 // If the object is undefined or null it's illegal to try to set any 1012 // properties on it; throw a TypeError in that case. 1013 if (object->IsUndefined() || object->IsNull()) { 1014 return TypeError("non_object_property_store", object, name); 1015 } 1016 1017 // Ignore stores where the receiver is not a JSObject. 1018 if (!object->IsJSObject()) return *value; 1019 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1020 1021 // Check if the given name is an array index. 1022 uint32_t index; 1023 if (name->AsArrayIndex(&index)) { 1024 HandleScope scope; 1025 Handle<Object> result = SetElement(receiver, index, value); 1026 if (result.is_null()) return Failure::Exception(); 1027 return *value; 1028 } 1029 1030 // Lookup the property locally in the receiver. 1031 if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { 1032 LookupResult lookup; 1033 if (LookupForWrite(*receiver, *name, &lookup)) { 1034 UpdateCaches(&lookup, state, receiver, name, value); 1035 } 1036 } 1037 1038 // Set the property. 1039 return receiver->SetProperty(*name, *value, NONE); 1040} 1041 1042 1043void StoreIC::UpdateCaches(LookupResult* lookup, 1044 State state, 1045 Handle<JSObject> receiver, 1046 Handle<String> name, 1047 Handle<Object> value) { 1048 ASSERT(lookup->IsLoaded()); 1049 // Skip JSGlobalProxy. 1050 ASSERT(!receiver->IsJSGlobalProxy()); 1051 1052 ASSERT(StoreICableLookup(lookup)); 1053 1054 // If the property has a non-field type allowing map transitions 1055 // where there is extra room in the object, we leave the IC in its 1056 // current state. 1057 PropertyType type = lookup->type(); 1058 1059 // Compute the code stub for this store; used for rewriting to 1060 // monomorphic state and making sure that the code stub is in the 1061 // stub cache. 1062 Object* code = NULL; 1063 switch (type) { 1064 case FIELD: { 1065 code = StubCache::ComputeStoreField(*name, *receiver, 1066 lookup->GetFieldIndex()); 1067 break; 1068 } 1069 case MAP_TRANSITION: { 1070 if (lookup->GetAttributes() != NONE) return; 1071 HandleScope scope; 1072 ASSERT(type == MAP_TRANSITION); 1073 Handle<Map> transition(lookup->GetTransitionMap()); 1074 int index = transition->PropertyIndexFor(*name); 1075 code = StubCache::ComputeStoreField(*name, *receiver, index, *transition); 1076 break; 1077 } 1078 case NORMAL: { 1079 if (!receiver->IsGlobalObject()) { 1080 return; 1081 } 1082 // The stub generated for the global object picks the value directly 1083 // from the property cell. So the property must be directly on the 1084 // global object. 1085 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 1086 JSGlobalPropertyCell* cell = 1087 JSGlobalPropertyCell::cast(global->GetPropertyCell(lookup)); 1088 code = StubCache::ComputeStoreGlobal(*name, *global, cell); 1089 break; 1090 } 1091 case CALLBACKS: { 1092 if (!lookup->GetCallbackObject()->IsAccessorInfo()) return; 1093 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); 1094 if (v8::ToCData<Address>(callback->setter()) == 0) return; 1095 code = StubCache::ComputeStoreCallback(*name, *receiver, callback); 1096 break; 1097 } 1098 case INTERCEPTOR: { 1099 ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); 1100 code = StubCache::ComputeStoreInterceptor(*name, *receiver); 1101 break; 1102 } 1103 default: 1104 return; 1105 } 1106 1107 // If we're unable to compute the stub (not enough memory left), we 1108 // simply avoid updating the caches. 1109 if (code == NULL || code->IsFailure()) return; 1110 1111 // Patch the call site depending on the state of the cache. 1112 if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) { 1113 set_target(Code::cast(code)); 1114 } else if (state == MONOMORPHIC) { 1115 // Only move to mega morphic if the target changes. 1116 if (target() != Code::cast(code)) set_target(megamorphic_stub()); 1117 } 1118 1119#ifdef DEBUG 1120 TraceIC("StoreIC", name, state, target()); 1121#endif 1122} 1123 1124 1125Object* KeyedStoreIC::Store(State state, 1126 Handle<Object> object, 1127 Handle<Object> key, 1128 Handle<Object> value) { 1129 if (key->IsSymbol()) { 1130 Handle<String> name = Handle<String>::cast(key); 1131 1132 // If the object is undefined or null it's illegal to try to set any 1133 // properties on it; throw a TypeError in that case. 1134 if (object->IsUndefined() || object->IsNull()) { 1135 return TypeError("non_object_property_store", object, name); 1136 } 1137 1138 // Ignore stores where the receiver is not a JSObject. 1139 if (!object->IsJSObject()) return *value; 1140 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1141 1142 // Check if the given name is an array index. 1143 uint32_t index; 1144 if (name->AsArrayIndex(&index)) { 1145 HandleScope scope; 1146 Handle<Object> result = SetElement(receiver, index, value); 1147 if (result.is_null()) return Failure::Exception(); 1148 return *value; 1149 } 1150 1151 // Lookup the property locally in the receiver. 1152 LookupResult lookup; 1153 receiver->LocalLookup(*name, &lookup); 1154 1155 // Update inline cache and stub cache. 1156 if (FLAG_use_ic && lookup.IsLoaded()) { 1157 UpdateCaches(&lookup, state, receiver, name, value); 1158 } 1159 1160 // Set the property. 1161 return receiver->SetProperty(*name, *value, NONE); 1162 } 1163 1164 // Do not use ICs for objects that require access checks (including 1165 // the global object). 1166 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); 1167 ASSERT(!(use_ic && object->IsJSGlobalProxy())); 1168 1169 if (use_ic) { 1170 Code* stub = generic_stub(); 1171 if (object->IsJSObject()) { 1172 Handle<JSObject> receiver = Handle<JSObject>::cast(object); 1173 if (receiver->HasExternalArrayElements()) { 1174 stub = external_array_stub(receiver->GetElementsKind()); 1175 } 1176 } 1177 set_target(stub); 1178 } 1179 1180 // Set the property. 1181 return Runtime::SetObjectProperty(object, key, value, NONE); 1182} 1183 1184 1185void KeyedStoreIC::UpdateCaches(LookupResult* lookup, 1186 State state, 1187 Handle<JSObject> receiver, 1188 Handle<String> name, 1189 Handle<Object> value) { 1190 ASSERT(lookup->IsLoaded()); 1191 1192 // Skip JSGlobalProxy. 1193 if (receiver->IsJSGlobalProxy()) return; 1194 1195 // Bail out if we didn't find a result. 1196 if (!lookup->IsValid() || !lookup->IsCacheable()) return; 1197 1198 // If the property is read-only, we leave the IC in its current 1199 // state. 1200 if (lookup->IsReadOnly()) return; 1201 1202 // If the property has a non-field type allowing map transitions 1203 // where there is extra room in the object, we leave the IC in its 1204 // current state. 1205 PropertyType type = lookup->type(); 1206 1207 // Compute the code stub for this store; used for rewriting to 1208 // monomorphic state and making sure that the code stub is in the 1209 // stub cache. 1210 Object* code = NULL; 1211 1212 switch (type) { 1213 case FIELD: { 1214 code = StubCache::ComputeKeyedStoreField(*name, *receiver, 1215 lookup->GetFieldIndex()); 1216 break; 1217 } 1218 case MAP_TRANSITION: { 1219 if (lookup->GetAttributes() == NONE) { 1220 HandleScope scope; 1221 ASSERT(type == MAP_TRANSITION); 1222 Handle<Map> transition(lookup->GetTransitionMap()); 1223 int index = transition->PropertyIndexFor(*name); 1224 code = StubCache::ComputeKeyedStoreField(*name, *receiver, 1225 index, *transition); 1226 break; 1227 } 1228 // fall through. 1229 } 1230 default: { 1231 // Always rewrite to the generic case so that we do not 1232 // repeatedly try to rewrite. 1233 code = generic_stub(); 1234 break; 1235 } 1236 } 1237 1238 // If we're unable to compute the stub (not enough memory left), we 1239 // simply avoid updating the caches. 1240 if (code == NULL || code->IsFailure()) return; 1241 1242 // Patch the call site depending on the state of the cache. Make 1243 // sure to always rewrite from monomorphic to megamorphic. 1244 ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE); 1245 if (state == UNINITIALIZED || state == PREMONOMORPHIC) { 1246 set_target(Code::cast(code)); 1247 } else if (state == MONOMORPHIC) { 1248 set_target(megamorphic_stub()); 1249 } 1250 1251#ifdef DEBUG 1252 TraceIC("KeyedStoreIC", name, state, target()); 1253#endif 1254} 1255 1256 1257// ---------------------------------------------------------------------------- 1258// Static IC stub generators. 1259// 1260 1261// Used from ic_<arch>.cc. 1262Object* CallIC_Miss(Arguments args) { 1263 NoHandleAllocation na; 1264 ASSERT(args.length() == 2); 1265 CallIC ic; 1266 IC::State state = IC::StateFrom(ic.target(), args[0]); 1267 Object* result = 1268 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); 1269 1270 // The first time the inline cache is updated may be the first time the 1271 // function it references gets called. If the function was lazily compiled 1272 // then the first call will trigger a compilation. We check for this case 1273 // and we do the compilation immediately, instead of waiting for the stub 1274 // currently attached to the JSFunction object to trigger compilation. We 1275 // do this in the case where we know that the inline cache is inside a loop, 1276 // because then we know that we want to optimize the function. 1277 if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { 1278 return result; 1279 } 1280 1281 // Compile now with optimization. 1282 HandleScope scope; 1283 Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); 1284 InLoopFlag in_loop = ic.target()->ic_in_loop(); 1285 if (in_loop == IN_LOOP) { 1286 CompileLazyInLoop(function, CLEAR_EXCEPTION); 1287 } else { 1288 CompileLazy(function, CLEAR_EXCEPTION); 1289 } 1290 return *function; 1291} 1292 1293 1294void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) { 1295 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); 1296} 1297 1298 1299void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { 1300 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); 1301} 1302 1303 1304// Used from ic_<arch>.cc. 1305Object* LoadIC_Miss(Arguments args) { 1306 NoHandleAllocation na; 1307 ASSERT(args.length() == 2); 1308 LoadIC ic; 1309 IC::State state = IC::StateFrom(ic.target(), args[0]); 1310 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); 1311} 1312 1313 1314void LoadIC::GenerateInitialize(MacroAssembler* masm) { 1315 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); 1316} 1317 1318 1319void LoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { 1320 Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss))); 1321} 1322 1323 1324// Used from ic_<arch>.cc 1325Object* KeyedLoadIC_Miss(Arguments args) { 1326 NoHandleAllocation na; 1327 ASSERT(args.length() == 2); 1328 KeyedLoadIC ic; 1329 IC::State state = IC::StateFrom(ic.target(), args[0]); 1330 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); 1331} 1332 1333 1334void KeyedLoadIC::GenerateInitialize(MacroAssembler* masm) { 1335 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); 1336} 1337 1338 1339void KeyedLoadIC::GeneratePreMonomorphic(MacroAssembler* masm) { 1340 Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); 1341} 1342 1343 1344// Used from ic_<arch>.cc. 1345Object* StoreIC_Miss(Arguments args) { 1346 NoHandleAllocation na; 1347 ASSERT(args.length() == 3); 1348 StoreIC ic; 1349 IC::State state = IC::StateFrom(ic.target(), args[0]); 1350 return ic.Store(state, args.at<Object>(0), args.at<String>(1), 1351 args.at<Object>(2)); 1352} 1353 1354 1355// Extend storage is called in a store inline cache when 1356// it is necessary to extend the properties array of a 1357// JSObject. 1358Object* SharedStoreIC_ExtendStorage(Arguments args) { 1359 NoHandleAllocation na; 1360 ASSERT(args.length() == 3); 1361 1362 // Convert the parameters 1363 JSObject* object = JSObject::cast(args[0]); 1364 Map* transition = Map::cast(args[1]); 1365 Object* value = args[2]; 1366 1367 // Check the object has run out out property space. 1368 ASSERT(object->HasFastProperties()); 1369 ASSERT(object->map()->unused_property_fields() == 0); 1370 1371 // Expand the properties array. 1372 FixedArray* old_storage = object->properties(); 1373 int new_unused = transition->unused_property_fields(); 1374 int new_size = old_storage->length() + new_unused + 1; 1375 Object* result = old_storage->CopySize(new_size); 1376 if (result->IsFailure()) return result; 1377 FixedArray* new_storage = FixedArray::cast(result); 1378 new_storage->set(old_storage->length(), value); 1379 1380 // Set the new property value and do the map transition. 1381 object->set_properties(new_storage); 1382 object->set_map(transition); 1383 1384 // Return the stored value. 1385 return value; 1386} 1387 1388 1389void StoreIC::GenerateInitialize(MacroAssembler* masm) { 1390 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); 1391} 1392 1393 1394void StoreIC::GenerateMiss(MacroAssembler* masm) { 1395 Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss))); 1396} 1397 1398 1399// Used from ic_<arch>.cc. 1400Object* KeyedStoreIC_Miss(Arguments args) { 1401 NoHandleAllocation na; 1402 ASSERT(args.length() == 3); 1403 KeyedStoreIC ic; 1404 IC::State state = IC::StateFrom(ic.target(), args[0]); 1405 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), 1406 args.at<Object>(2)); 1407} 1408 1409 1410void KeyedStoreIC::GenerateInitialize(MacroAssembler* masm) { 1411 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); 1412} 1413 1414 1415void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { 1416 Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss))); 1417} 1418 1419 1420static Address IC_utilities[] = { 1421#define ADDR(name) FUNCTION_ADDR(name), 1422 IC_UTIL_LIST(ADDR) 1423 NULL 1424#undef ADDR 1425}; 1426 1427 1428Address IC::AddressFromUtilityId(IC::UtilityId id) { 1429 return IC_utilities[id]; 1430} 1431 1432 1433} } // namespace v8::internal 1434