Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "api.h"
     31 #include "arguments.h"
     32 #include "ast.h"
     33 #include "code-stubs.h"
     34 #include "gdb-jit.h"
     35 #include "ic-inl.h"
     36 #include "stub-cache.h"
     37 #include "vm-state-inl.h"
     38 
     39 namespace v8 {
     40 namespace internal {
     41 
     42 // -----------------------------------------------------------------------
     43 // StubCache implementation.
     44 
     45 
     46 StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
     47   ASSERT(isolate == Isolate::Current());
     48 }
     49 
     50 
     51 void StubCache::Initialize() {
     52   ASSERT(IsPowerOf2(kPrimaryTableSize));
     53   ASSERT(IsPowerOf2(kSecondaryTableSize));
     54   Clear();
     55 }
     56 
     57 
     58 Code* StubCache::Set(String* name, Map* map, Code* code) {
     59   // Get the flags from the code.
     60   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
     61 
     62   // Validate that the name does not move on scavenge, and that we
     63   // can use identity checks instead of string equality checks.
     64   ASSERT(!heap()->InNewSpace(name));
     65   ASSERT(name->IsSymbol());
     66 
     67   // The state bits are not important to the hash function because
     68   // the stub cache only contains monomorphic stubs. Make sure that
     69   // the bits are the least significant so they will be the ones
     70   // masked out.
     71   ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
     72   STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
     73 
     74   // Make sure that the code type is not included in the hash.
     75   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
     76 
     77   // Compute the primary entry.
     78   int primary_offset = PrimaryOffset(name, flags, map);
     79   Entry* primary = entry(primary_, primary_offset);
     80   Code* old_code = primary->value;
     81 
     82   // If the primary entry has useful data in it, we retire it to the
     83   // secondary cache before overwriting it.
     84   if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
     85     Map* old_map = primary->map;
     86     Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
     87     int seed = PrimaryOffset(primary->key, old_flags, old_map);
     88     int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
     89     Entry* secondary = entry(secondary_, secondary_offset);
     90     *secondary = *primary;
     91   }
     92 
     93   // Update primary cache.
     94   primary->key = name;
     95   primary->value = code;
     96   primary->map = map;
     97   isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
     98   return code;
     99 }
    100 
    101 
    102 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
    103                                                Handle<JSObject> receiver) {
    104   ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
    105   // If no global objects are present in the prototype chain, the load
    106   // nonexistent IC stub can be shared for all names for a given map
    107   // and we use the empty string for the map cache in that case.  If
    108   // there are global objects involved, we need to check global
    109   // property cells in the stub and therefore the stub will be
    110   // specific to the name.
    111   Handle<String> cache_name = factory()->empty_string();
    112   if (receiver->IsGlobalObject()) cache_name = name;
    113   Handle<JSObject> last = receiver;
    114   while (last->GetPrototype() != heap()->null_value()) {
    115     last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
    116     if (last->IsGlobalObject()) cache_name = name;
    117   }
    118   // Compile the stub that is either shared for all names or
    119   // name specific if there are global objects involved.
    120   Code::Flags flags =
    121       Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
    122   Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags));
    123   if (probe->IsCode()) return Handle<Code>::cast(probe);
    124 
    125   LoadStubCompiler compiler(isolate_);
    126   Handle<Code> code =
    127       compiler.CompileLoadNonexistent(cache_name, receiver, last);
    128   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
    129   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
    130   JSObject::UpdateMapCodeCache(receiver, cache_name, code);
    131   return code;
    132 }
    133 
    134 
    135 Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
    136                                          Handle<JSObject> receiver,
    137                                          Handle<JSObject> holder,
    138                                          int field_index) {
    139   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    140   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
    141   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    142   if (probe->IsCode()) return Handle<Code>::cast(probe);
    143 
    144   LoadStubCompiler compiler(isolate_);
    145   Handle<Code> code =
    146       compiler.CompileLoadField(receiver, holder, field_index, name);
    147   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
    148   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
    149   JSObject::UpdateMapCodeCache(receiver, name, code);
    150   return code;
    151 }
    152 
    153 
    154 Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
    155                                             Handle<JSObject> receiver,
    156                                             Handle<JSObject> holder,
    157                                             Handle<AccessorInfo> callback) {
    158   ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
    159   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    160   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
    161   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    162   if (probe->IsCode()) return Handle<Code>::cast(probe);
    163 
    164   LoadStubCompiler compiler(isolate_);
    165   Handle<Code> code =
    166       compiler.CompileLoadCallback(name, receiver, holder, callback);
    167   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
    168   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
    169   JSObject::UpdateMapCodeCache(receiver, name, code);
    170   return code;
    171 }
    172 
    173 
    174 Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
    175                                             Handle<JSObject> receiver,
    176                                             Handle<JSObject> holder,
    177                                             Handle<JSFunction> value) {
    178   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    179   Code::Flags flags =
    180       Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
    181   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    182   if (probe->IsCode()) return Handle<Code>::cast(probe);
    183 
    184   LoadStubCompiler compiler(isolate_);
    185   Handle<Code> code =
    186         compiler.CompileLoadConstant(receiver, holder, value, name);
    187   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
    188   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
    189   JSObject::UpdateMapCodeCache(receiver, name, code);
    190   return code;
    191 }
    192 
    193 
    194 Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
    195                                                Handle<JSObject> receiver,
    196                                                Handle<JSObject> holder) {
    197   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    198   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
    199   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    200   if (probe->IsCode()) return Handle<Code>::cast(probe);
    201 
    202   LoadStubCompiler compiler(isolate_);
    203   Handle<Code> code =
    204         compiler.CompileLoadInterceptor(receiver, holder, name);
    205   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
    206   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
    207   JSObject::UpdateMapCodeCache(receiver, name, code);
    208   return code;
    209 }
    210 
    211 
    212 Handle<Code> StubCache::ComputeLoadNormal() {
    213   return isolate_->builtins()->LoadIC_Normal();
    214 }
    215 
    216 
    217 Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
    218                                           Handle<JSObject> receiver,
    219                                           Handle<GlobalObject> holder,
    220                                           Handle<JSGlobalPropertyCell> cell,
    221                                           bool is_dont_delete) {
    222   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    223   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
    224   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    225   if (probe->IsCode()) return Handle<Code>::cast(probe);
    226 
    227   LoadStubCompiler compiler(isolate_);
    228   Handle<Code> code =
    229       compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
    230   PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
    231   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
    232   JSObject::UpdateMapCodeCache(receiver, name, code);
    233   return code;
    234 }
    235 
    236 
    237 Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
    238                                               Handle<JSObject> receiver,
    239                                               Handle<JSObject> holder,
    240                                               int field_index) {
    241   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    242   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
    243   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    244   if (probe->IsCode()) return Handle<Code>::cast(probe);
    245 
    246   KeyedLoadStubCompiler compiler(isolate_);
    247   Handle<Code> code =
    248       compiler.CompileLoadField(name, receiver, holder, field_index);
    249   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    250   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    251   JSObject::UpdateMapCodeCache(receiver, name, code);
    252   return code;
    253 }
    254 
    255 
    256 Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
    257                                                  Handle<JSObject> receiver,
    258                                                  Handle<JSObject> holder,
    259                                                  Handle<JSFunction> value) {
    260   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    261   Code::Flags flags =
    262       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
    263   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    264   if (probe->IsCode()) return Handle<Code>::cast(probe);
    265 
    266   KeyedLoadStubCompiler compiler(isolate_);
    267   Handle<Code> code =
    268       compiler.CompileLoadConstant(name, receiver, holder, value);
    269   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    270   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    271   JSObject::UpdateMapCodeCache(receiver, name, code);
    272   return code;
    273 }
    274 
    275 
    276 Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
    277                                                     Handle<JSObject> receiver,
    278                                                     Handle<JSObject> holder) {
    279   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    280   Code::Flags flags =
    281       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
    282   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    283   if (probe->IsCode()) return Handle<Code>::cast(probe);
    284 
    285   KeyedLoadStubCompiler compiler(isolate_);
    286   Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
    287   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    288   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    289   JSObject::UpdateMapCodeCache(receiver, name, code);
    290   return code;
    291 }
    292 
    293 
    294 Handle<Code> StubCache::ComputeKeyedLoadCallback(
    295     Handle<String> name,
    296     Handle<JSObject> receiver,
    297     Handle<JSObject> holder,
    298     Handle<AccessorInfo> callback) {
    299   ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
    300   Code::Flags flags =
    301       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    302   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    303   if (probe->IsCode()) return Handle<Code>::cast(probe);
    304 
    305   KeyedLoadStubCompiler compiler(isolate_);
    306   Handle<Code> code =
    307       compiler.CompileLoadCallback(name, receiver, holder, callback);
    308   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    309   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    310   JSObject::UpdateMapCodeCache(receiver, name, code);
    311   return code;
    312 }
    313 
    314 
    315 Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name,
    316                                                     Handle<JSArray> receiver) {
    317   Code::Flags flags =
    318       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    319   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    320   if (probe->IsCode()) return Handle<Code>::cast(probe);
    321 
    322   KeyedLoadStubCompiler compiler(isolate_);
    323   Handle<Code> code = compiler.CompileLoadArrayLength(name);
    324   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    325   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    326   JSObject::UpdateMapCodeCache(receiver, name, code);
    327   return code;
    328 }
    329 
    330 
    331 Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
    332                                                      Handle<String> receiver) {
    333   Code::Flags flags =
    334       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    335   Handle<Map> map(receiver->map());
    336   Handle<Object> probe(map->FindInCodeCache(*name, flags));
    337   if (probe->IsCode()) return Handle<Code>::cast(probe);
    338 
    339   KeyedLoadStubCompiler compiler(isolate_);
    340   Handle<Code> code = compiler.CompileLoadStringLength(name);
    341   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    342   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    343   Map::UpdateCodeCache(map, name, code);
    344   return code;
    345 }
    346 
    347 
    348 Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
    349     Handle<String> name,
    350     Handle<JSFunction> receiver) {
    351   Code::Flags flags =
    352       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    353   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    354   if (probe->IsCode()) return Handle<Code>::cast(probe);
    355 
    356   KeyedLoadStubCompiler compiler(isolate_);
    357   Handle<Code> code = compiler.CompileLoadFunctionPrototype(name);
    358   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
    359   GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
    360   JSObject::UpdateMapCodeCache(receiver, name, code);
    361   return code;
    362 }
    363 
    364 
    365 Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
    366                                           Handle<JSObject> receiver,
    367                                           int field_index,
    368                                           Handle<Map> transition,
    369                                           StrictModeFlag strict_mode) {
    370   PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
    371   Code::Flags flags = Code::ComputeMonomorphicFlags(
    372       Code::STORE_IC, type, strict_mode);
    373   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    374   if (probe->IsCode()) return Handle<Code>::cast(probe);
    375 
    376   StoreStubCompiler compiler(isolate_, strict_mode);
    377   Handle<Code> code =
    378       compiler.CompileStoreField(receiver, field_index, transition, name);
    379   PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
    380   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
    381   JSObject::UpdateMapCodeCache(receiver, name, code);
    382   return code;
    383 }
    384 
    385 
    386 Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
    387     Handle<JSObject> receiver,
    388     KeyedIC::StubKind stub_kind,
    389     StrictModeFlag strict_mode) {
    390   KeyedAccessGrowMode grow_mode =
    391       KeyedIC::GetGrowModeFromStubKind(stub_kind);
    392   Code::ExtraICState extra_state =
    393       Code::ComputeExtraICState(grow_mode, strict_mode);
    394   Code::Flags flags =
    395       Code::ComputeMonomorphicFlags(
    396           stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
    397                                      : Code::KEYED_STORE_IC,
    398           NORMAL,
    399           extra_state);
    400   Handle<String> name;
    401   switch (stub_kind) {
    402     case KeyedIC::LOAD:
    403       name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
    404       break;
    405     case KeyedIC::STORE_NO_TRANSITION:
    406       name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
    407       break;
    408     case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
    409       name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
    410       break;
    411     default:
    412       UNREACHABLE();
    413       break;
    414   }
    415   Handle<Map> receiver_map(receiver->map());
    416   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags));
    417   if (probe->IsCode()) return Handle<Code>::cast(probe);
    418 
    419   Handle<Code> code;
    420   switch (stub_kind) {
    421     case KeyedIC::LOAD: {
    422       KeyedLoadStubCompiler compiler(isolate_);
    423       code = compiler.CompileLoadElement(receiver_map);
    424       break;
    425     }
    426     case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
    427       KeyedStoreStubCompiler compiler(isolate_, strict_mode,
    428                                       ALLOW_JSARRAY_GROWTH);
    429       code = compiler.CompileStoreElement(receiver_map);
    430       break;
    431     }
    432     case KeyedIC::STORE_NO_TRANSITION: {
    433       KeyedStoreStubCompiler compiler(isolate_, strict_mode,
    434                                       DO_NOT_ALLOW_JSARRAY_GROWTH);
    435       code = compiler.CompileStoreElement(receiver_map);
    436       break;
    437     }
    438     default:
    439       UNREACHABLE();
    440       break;
    441   }
    442 
    443   ASSERT(!code.is_null());
    444 
    445   if (stub_kind == KeyedIC::LOAD) {
    446     PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
    447   } else {
    448     PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
    449   }
    450   JSObject::UpdateMapCodeCache(receiver, name, code);
    451   return code;
    452 }
    453 
    454 
    455 Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
    456   return (strict_mode == kStrictMode)
    457       ? isolate_->builtins()->Builtins::StoreIC_Normal_Strict()
    458       : isolate_->builtins()->Builtins::StoreIC_Normal();
    459 }
    460 
    461 
    462 Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
    463                                            Handle<GlobalObject> receiver,
    464                                            Handle<JSGlobalPropertyCell> cell,
    465                                            StrictModeFlag strict_mode) {
    466   Code::Flags flags = Code::ComputeMonomorphicFlags(
    467       Code::STORE_IC, NORMAL, strict_mode);
    468   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    469   if (probe->IsCode()) return Handle<Code>::cast(probe);
    470 
    471   StoreStubCompiler compiler(isolate_, strict_mode);
    472   Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
    473   PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
    474   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
    475   JSObject::UpdateMapCodeCache(receiver, name, code);
    476   return code;
    477 }
    478 
    479 
    480 Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name,
    481                                              Handle<JSObject> receiver,
    482                                              Handle<AccessorInfo> callback,
    483                                              StrictModeFlag strict_mode) {
    484   ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
    485   Code::Flags flags = Code::ComputeMonomorphicFlags(
    486       Code::STORE_IC, CALLBACKS, strict_mode);
    487   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    488   if (probe->IsCode()) return Handle<Code>::cast(probe);
    489 
    490   StoreStubCompiler compiler(isolate_, strict_mode);
    491   Handle<Code> code = compiler.CompileStoreCallback(receiver, callback, name);
    492   PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
    493   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
    494   JSObject::UpdateMapCodeCache(receiver, name, code);
    495   return code;
    496 }
    497 
    498 
    499 Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
    500                                                 Handle<JSObject> receiver,
    501                                                 StrictModeFlag strict_mode) {
    502   Code::Flags flags = Code::ComputeMonomorphicFlags(
    503       Code::STORE_IC, INTERCEPTOR, strict_mode);
    504   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    505   if (probe->IsCode()) return Handle<Code>::cast(probe);
    506 
    507   StoreStubCompiler compiler(isolate_, strict_mode);
    508   Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
    509   PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
    510   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
    511   JSObject::UpdateMapCodeCache(receiver, name, code);
    512   return code;
    513 }
    514 
    515 Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
    516                                                Handle<JSObject> receiver,
    517                                                int field_index,
    518                                                Handle<Map> transition,
    519                                                StrictModeFlag strict_mode) {
    520   PropertyType type = (transition.is_null()) ? FIELD : MAP_TRANSITION;
    521   Code::Flags flags = Code::ComputeMonomorphicFlags(
    522       Code::KEYED_STORE_IC, type, strict_mode);
    523   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
    524   if (probe->IsCode()) return Handle<Code>::cast(probe);
    525 
    526   KeyedStoreStubCompiler compiler(isolate(), strict_mode,
    527                                   DO_NOT_ALLOW_JSARRAY_GROWTH);
    528   Handle<Code> code =
    529       compiler.CompileStoreField(receiver, field_index, transition, name);
    530   PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
    531   GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
    532   JSObject::UpdateMapCodeCache(receiver, name, code);
    533   return code;
    534 }
    535 
    536 
    537 #define CALL_LOGGER_TAG(kind, type) \
    538     (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
    539 
    540 Handle<Code> StubCache::ComputeCallConstant(int argc,
    541                                             Code::Kind kind,
    542                                             Code::ExtraICState extra_state,
    543                                             Handle<String> name,
    544                                             Handle<Object> object,
    545                                             Handle<JSObject> holder,
    546                                             Handle<JSFunction> function) {
    547   // Compute the check type and the map.
    548   InlineCacheHolderFlag cache_holder =
    549       IC::GetCodeCacheForObject(*object, *holder);
    550   Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
    551 
    552   // Compute check type based on receiver/holder.
    553   CheckType check = RECEIVER_MAP_CHECK;
    554   if (object->IsString()) {
    555     check = STRING_CHECK;
    556   } else if (object->IsNumber()) {
    557     check = NUMBER_CHECK;
    558   } else if (object->IsBoolean()) {
    559     check = BOOLEAN_CHECK;
    560   }
    561 
    562   Code::Flags flags =
    563       Code::ComputeMonomorphicFlags(kind, CONSTANT_FUNCTION, extra_state,
    564                                     cache_holder, argc);
    565   Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
    566   if (probe->IsCode()) return Handle<Code>::cast(probe);
    567 
    568   CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
    569   Handle<Code> code =
    570       compiler.CompileCallConstant(object, holder, function, name, check);
    571   code->set_check_type(check);
    572   ASSERT_EQ(flags, code->flags());
    573   PROFILE(isolate_,
    574           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
    575   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
    576   JSObject::UpdateMapCodeCache(map_holder, name, code);
    577   return code;
    578 }
    579 
    580 
    581 Handle<Code> StubCache::ComputeCallField(int argc,
    582                                          Code::Kind kind,
    583                                          Code::ExtraICState extra_state,
    584                                          Handle<String> name,
    585                                          Handle<Object> object,
    586                                          Handle<JSObject> holder,
    587                                          int index) {
    588   // Compute the check type and the map.
    589   InlineCacheHolderFlag cache_holder =
    590       IC::GetCodeCacheForObject(*object, *holder);
    591   Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
    592 
    593   // TODO(1233596): We cannot do receiver map check for non-JS objects
    594   // because they may be represented as immediates without a
    595   // map. Instead, we check against the map in the holder.
    596   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    597     object = holder;
    598   }
    599 
    600   Code::Flags flags =
    601       Code::ComputeMonomorphicFlags(kind, FIELD, extra_state,
    602                                     cache_holder, argc);
    603   Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
    604   if (probe->IsCode()) return Handle<Code>::cast(probe);
    605 
    606   CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
    607   Handle<Code> code =
    608       compiler.CompileCallField(Handle<JSObject>::cast(object),
    609                                 holder, index, name);
    610   ASSERT_EQ(flags, code->flags());
    611   PROFILE(isolate_,
    612           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
    613   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
    614   JSObject::UpdateMapCodeCache(map_holder, name, code);
    615   return code;
    616 }
    617 
    618 
    619 Handle<Code> StubCache::ComputeCallInterceptor(int argc,
    620                                                Code::Kind kind,
    621                                                Code::ExtraICState extra_state,
    622                                                Handle<String> name,
    623                                                Handle<Object> object,
    624                                                Handle<JSObject> holder) {
    625   // Compute the check type and the map.
    626   InlineCacheHolderFlag cache_holder =
    627       IC::GetCodeCacheForObject(*object, *holder);
    628   Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));
    629 
    630   // TODO(1233596): We cannot do receiver map check for non-JS objects
    631   // because they may be represented as immediates without a
    632   // map. Instead, we check against the map in the holder.
    633   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    634     object = holder;
    635   }
    636 
    637   Code::Flags flags =
    638       Code::ComputeMonomorphicFlags(kind, INTERCEPTOR, extra_state,
    639                                     cache_holder, argc);
    640   Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
    641   if (probe->IsCode()) return Handle<Code>::cast(probe);
    642 
    643   CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
    644   Handle<Code> code =
    645       compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
    646                                       holder, name);
    647   ASSERT_EQ(flags, code->flags());
    648   PROFILE(isolate(),
    649           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
    650   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
    651   JSObject::UpdateMapCodeCache(map_holder, name, code);
    652   return code;
    653 }
    654 
    655 
    656 Handle<Code> StubCache::ComputeCallGlobal(int argc,
    657                                           Code::Kind kind,
    658                                           Code::ExtraICState extra_state,
    659                                           Handle<String> name,
    660                                           Handle<JSObject> receiver,
    661                                           Handle<GlobalObject> holder,
    662                                           Handle<JSGlobalPropertyCell> cell,
    663                                           Handle<JSFunction> function) {
    664   InlineCacheHolderFlag cache_holder =
    665       IC::GetCodeCacheForObject(*receiver, *holder);
    666   Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
    667   Code::Flags flags =
    668       Code::ComputeMonomorphicFlags(kind, NORMAL, extra_state,
    669                                     cache_holder, argc);
    670   Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
    671   if (probe->IsCode()) return Handle<Code>::cast(probe);
    672 
    673   CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
    674   Handle<Code> code =
    675       compiler.CompileCallGlobal(receiver, holder, cell, function, name);
    676   ASSERT_EQ(flags, code->flags());
    677   PROFILE(isolate(),
    678           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
    679   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
    680   JSObject::UpdateMapCodeCache(map_holder, name, code);
    681   return code;
    682 }
    683 
    684 
    685 static void FillCache(Isolate* isolate, Handle<Code> code) {
    686   Handle<UnseededNumberDictionary> dictionary =
    687       UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
    688                                     code->flags(),
    689                                     code);
    690   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
    691 }
    692 
    693 
    694 Code* StubCache::FindCallInitialize(int argc,
    695                                     RelocInfo::Mode mode,
    696                                     Code::Kind kind) {
    697   Code::ExtraICState extra_state =
    698       CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
    699       CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
    700   Code::Flags flags =
    701       Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
    702 
    703   // Use raw_unchecked... so we don't get assert failures during GC.
    704   UnseededNumberDictionary* dictionary =
    705       isolate()->heap()->raw_unchecked_non_monomorphic_cache();
    706   int entry = dictionary->FindEntry(isolate(), flags);
    707   ASSERT(entry != -1);
    708   Object* code = dictionary->ValueAt(entry);
    709   // This might be called during the marking phase of the collector
    710   // hence the unchecked cast.
    711   return reinterpret_cast<Code*>(code);
    712 }
    713 
    714 
    715 Handle<Code> StubCache::ComputeCallInitialize(int argc,
    716                                               RelocInfo::Mode mode,
    717                                               Code::Kind kind) {
    718   Code::ExtraICState extra_state =
    719       CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
    720       CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
    721   Code::Flags flags =
    722       Code::ComputeFlags(kind, UNINITIALIZED, extra_state, NORMAL, argc);
    723   Handle<UnseededNumberDictionary> cache =
    724       isolate_->factory()->non_monomorphic_cache();
    725   int entry = cache->FindEntry(isolate_, flags);
    726   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    727 
    728   StubCompiler compiler(isolate_);
    729   Handle<Code> code = compiler.CompileCallInitialize(flags);
    730   FillCache(isolate_, code);
    731   return code;
    732 }
    733 
    734 
    735 Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
    736   return ComputeCallInitialize(argc, mode, Code::CALL_IC);
    737 }
    738 
    739 
    740 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
    741   return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
    742                                Code::KEYED_CALL_IC);
    743 }
    744 
    745 
    746 Handle<Code> StubCache::ComputeCallPreMonomorphic(
    747     int argc,
    748     Code::Kind kind,
    749     Code::ExtraICState extra_state) {
    750   Code::Flags flags =
    751       Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, NORMAL, argc);
    752   Handle<UnseededNumberDictionary> cache =
    753       isolate_->factory()->non_monomorphic_cache();
    754   int entry = cache->FindEntry(isolate_, flags);
    755   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    756 
    757   StubCompiler compiler(isolate_);
    758   Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
    759   FillCache(isolate_, code);
    760   return code;
    761 }
    762 
    763 
    764 Handle<Code> StubCache::ComputeCallNormal(int argc,
    765                                           Code::Kind kind,
    766                                           Code::ExtraICState extra_state) {
    767   Code::Flags flags =
    768       Code::ComputeFlags(kind, MONOMORPHIC, extra_state, NORMAL, argc);
    769   Handle<UnseededNumberDictionary> cache =
    770       isolate_->factory()->non_monomorphic_cache();
    771   int entry = cache->FindEntry(isolate_, flags);
    772   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    773 
    774   StubCompiler compiler(isolate_);
    775   Handle<Code> code = compiler.CompileCallNormal(flags);
    776   FillCache(isolate_, code);
    777   return code;
    778 }
    779 
    780 
    781 Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
    782   ASSERT(kind == Code::KEYED_CALL_IC);
    783   Code::Flags flags =
    784       Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
    785                          NORMAL, argc);
    786   Handle<UnseededNumberDictionary> cache =
    787       isolate_->factory()->non_monomorphic_cache();
    788   int entry = cache->FindEntry(isolate_, flags);
    789   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    790 
    791   StubCompiler compiler(isolate_);
    792   Handle<Code> code = compiler.CompileCallArguments(flags);
    793   FillCache(isolate_, code);
    794   return code;
    795 }
    796 
    797 
    798 Handle<Code> StubCache::ComputeCallMegamorphic(
    799     int argc,
    800     Code::Kind kind,
    801     Code::ExtraICState extra_state) {
    802   Code::Flags flags =
    803       Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
    804                          NORMAL, argc);
    805   Handle<UnseededNumberDictionary> cache =
    806       isolate_->factory()->non_monomorphic_cache();
    807   int entry = cache->FindEntry(isolate_, flags);
    808   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    809 
    810   StubCompiler compiler(isolate_);
    811   Handle<Code> code = compiler.CompileCallMegamorphic(flags);
    812   FillCache(isolate_, code);
    813   return code;
    814 }
    815 
    816 
    817 Handle<Code> StubCache::ComputeCallMiss(int argc,
    818                                         Code::Kind kind,
    819                                         Code::ExtraICState extra_state) {
    820   // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
    821   // and monomorphic stubs are not mixed up together in the stub cache.
    822   Code::Flags flags =
    823       Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
    824                          NORMAL, argc, OWN_MAP);
    825   Handle<UnseededNumberDictionary> cache =
    826       isolate_->factory()->non_monomorphic_cache();
    827   int entry = cache->FindEntry(isolate_, flags);
    828   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    829 
    830   StubCompiler compiler(isolate_);
    831   Handle<Code> code = compiler.CompileCallMiss(flags);
    832   FillCache(isolate_, code);
    833   return code;
    834 }
    835 
    836 
    837 #ifdef ENABLE_DEBUGGER_SUPPORT
    838 Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
    839                                               Code::Kind kind) {
    840   // Extra IC state is irrelevant for debug break ICs. They jump to
    841   // the actual call ic to carry out the work.
    842   Code::Flags flags =
    843       Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState,
    844                          NORMAL, argc);
    845   Handle<UnseededNumberDictionary> cache =
    846       isolate_->factory()->non_monomorphic_cache();
    847   int entry = cache->FindEntry(isolate_, flags);
    848   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    849 
    850   StubCompiler compiler(isolate_);
    851   Handle<Code> code = compiler.CompileCallDebugBreak(flags);
    852   FillCache(isolate_, code);
    853   return code;
    854 }
    855 
    856 
    857 Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
    858                                                       Code::Kind kind) {
    859   // Extra IC state is irrelevant for debug break ICs. They jump to
    860   // the actual call ic to carry out the work.
    861   Code::Flags flags =
    862       Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState,
    863                          NORMAL, argc);
    864   Handle<UnseededNumberDictionary> cache =
    865       isolate_->factory()->non_monomorphic_cache();
    866   int entry = cache->FindEntry(isolate_, flags);
    867   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    868 
    869   StubCompiler compiler(isolate_);
    870   Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
    871   FillCache(isolate_, code);
    872   return code;
    873 }
    874 #endif
    875 
    876 
    877 void StubCache::Clear() {
    878   Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
    879   for (int i = 0; i < kPrimaryTableSize; i++) {
    880     primary_[i].key = heap()->empty_string();
    881     primary_[i].value = empty;
    882   }
    883   for (int j = 0; j < kSecondaryTableSize; j++) {
    884     secondary_[j].key = heap()->empty_string();
    885     secondary_[j].value = empty;
    886   }
    887 }
    888 
    889 
    890 void StubCache::CollectMatchingMaps(SmallMapList* types,
    891                                     String* name,
    892                                     Code::Flags flags,
    893                                     Handle<Context> global_context) {
    894   for (int i = 0; i < kPrimaryTableSize; i++) {
    895     if (primary_[i].key == name) {
    896       Map* map = primary_[i].value->FindFirstMap();
    897       // Map can be NULL, if the stub is constant function call
    898       // with a primitive receiver.
    899       if (map == NULL) continue;
    900 
    901       int offset = PrimaryOffset(name, flags, map);
    902       if (entry(primary_, offset) == &primary_[i] &&
    903           !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
    904         types->Add(Handle<Map>(map));
    905       }
    906     }
    907   }
    908 
    909   for (int i = 0; i < kSecondaryTableSize; i++) {
    910     if (secondary_[i].key == name) {
    911       Map* map = secondary_[i].value->FindFirstMap();
    912       // Map can be NULL, if the stub is constant function call
    913       // with a primitive receiver.
    914       if (map == NULL) continue;
    915 
    916       // Lookup in primary table and skip duplicates.
    917       int primary_offset = PrimaryOffset(name, flags, map);
    918       Entry* primary_entry = entry(primary_, primary_offset);
    919       if (primary_entry->key == name) {
    920         Map* primary_map = primary_entry->value->FindFirstMap();
    921         if (map == primary_map) continue;
    922       }
    923 
    924       // Lookup in secondary table and add matches.
    925       int offset = SecondaryOffset(name, flags, primary_offset);
    926       if (entry(secondary_, offset) == &secondary_[i] &&
    927           !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
    928         types->Add(Handle<Map>(map));
    929       }
    930     }
    931   }
    932 }
    933 
    934 
    935 // ------------------------------------------------------------------------
    936 // StubCompiler implementation.
    937 
    938 
    939 RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
    940   ASSERT(args[0]->IsJSObject());
    941   ASSERT(args[1]->IsJSObject());
    942   AccessorInfo* callback = AccessorInfo::cast(args[3]);
    943   Address getter_address = v8::ToCData<Address>(callback->getter());
    944   v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
    945   ASSERT(fun != NULL);
    946   v8::AccessorInfo info(&args[0]);
    947   HandleScope scope(isolate);
    948   v8::Handle<v8::Value> result;
    949   {
    950     // Leaving JavaScript.
    951     VMState state(isolate, EXTERNAL);
    952     ExternalCallbackScope call_scope(isolate, getter_address);
    953     result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
    954   }
    955   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
    956   if (result.IsEmpty()) return HEAP->undefined_value();
    957   return *v8::Utils::OpenHandle(*result);
    958 }
    959 
    960 
    961 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
    962   JSObject* recv = JSObject::cast(args[0]);
    963   AccessorInfo* callback = AccessorInfo::cast(args[1]);
    964   Address setter_address = v8::ToCData<Address>(callback->setter());
    965   v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
    966   ASSERT(fun != NULL);
    967   Handle<String> name = args.at<String>(2);
    968   Handle<Object> value = args.at<Object>(3);
    969   HandleScope scope(isolate);
    970   LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
    971   CustomArguments custom_args(isolate, callback->data(), recv, recv);
    972   v8::AccessorInfo info(custom_args.end());
    973   {
    974     // Leaving JavaScript.
    975     VMState state(isolate, EXTERNAL);
    976     ExternalCallbackScope call_scope(isolate, setter_address);
    977     fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
    978   }
    979   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
    980   return *value;
    981 }
    982 
    983 
    984 static const int kAccessorInfoOffsetInInterceptorArgs = 2;
    985 
    986 
    987 /**
    988  * Attempts to load a property with an interceptor (which must be present),
    989  * but doesn't search the prototype chain.
    990  *
    991  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
    992  * provide any value for the given name.
    993  */
    994 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
    995   Handle<String> name_handle = args.at<String>(0);
    996   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
    997   ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
    998   ASSERT(args[2]->IsJSObject());  // Receiver.
    999   ASSERT(args[3]->IsJSObject());  // Holder.
   1000   ASSERT(args.length() == 5);  // Last arg is data object.
   1001 
   1002   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   1003   v8::NamedPropertyGetter getter =
   1004       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   1005   ASSERT(getter != NULL);
   1006 
   1007   {
   1008     // Use the interceptor getter.
   1009     v8::AccessorInfo info(args.arguments() -
   1010                           kAccessorInfoOffsetInInterceptorArgs);
   1011     HandleScope scope(isolate);
   1012     v8::Handle<v8::Value> r;
   1013     {
   1014       // Leaving JavaScript.
   1015       VMState state(isolate, EXTERNAL);
   1016       r = getter(v8::Utils::ToLocal(name_handle), info);
   1017     }
   1018     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1019     if (!r.IsEmpty()) {
   1020       return *v8::Utils::OpenHandle(*r);
   1021     }
   1022   }
   1023 
   1024   return isolate->heap()->no_interceptor_result_sentinel();
   1025 }
   1026 
   1027 
   1028 static MaybeObject* ThrowReferenceError(String* name) {
   1029   // If the load is non-contextual, just return the undefined result.
   1030   // Note that both keyed and non-keyed loads may end up here, so we
   1031   // can't use either LoadIC or KeyedLoadIC constructors.
   1032   IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
   1033   ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
   1034   if (!ic.SlowIsContextual()) return HEAP->undefined_value();
   1035 
   1036   // Throw a reference error.
   1037   HandleScope scope;
   1038   Handle<String> name_handle(name);
   1039   Handle<Object> error =
   1040       FACTORY->NewReferenceError("not_defined",
   1041                                   HandleVector(&name_handle, 1));
   1042   return Isolate::Current()->Throw(*error);
   1043 }
   1044 
   1045 
   1046 static MaybeObject* LoadWithInterceptor(Arguments* args,
   1047                                         PropertyAttributes* attrs) {
   1048   Handle<String> name_handle = args->at<String>(0);
   1049   Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
   1050   ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
   1051   Handle<JSObject> receiver_handle = args->at<JSObject>(2);
   1052   Handle<JSObject> holder_handle = args->at<JSObject>(3);
   1053   ASSERT(args->length() == 5);  // Last arg is data object.
   1054 
   1055   Isolate* isolate = receiver_handle->GetIsolate();
   1056 
   1057   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   1058   v8::NamedPropertyGetter getter =
   1059       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   1060   ASSERT(getter != NULL);
   1061 
   1062   {
   1063     // Use the interceptor getter.
   1064     v8::AccessorInfo info(args->arguments() -
   1065                           kAccessorInfoOffsetInInterceptorArgs);
   1066     HandleScope scope(isolate);
   1067     v8::Handle<v8::Value> r;
   1068     {
   1069       // Leaving JavaScript.
   1070       VMState state(isolate, EXTERNAL);
   1071       r = getter(v8::Utils::ToLocal(name_handle), info);
   1072     }
   1073     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1074     if (!r.IsEmpty()) {
   1075       *attrs = NONE;
   1076       return *v8::Utils::OpenHandle(*r);
   1077     }
   1078   }
   1079 
   1080   MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
   1081       *receiver_handle,
   1082       *name_handle,
   1083       attrs);
   1084   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1085   return result;
   1086 }
   1087 
   1088 
   1089 /**
   1090  * Loads a property with an interceptor performing post interceptor
   1091  * lookup if interceptor failed.
   1092  */
   1093 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
   1094   PropertyAttributes attr = NONE;
   1095   Object* result;
   1096   { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
   1097     if (!maybe_result->ToObject(&result)) return maybe_result;
   1098   }
   1099 
   1100   // If the property is present, return it.
   1101   if (attr != ABSENT) return result;
   1102   return ThrowReferenceError(String::cast(args[0]));
   1103 }
   1104 
   1105 
   1106 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
   1107   PropertyAttributes attr;
   1108   MaybeObject* result = LoadWithInterceptor(&args, &attr);
   1109   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1110   // This is call IC. In this case, we simply return the undefined result which
   1111   // will lead to an exception when trying to invoke the result as a
   1112   // function.
   1113   return result;
   1114 }
   1115 
   1116 
   1117 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
   1118   ASSERT(args.length() == 4);
   1119   JSObject* recv = JSObject::cast(args[0]);
   1120   String* name = String::cast(args[1]);
   1121   Object* value = args[2];
   1122   ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
   1123   StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
   1124   ASSERT(recv->HasNamedInterceptor());
   1125   PropertyAttributes attr = NONE;
   1126   MaybeObject* result = recv->SetPropertyWithInterceptor(
   1127       name, value, attr, strict_mode);
   1128   return result;
   1129 }
   1130 
   1131 
   1132 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
   1133   JSObject* receiver = JSObject::cast(args[0]);
   1134   ASSERT(args.smi_at(1) >= 0);
   1135   uint32_t index = args.smi_at(1);
   1136   return receiver->GetElementWithInterceptor(receiver, index);
   1137 }
   1138 
   1139 
   1140 Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
   1141   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1142   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1143   Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
   1144   if (kind == Code::CALL_IC) {
   1145     CallIC::GenerateInitialize(masm(), argc, extra_state);
   1146   } else {
   1147     KeyedCallIC::GenerateInitialize(masm(), argc);
   1148   }
   1149   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
   1150   isolate()->counters()->call_initialize_stubs()->Increment();
   1151   PROFILE(isolate(),
   1152           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
   1153                           *code, code->arguments_count()));
   1154   GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
   1155   return code;
   1156 }
   1157 
   1158 
   1159 Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
   1160   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1161   // The code of the PreMonomorphic stub is the same as the code
   1162   // of the Initialized stub.  They just differ on the code object flags.
   1163   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1164   Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
   1165   if (kind == Code::CALL_IC) {
   1166     CallIC::GenerateInitialize(masm(), argc, extra_state);
   1167   } else {
   1168     KeyedCallIC::GenerateInitialize(masm(), argc);
   1169   }
   1170   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
   1171   isolate()->counters()->call_premonomorphic_stubs()->Increment();
   1172   PROFILE(isolate(),
   1173           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
   1174                           *code, code->arguments_count()));
   1175   GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
   1176   return code;
   1177 }
   1178 
   1179 
   1180 Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
   1181   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1182   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1183   if (kind == Code::CALL_IC) {
   1184     // Call normal is always with a explict receiver.
   1185     ASSERT(!CallIC::Contextual::decode(
   1186         Code::ExtractExtraICStateFromFlags(flags)));
   1187     CallIC::GenerateNormal(masm(), argc);
   1188   } else {
   1189     KeyedCallIC::GenerateNormal(masm(), argc);
   1190   }
   1191   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
   1192   isolate()->counters()->call_normal_stubs()->Increment();
   1193   PROFILE(isolate(),
   1194           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
   1195                           *code, code->arguments_count()));
   1196   GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
   1197   return code;
   1198 }
   1199 
   1200 
   1201 Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
   1202   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1203   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1204   Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
   1205   if (kind == Code::CALL_IC) {
   1206     CallIC::GenerateMegamorphic(masm(), argc, extra_state);
   1207   } else {
   1208     KeyedCallIC::GenerateMegamorphic(masm(), argc);
   1209   }
   1210   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
   1211   isolate()->counters()->call_megamorphic_stubs()->Increment();
   1212   PROFILE(isolate(),
   1213           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
   1214                           *code, code->arguments_count()));
   1215   GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
   1216   return code;
   1217 }
   1218 
   1219 
   1220 Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
   1221   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1222   KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
   1223   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
   1224   PROFILE(isolate(),
   1225           CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
   1226                                           CALL_MEGAMORPHIC_TAG),
   1227                           *code, code->arguments_count()));
   1228   GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
   1229   return code;
   1230 }
   1231 
   1232 
   1233 Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
   1234   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1235   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1236   Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
   1237   if (kind == Code::CALL_IC) {
   1238     CallIC::GenerateMiss(masm(), argc, extra_state);
   1239   } else {
   1240     KeyedCallIC::GenerateMiss(masm(), argc);
   1241   }
   1242   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
   1243   isolate()->counters()->call_megamorphic_stubs()->Increment();
   1244   PROFILE(isolate(),
   1245           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
   1246                           *code, code->arguments_count()));
   1247   GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
   1248   return code;
   1249 }
   1250 
   1251 
   1252 #ifdef ENABLE_DEBUGGER_SUPPORT
   1253 Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
   1254   Debug::GenerateCallICDebugBreak(masm());
   1255   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
   1256   PROFILE(isolate(),
   1257           CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
   1258                                           CALL_DEBUG_BREAK_TAG),
   1259                           *code, code->arguments_count()));
   1260   return code;
   1261 }
   1262 
   1263 
   1264 Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
   1265   // Use the same code for the the step in preparations as we do for the
   1266   // miss case.
   1267   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1268   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1269   if (kind == Code::CALL_IC) {
   1270     // For the debugger extra ic state is irrelevant.
   1271     CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
   1272   } else {
   1273     KeyedCallIC::GenerateMiss(masm(), argc);
   1274   }
   1275   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
   1276   PROFILE(isolate(),
   1277           CodeCreateEvent(
   1278               CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
   1279               *code,
   1280               code->arguments_count()));
   1281   return code;
   1282 }
   1283 #endif  // ENABLE_DEBUGGER_SUPPORT
   1284 
   1285 #undef CALL_LOGGER_TAG
   1286 
   1287 
   1288 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
   1289                                             const char* name) {
   1290   // Create code object in the heap.
   1291   CodeDesc desc;
   1292   masm_.GetCode(&desc);
   1293   Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
   1294 #ifdef ENABLE_DISASSEMBLER
   1295   if (FLAG_print_code_stubs) code->Disassemble(name);
   1296 #endif
   1297   return code;
   1298 }
   1299 
   1300 
   1301 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
   1302                                             Handle<String> name) {
   1303   return (FLAG_print_code_stubs && !name.is_null())
   1304       ? GetCodeWithFlags(flags, *name->ToCString())
   1305       : GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
   1306 }
   1307 
   1308 
   1309 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
   1310                                          Handle<String> name,
   1311                                          LookupResult* lookup) {
   1312   holder->LocalLookupRealNamedProperty(*name, lookup);
   1313   if (lookup->IsProperty()) return;
   1314 
   1315   lookup->NotFound();
   1316   if (holder->GetPrototype()->IsNull()) return;
   1317 
   1318   holder->GetPrototype()->Lookup(*name, lookup);
   1319 }
   1320 
   1321 
   1322 Handle<Code> LoadStubCompiler::GetCode(PropertyType type, Handle<String> name) {
   1323   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
   1324   Handle<Code> code = GetCodeWithFlags(flags, name);
   1325   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
   1326   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
   1327   return code;
   1328 }
   1329 
   1330 
   1331 Handle<Code> KeyedLoadStubCompiler::GetCode(PropertyType type,
   1332                                             Handle<String> name,
   1333                                             InlineCacheState state) {
   1334   Code::Flags flags = Code::ComputeFlags(
   1335       Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
   1336   Handle<Code> code = GetCodeWithFlags(flags, name);
   1337   PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
   1338   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
   1339   return code;
   1340 }
   1341 
   1342 
   1343 Handle<Code> StoreStubCompiler::GetCode(PropertyType type,
   1344                                         Handle<String> name) {
   1345   Code::Flags flags =
   1346       Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
   1347   Handle<Code> code = GetCodeWithFlags(flags, name);
   1348   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
   1349   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   1350   return code;
   1351 }
   1352 
   1353 
   1354 Handle<Code> KeyedStoreStubCompiler::GetCode(PropertyType type,
   1355                                              Handle<String> name,
   1356                                              InlineCacheState state) {
   1357   Code::ExtraICState extra_state =
   1358       Code::ComputeExtraICState(grow_mode_, strict_mode_);
   1359   Code::Flags flags =
   1360       Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
   1361   Handle<Code> code = GetCodeWithFlags(flags, name);
   1362   PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
   1363   GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
   1364   return code;
   1365 }
   1366 
   1367 
   1368 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
   1369     MacroAssembler* masm) {
   1370   KeyedStoreIC::GenerateSlow(masm);
   1371 }
   1372 
   1373 
   1374 CallStubCompiler::CallStubCompiler(Isolate* isolate,
   1375                                    int argc,
   1376                                    Code::Kind kind,
   1377                                    Code::ExtraICState extra_state,
   1378                                    InlineCacheHolderFlag cache_holder)
   1379     : StubCompiler(isolate),
   1380       arguments_(argc),
   1381       kind_(kind),
   1382       extra_state_(extra_state),
   1383       cache_holder_(cache_holder) {
   1384 }
   1385 
   1386 
   1387 bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
   1388   if (function->shared()->HasBuiltinFunctionId()) {
   1389     BuiltinFunctionId id = function->shared()->builtin_function_id();
   1390 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
   1391     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
   1392 #undef CALL_GENERATOR_CASE
   1393   }
   1394 
   1395   CallOptimization optimization(function);
   1396   return optimization.is_simple_api_call();
   1397 }
   1398 
   1399 
   1400 Handle<Code> CallStubCompiler::CompileCustomCall(
   1401     Handle<Object> object,
   1402     Handle<JSObject> holder,
   1403     Handle<JSGlobalPropertyCell> cell,
   1404     Handle<JSFunction> function,
   1405     Handle<String> fname) {
   1406   ASSERT(HasCustomCallGenerator(function));
   1407 
   1408   if (function->shared()->HasBuiltinFunctionId()) {
   1409     BuiltinFunctionId id = function->shared()->builtin_function_id();
   1410 #define CALL_GENERATOR_CASE(name)                               \
   1411     if (id == k##name) {                                        \
   1412       return CallStubCompiler::Compile##name##Call(object,      \
   1413                                                    holder,      \
   1414                                                    cell,        \
   1415                                                    function,    \
   1416                                                    fname);      \
   1417     }
   1418     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
   1419 #undef CALL_GENERATOR_CASE
   1420   }
   1421   CallOptimization optimization(function);
   1422   ASSERT(optimization.is_simple_api_call());
   1423   return CompileFastApiCall(optimization,
   1424                             object,
   1425                             holder,
   1426                             cell,
   1427                             function,
   1428                             fname);
   1429 }
   1430 
   1431 
   1432 Handle<Code> CallStubCompiler::GetCode(PropertyType type, Handle<String> name) {
   1433   int argc = arguments_.immediate();
   1434   Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
   1435                                                     type,
   1436                                                     extra_state_,
   1437                                                     cache_holder_,
   1438                                                     argc);
   1439   return GetCodeWithFlags(flags, name);
   1440 }
   1441 
   1442 
   1443 Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
   1444   Handle<String> function_name;
   1445   if (function->shared()->name()->IsString()) {
   1446     function_name = Handle<String>(String::cast(function->shared()->name()));
   1447   }
   1448   return GetCode(CONSTANT_FUNCTION, function_name);
   1449 }
   1450 
   1451 
   1452 Handle<Code> ConstructStubCompiler::GetCode() {
   1453   Code::Flags flags = Code::ComputeFlags(Code::STUB);
   1454   Handle<Code> code = GetCodeWithFlags(flags, "ConstructStub");
   1455   PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, "ConstructStub"));
   1456   GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", *code));
   1457   return code;
   1458 }
   1459 
   1460 
   1461 CallOptimization::CallOptimization(LookupResult* lookup) {
   1462   if (lookup->IsFound() &&
   1463       lookup->IsCacheable() &&
   1464       lookup->type() == CONSTANT_FUNCTION) {
   1465     // We only optimize constant function calls.
   1466     Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
   1467   } else {
   1468     Initialize(Handle<JSFunction>::null());
   1469   }
   1470 }
   1471 
   1472 CallOptimization::CallOptimization(Handle<JSFunction> function) {
   1473   Initialize(function);
   1474 }
   1475 
   1476 
   1477 int CallOptimization::GetPrototypeDepthOfExpectedType(
   1478     Handle<JSObject> object,
   1479     Handle<JSObject> holder) const {
   1480   ASSERT(is_simple_api_call());
   1481   if (expected_receiver_type_.is_null()) return 0;
   1482   int depth = 0;
   1483   while (!object.is_identical_to(holder)) {
   1484     if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
   1485     object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
   1486     ++depth;
   1487   }
   1488   if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
   1489   return kInvalidProtoDepth;
   1490 }
   1491 
   1492 
   1493 void CallOptimization::Initialize(Handle<JSFunction> function) {
   1494   constant_function_ = Handle<JSFunction>::null();
   1495   is_simple_api_call_ = false;
   1496   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
   1497   api_call_info_ = Handle<CallHandlerInfo>::null();
   1498 
   1499   if (function.is_null() || !function->is_compiled()) return;
   1500 
   1501   constant_function_ = function;
   1502   AnalyzePossibleApiFunction(function);
   1503 }
   1504 
   1505 
   1506 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
   1507   if (!function->shared()->IsApiFunction()) return;
   1508   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
   1509 
   1510   // Require a C++ callback.
   1511   if (info->call_code()->IsUndefined()) return;
   1512   api_call_info_ =
   1513       Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
   1514 
   1515   // Accept signatures that either have no restrictions at all or
   1516   // only have restrictions on the receiver.
   1517   if (!info->signature()->IsUndefined()) {
   1518     Handle<SignatureInfo> signature =
   1519         Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
   1520     if (!signature->args()->IsUndefined()) return;
   1521     if (!signature->receiver()->IsUndefined()) {
   1522       expected_receiver_type_ =
   1523           Handle<FunctionTemplateInfo>(
   1524               FunctionTemplateInfo::cast(signature->receiver()));
   1525     }
   1526   }
   1527 
   1528   is_simple_api_call_ = true;
   1529 }
   1530 
   1531 
   1532 } }  // namespace v8::internal
   1533