Home | History | Annotate | Download | only in src
      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