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