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 "api.h"
     31 #include "arguments.h"
     32 #include "gdb-jit.h"
     33 #include "ic-inl.h"
     34 #include "stub-cache.h"
     35 #include "vm-state-inl.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 // -----------------------------------------------------------------------
     41 // StubCache implementation.
     42 
     43 
     44 StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
     45   ASSERT(isolate == Isolate::Current());
     46   memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
     47   memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
     48 }
     49 
     50 
     51 void StubCache::Initialize(bool create_heap_objects) {
     52   ASSERT(IsPowerOf2(kPrimaryTableSize));
     53   ASSERT(IsPowerOf2(kSecondaryTableSize));
     54   if (create_heap_objects) {
     55     HandleScope scope;
     56     Clear();
     57   }
     58 }
     59 
     60 
     61 Code* StubCache::Set(String* name, Map* map, Code* code) {
     62   // Get the flags from the code.
     63   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
     64 
     65   // Validate that the name does not move on scavenge, and that we
     66   // can use identity checks instead of string equality checks.
     67   ASSERT(!heap()->InNewSpace(name));
     68   ASSERT(name->IsSymbol());
     69 
     70   // The state bits are not important to the hash function because
     71   // the stub cache only contains monomorphic stubs. Make sure that
     72   // the bits are the least significant so they will be the ones
     73   // masked out.
     74   ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
     75   ASSERT(Code::kFlagsICStateShift == 0);
     76 
     77   // Make sure that the code type is not included in the hash.
     78   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
     79 
     80   // Compute the primary entry.
     81   int primary_offset = PrimaryOffset(name, flags, map);
     82   Entry* primary = entry(primary_, primary_offset);
     83   Code* hit = primary->value;
     84 
     85   // If the primary entry has useful data in it, we retire it to the
     86   // secondary cache before overwriting it.
     87   if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
     88     Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
     89     int secondary_offset =
     90         SecondaryOffset(primary->key, primary_flags, primary_offset);
     91     Entry* secondary = entry(secondary_, secondary_offset);
     92     *secondary = *primary;
     93   }
     94 
     95   // Update primary cache.
     96   primary->key = name;
     97   primary->value = code;
     98   return code;
     99 }
    100 
    101 
    102 MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
    103                                                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   String* cache_name = heap()->empty_string();
    112   if (receiver->IsGlobalObject()) cache_name = name;
    113   JSObject* last = receiver;
    114   while (last->GetPrototype() != heap()->null_value()) {
    115     last = 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   Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
    123   if (code->IsUndefined()) {
    124     LoadStubCompiler compiler;
    125     { MaybeObject* maybe_code =
    126           compiler.CompileLoadNonexistent(cache_name, receiver, last);
    127       if (!maybe_code->ToObject(&code)) return maybe_code;
    128     }
    129     PROFILE(isolate_,
    130             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
    131     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
    132     Object* result;
    133     { MaybeObject* maybe_result =
    134           receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
    135       if (!maybe_result->ToObject(&result)) return maybe_result;
    136     }
    137   }
    138   return code;
    139 }
    140 
    141 
    142 MaybeObject* StubCache::ComputeLoadField(String* name,
    143                                          JSObject* receiver,
    144                                          JSObject* holder,
    145                                          int field_index) {
    146   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    147   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
    148   Object* code = receiver->map()->FindInCodeCache(name, flags);
    149   if (code->IsUndefined()) {
    150     LoadStubCompiler compiler;
    151     { MaybeObject* maybe_code =
    152           compiler.CompileLoadField(receiver, holder, field_index, name);
    153       if (!maybe_code->ToObject(&code)) return maybe_code;
    154     }
    155     PROFILE(isolate_,
    156             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
    157     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
    158     Object* result;
    159     { MaybeObject* maybe_result =
    160           receiver->UpdateMapCodeCache(name, Code::cast(code));
    161       if (!maybe_result->ToObject(&result)) return maybe_result;
    162     }
    163   }
    164   return code;
    165 }
    166 
    167 
    168 MaybeObject* StubCache::ComputeLoadCallback(String* name,
    169                                             JSObject* receiver,
    170                                             JSObject* holder,
    171                                             AccessorInfo* callback) {
    172   ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
    173   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    174   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
    175   Object* code = receiver->map()->FindInCodeCache(name, flags);
    176   if (code->IsUndefined()) {
    177     LoadStubCompiler compiler;
    178     { MaybeObject* maybe_code =
    179           compiler.CompileLoadCallback(name, receiver, holder, callback);
    180       if (!maybe_code->ToObject(&code)) return maybe_code;
    181     }
    182     PROFILE(isolate_,
    183             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
    184     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
    185     Object* result;
    186     { MaybeObject* maybe_result =
    187           receiver->UpdateMapCodeCache(name, Code::cast(code));
    188       if (!maybe_result->ToObject(&result)) return maybe_result;
    189     }
    190   }
    191   return code;
    192 }
    193 
    194 
    195 MaybeObject* StubCache::ComputeLoadConstant(String* name,
    196                                             JSObject* receiver,
    197                                             JSObject* holder,
    198                                             Object* value) {
    199   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    200   Code::Flags flags =
    201       Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
    202   Object* code = receiver->map()->FindInCodeCache(name, flags);
    203   if (code->IsUndefined()) {
    204     LoadStubCompiler compiler;
    205     { MaybeObject* maybe_code =
    206           compiler.CompileLoadConstant(receiver, holder, value, name);
    207       if (!maybe_code->ToObject(&code)) return maybe_code;
    208     }
    209     PROFILE(isolate_,
    210             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
    211     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
    212     Object* result;
    213     { MaybeObject* maybe_result =
    214           receiver->UpdateMapCodeCache(name, Code::cast(code));
    215       if (!maybe_result->ToObject(&result)) return maybe_result;
    216     }
    217   }
    218   return code;
    219 }
    220 
    221 
    222 MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
    223                                                JSObject* receiver,
    224                                                JSObject* holder) {
    225   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    226   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
    227   Object* code = receiver->map()->FindInCodeCache(name, flags);
    228   if (code->IsUndefined()) {
    229     LoadStubCompiler compiler;
    230     { MaybeObject* maybe_code =
    231           compiler.CompileLoadInterceptor(receiver, holder, name);
    232       if (!maybe_code->ToObject(&code)) return maybe_code;
    233     }
    234     PROFILE(isolate_,
    235             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
    236     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
    237     Object* result;
    238     { MaybeObject* maybe_result =
    239           receiver->UpdateMapCodeCache(name, Code::cast(code));
    240       if (!maybe_result->ToObject(&result)) return maybe_result;
    241     }
    242   }
    243   return code;
    244 }
    245 
    246 
    247 MaybeObject* StubCache::ComputeLoadNormal() {
    248   return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
    249 }
    250 
    251 
    252 MaybeObject* StubCache::ComputeLoadGlobal(String* name,
    253                                           JSObject* receiver,
    254                                           GlobalObject* holder,
    255                                           JSGlobalPropertyCell* cell,
    256                                           bool is_dont_delete) {
    257   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    258   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
    259   Object* code = receiver->map()->FindInCodeCache(name, flags);
    260   if (code->IsUndefined()) {
    261     LoadStubCompiler compiler;
    262     { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
    263                                                            holder,
    264                                                            cell,
    265                                                            name,
    266                                                            is_dont_delete);
    267       if (!maybe_code->ToObject(&code)) return maybe_code;
    268     }
    269     PROFILE(isolate_,
    270             CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
    271     GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
    272     Object* result;
    273     { MaybeObject* maybe_result =
    274           receiver->UpdateMapCodeCache(name, Code::cast(code));
    275       if (!maybe_result->ToObject(&result)) return maybe_result;
    276     }
    277   }
    278   return code;
    279 }
    280 
    281 
    282 MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
    283                                               JSObject* receiver,
    284                                               JSObject* holder,
    285                                               int field_index) {
    286   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    287   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
    288   Object* code = receiver->map()->FindInCodeCache(name, flags);
    289   if (code->IsUndefined()) {
    290     KeyedLoadStubCompiler compiler;
    291     { MaybeObject* maybe_code =
    292           compiler.CompileLoadField(name, receiver, holder, field_index);
    293       if (!maybe_code->ToObject(&code)) return maybe_code;
    294     }
    295     PROFILE(isolate_,
    296             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    297     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    298     Object* result;
    299     { MaybeObject* maybe_result =
    300           receiver->UpdateMapCodeCache(name, Code::cast(code));
    301       if (!maybe_result->ToObject(&result)) return maybe_result;
    302     }
    303   }
    304   return code;
    305 }
    306 
    307 
    308 MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
    309                                                  JSObject* receiver,
    310                                                  JSObject* holder,
    311                                                  Object* value) {
    312   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    313   Code::Flags flags =
    314       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
    315   Object* code = receiver->map()->FindInCodeCache(name, flags);
    316   if (code->IsUndefined()) {
    317     KeyedLoadStubCompiler compiler;
    318     { MaybeObject* maybe_code =
    319           compiler.CompileLoadConstant(name, receiver, holder, value);
    320       if (!maybe_code->ToObject(&code)) return maybe_code;
    321     }
    322     PROFILE(isolate_,
    323             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    324     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    325     Object* result;
    326     { MaybeObject* maybe_result =
    327           receiver->UpdateMapCodeCache(name, Code::cast(code));
    328       if (!maybe_result->ToObject(&result)) return maybe_result;
    329     }
    330   }
    331   return code;
    332 }
    333 
    334 
    335 MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
    336                                                     JSObject* receiver,
    337                                                     JSObject* holder) {
    338   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    339   Code::Flags flags =
    340       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
    341   Object* code = receiver->map()->FindInCodeCache(name, flags);
    342   if (code->IsUndefined()) {
    343     KeyedLoadStubCompiler compiler;
    344     { MaybeObject* maybe_code =
    345           compiler.CompileLoadInterceptor(receiver, holder, name);
    346       if (!maybe_code->ToObject(&code)) return maybe_code;
    347     }
    348     PROFILE(isolate_,
    349             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    350     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    351     Object* result;
    352     { MaybeObject* maybe_result =
    353           receiver->UpdateMapCodeCache(name, Code::cast(code));
    354       if (!maybe_result->ToObject(&result)) return maybe_result;
    355     }
    356   }
    357   return code;
    358 }
    359 
    360 
    361 MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
    362                                                  JSObject* receiver,
    363                                                  JSObject* holder,
    364                                                  AccessorInfo* callback) {
    365   ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
    366   Code::Flags flags =
    367       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    368   Object* code = receiver->map()->FindInCodeCache(name, flags);
    369   if (code->IsUndefined()) {
    370     KeyedLoadStubCompiler compiler;
    371     { MaybeObject* maybe_code =
    372           compiler.CompileLoadCallback(name, receiver, holder, callback);
    373       if (!maybe_code->ToObject(&code)) return maybe_code;
    374     }
    375     PROFILE(isolate_,
    376             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    377     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    378     Object* result;
    379     { MaybeObject* maybe_result =
    380           receiver->UpdateMapCodeCache(name, Code::cast(code));
    381       if (!maybe_result->ToObject(&result)) return maybe_result;
    382     }
    383   }
    384   return code;
    385 }
    386 
    387 
    388 
    389 MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
    390                                                     JSArray* receiver) {
    391   Code::Flags flags =
    392       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    393   ASSERT(receiver->IsJSObject());
    394   Object* code = receiver->map()->FindInCodeCache(name, flags);
    395   if (code->IsUndefined()) {
    396     KeyedLoadStubCompiler compiler;
    397     { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
    398       if (!maybe_code->ToObject(&code)) return maybe_code;
    399     }
    400     PROFILE(isolate_,
    401             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    402     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    403     Object* result;
    404     { MaybeObject* maybe_result =
    405           receiver->UpdateMapCodeCache(name, Code::cast(code));
    406       if (!maybe_result->ToObject(&result)) return maybe_result;
    407     }
    408   }
    409   return code;
    410 }
    411 
    412 
    413 MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
    414                                                      String* receiver) {
    415   Code::Flags flags =
    416       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    417   Map* map = receiver->map();
    418   Object* code = map->FindInCodeCache(name, flags);
    419   if (code->IsUndefined()) {
    420     KeyedLoadStubCompiler compiler;
    421     { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
    422       if (!maybe_code->ToObject(&code)) return maybe_code;
    423     }
    424     PROFILE(isolate_,
    425             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    426     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    427     Object* result;
    428     { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
    429       if (!maybe_result->ToObject(&result)) return maybe_result;
    430     }
    431   }
    432   return code;
    433 }
    434 
    435 
    436 MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
    437     String* name,
    438     JSFunction* receiver) {
    439   Code::Flags flags =
    440       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
    441   Object* code = receiver->map()->FindInCodeCache(name, flags);
    442   if (code->IsUndefined()) {
    443     KeyedLoadStubCompiler compiler;
    444     { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
    445       if (!maybe_code->ToObject(&code)) return maybe_code;
    446     }
    447     PROFILE(isolate_,
    448             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
    449     GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
    450     Object* result;
    451     { MaybeObject* maybe_result =
    452           receiver->UpdateMapCodeCache(name, Code::cast(code));
    453       if (!maybe_result->ToObject(&result)) return maybe_result;
    454     }
    455   }
    456   return code;
    457 }
    458 
    459 
    460 MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
    461   // Using NORMAL as the PropertyType for array element loads is a misuse. The
    462   // generated stub always accesses fast elements, not slow-mode fields, but
    463   // some property type is required for the stub lookup. Note that overloading
    464   // the NORMAL PropertyType is only safe as long as no stubs are generated for
    465   // other keyed field loads. This is guaranteed to be the case since all field
    466   // keyed loads that are not array elements go through a generic builtin stub.
    467   Code::Flags flags =
    468       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
    469   String* name = heap()->KeyedLoadSpecialized_symbol();
    470   Object* code = receiver->map()->FindInCodeCache(name, flags);
    471   if (code->IsUndefined()) {
    472     KeyedLoadStubCompiler compiler;
    473     { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
    474       if (!maybe_code->ToObject(&code)) return maybe_code;
    475     }
    476     PROFILE(isolate_,
    477             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
    478     Object* result;
    479     { MaybeObject* maybe_result =
    480           receiver->UpdateMapCodeCache(name, Code::cast(code));
    481       if (!maybe_result->ToObject(&result)) return maybe_result;
    482     }
    483   }
    484   return code;
    485 }
    486 
    487 
    488 MaybeObject* StubCache::ComputeStoreField(String* name,
    489                                           JSObject* receiver,
    490                                           int field_index,
    491                                           Map* transition,
    492                                           StrictModeFlag strict_mode) {
    493   PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
    494   Code::Flags flags = Code::ComputeMonomorphicFlags(
    495       Code::STORE_IC, type, strict_mode);
    496   Object* code = receiver->map()->FindInCodeCache(name, flags);
    497   if (code->IsUndefined()) {
    498     StoreStubCompiler compiler(strict_mode);
    499     { MaybeObject* maybe_code =
    500           compiler.CompileStoreField(receiver, field_index, transition, name);
    501       if (!maybe_code->ToObject(&code)) return maybe_code;
    502     }
    503     PROFILE(isolate_,
    504             CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
    505     GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
    506     Object* result;
    507     { MaybeObject* maybe_result =
    508           receiver->UpdateMapCodeCache(name, Code::cast(code));
    509       if (!maybe_result->ToObject(&result)) return maybe_result;
    510     }
    511   }
    512   return code;
    513 }
    514 
    515 
    516 MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
    517     JSObject* receiver,
    518     StrictModeFlag strict_mode) {
    519   Code::Flags flags =
    520       Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
    521   String* name = heap()->KeyedStoreSpecialized_symbol();
    522   Object* code = receiver->map()->FindInCodeCache(name, flags);
    523   if (code->IsUndefined()) {
    524     KeyedStoreStubCompiler compiler(strict_mode);
    525     { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
    526       if (!maybe_code->ToObject(&code)) return maybe_code;
    527     }
    528     PROFILE(isolate_,
    529             CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
    530     Object* result;
    531     { MaybeObject* maybe_result =
    532           receiver->UpdateMapCodeCache(name, Code::cast(code));
    533       if (!maybe_result->ToObject(&result)) return maybe_result;
    534     }
    535   }
    536   return code;
    537 }
    538 
    539 
    540 namespace {
    541 
    542 ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
    543   switch (kind) {
    544     case JSObject::EXTERNAL_BYTE_ELEMENTS:
    545       return kExternalByteArray;
    546     case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
    547       return kExternalUnsignedByteArray;
    548     case JSObject::EXTERNAL_SHORT_ELEMENTS:
    549       return kExternalShortArray;
    550     case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
    551       return kExternalUnsignedShortArray;
    552     case JSObject::EXTERNAL_INT_ELEMENTS:
    553       return kExternalIntArray;
    554     case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
    555       return kExternalUnsignedIntArray;
    556     case JSObject::EXTERNAL_FLOAT_ELEMENTS:
    557       return kExternalFloatArray;
    558     case JSObject::EXTERNAL_PIXEL_ELEMENTS:
    559       return kExternalPixelArray;
    560     default:
    561       UNREACHABLE();
    562       return static_cast<ExternalArrayType>(0);
    563   }
    564 }
    565 
    566 String* ExternalArrayTypeToStubName(Heap* heap,
    567                                     ExternalArrayType array_type,
    568                                     bool is_store) {
    569   if (is_store) {
    570     switch (array_type) {
    571       case kExternalByteArray:
    572         return heap->KeyedStoreExternalByteArray_symbol();
    573       case kExternalUnsignedByteArray:
    574         return heap->KeyedStoreExternalUnsignedByteArray_symbol();
    575       case kExternalShortArray:
    576         return heap->KeyedStoreExternalShortArray_symbol();
    577       case kExternalUnsignedShortArray:
    578         return heap->KeyedStoreExternalUnsignedShortArray_symbol();
    579       case kExternalIntArray:
    580         return heap->KeyedStoreExternalIntArray_symbol();
    581       case kExternalUnsignedIntArray:
    582         return heap->KeyedStoreExternalUnsignedIntArray_symbol();
    583       case kExternalFloatArray:
    584         return heap->KeyedStoreExternalFloatArray_symbol();
    585       case kExternalPixelArray:
    586         return heap->KeyedStoreExternalPixelArray_symbol();
    587       default:
    588         UNREACHABLE();
    589         return NULL;
    590     }
    591   } else {
    592     switch (array_type) {
    593       case kExternalByteArray:
    594         return heap->KeyedLoadExternalByteArray_symbol();
    595       case kExternalUnsignedByteArray:
    596         return heap->KeyedLoadExternalUnsignedByteArray_symbol();
    597       case kExternalShortArray:
    598         return heap->KeyedLoadExternalShortArray_symbol();
    599       case kExternalUnsignedShortArray:
    600         return heap->KeyedLoadExternalUnsignedShortArray_symbol();
    601       case kExternalIntArray:
    602         return heap->KeyedLoadExternalIntArray_symbol();
    603       case kExternalUnsignedIntArray:
    604         return heap->KeyedLoadExternalUnsignedIntArray_symbol();
    605       case kExternalFloatArray:
    606         return heap->KeyedLoadExternalFloatArray_symbol();
    607       case kExternalPixelArray:
    608         return heap->KeyedLoadExternalPixelArray_symbol();
    609       default:
    610         UNREACHABLE();
    611         return NULL;
    612     }
    613   }
    614 }
    615 
    616 }  // anonymous namespace
    617 
    618 
    619 MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
    620     JSObject* receiver,
    621     bool is_store,
    622     StrictModeFlag strict_mode) {
    623   Code::Flags flags =
    624       Code::ComputeMonomorphicFlags(
    625           is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
    626                      Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
    627           NORMAL,
    628           strict_mode);
    629   ExternalArrayType array_type =
    630       ElementsKindToExternalArrayType(receiver->GetElementsKind());
    631   String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
    632   Object* code = receiver->map()->FindInCodeCache(name, flags);
    633   if (code->IsUndefined()) {
    634     ExternalArrayStubCompiler compiler;
    635     { MaybeObject* maybe_code =
    636           is_store ?
    637               compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
    638               compiler.CompileKeyedLoadStub(receiver, array_type, flags);
    639       if (!maybe_code->ToObject(&code)) return maybe_code;
    640     }
    641     Code::cast(code)->set_external_array_type(array_type);
    642     if (is_store) {
    643       PROFILE(isolate_,
    644           CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
    645                           Code::cast(code), 0));
    646     } else {
    647       PROFILE(isolate_,
    648           CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
    649                           Code::cast(code), 0));
    650     }
    651     Object* result;
    652     { MaybeObject* maybe_result =
    653           receiver->UpdateMapCodeCache(name, Code::cast(code));
    654       if (!maybe_result->ToObject(&result)) return maybe_result;
    655     }
    656   }
    657   return code;
    658 }
    659 
    660 
    661 MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
    662   return isolate_->builtins()->builtin((strict_mode == kStrictMode)
    663                             ? Builtins::kStoreIC_Normal_Strict
    664                             : Builtins::kStoreIC_Normal);
    665 }
    666 
    667 
    668 MaybeObject* StubCache::ComputeStoreGlobal(String* name,
    669                                            GlobalObject* receiver,
    670                                            JSGlobalPropertyCell* cell,
    671                                            StrictModeFlag strict_mode) {
    672   Code::Flags flags = Code::ComputeMonomorphicFlags(
    673       Code::STORE_IC, NORMAL, strict_mode);
    674   Object* code = receiver->map()->FindInCodeCache(name, flags);
    675   if (code->IsUndefined()) {
    676     StoreStubCompiler compiler(strict_mode);
    677     { MaybeObject* maybe_code =
    678           compiler.CompileStoreGlobal(receiver, cell, name);
    679       if (!maybe_code->ToObject(&code)) return maybe_code;
    680     }
    681     PROFILE(isolate_,
    682             CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
    683     GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
    684     Object* result;
    685     { MaybeObject* maybe_result =
    686           receiver->UpdateMapCodeCache(name, Code::cast(code));
    687       if (!maybe_result->ToObject(&result)) return maybe_result;
    688     }
    689   }
    690   return code;
    691 }
    692 
    693 
    694 MaybeObject* StubCache::ComputeStoreCallback(
    695     String* name,
    696     JSObject* receiver,
    697     AccessorInfo* callback,
    698     StrictModeFlag strict_mode) {
    699   ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
    700   Code::Flags flags = Code::ComputeMonomorphicFlags(
    701       Code::STORE_IC, CALLBACKS, strict_mode);
    702   Object* code = receiver->map()->FindInCodeCache(name, flags);
    703   if (code->IsUndefined()) {
    704     StoreStubCompiler compiler(strict_mode);
    705     { MaybeObject* maybe_code =
    706           compiler.CompileStoreCallback(receiver, callback, name);
    707       if (!maybe_code->ToObject(&code)) return maybe_code;
    708     }
    709     PROFILE(isolate_,
    710             CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
    711     GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
    712     Object* result;
    713     { MaybeObject* maybe_result =
    714           receiver->UpdateMapCodeCache(name, Code::cast(code));
    715       if (!maybe_result->ToObject(&result)) return maybe_result;
    716     }
    717   }
    718   return code;
    719 }
    720 
    721 
    722 MaybeObject* StubCache::ComputeStoreInterceptor(
    723     String* name,
    724     JSObject* receiver,
    725     StrictModeFlag strict_mode) {
    726   Code::Flags flags = Code::ComputeMonomorphicFlags(
    727       Code::STORE_IC, INTERCEPTOR, strict_mode);
    728   Object* code = receiver->map()->FindInCodeCache(name, flags);
    729   if (code->IsUndefined()) {
    730     StoreStubCompiler compiler(strict_mode);
    731     { MaybeObject* maybe_code =
    732           compiler.CompileStoreInterceptor(receiver, name);
    733       if (!maybe_code->ToObject(&code)) return maybe_code;
    734     }
    735     PROFILE(isolate_,
    736             CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
    737     GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
    738     Object* result;
    739     { MaybeObject* maybe_result =
    740           receiver->UpdateMapCodeCache(name, Code::cast(code));
    741       if (!maybe_result->ToObject(&result)) return maybe_result;
    742     }
    743   }
    744   return code;
    745 }
    746 
    747 
    748 MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
    749                                                JSObject* receiver,
    750                                                int field_index,
    751                                                Map* transition,
    752                                                StrictModeFlag strict_mode) {
    753   PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
    754   Code::Flags flags = Code::ComputeMonomorphicFlags(
    755       Code::KEYED_STORE_IC, type, strict_mode);
    756   Object* code = receiver->map()->FindInCodeCache(name, flags);
    757   if (code->IsUndefined()) {
    758     KeyedStoreStubCompiler compiler(strict_mode);
    759     { MaybeObject* maybe_code =
    760           compiler.CompileStoreField(receiver, field_index, transition, name);
    761       if (!maybe_code->ToObject(&code)) return maybe_code;
    762     }
    763     PROFILE(isolate(),
    764             CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
    765                             Code::cast(code), name));
    766     GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
    767     Object* result;
    768     { MaybeObject* maybe_result =
    769           receiver->UpdateMapCodeCache(name, Code::cast(code));
    770       if (!maybe_result->ToObject(&result)) return maybe_result;
    771     }
    772   }
    773   return code;
    774 }
    775 
    776 #define CALL_LOGGER_TAG(kind, type) \
    777     (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
    778 
    779 MaybeObject* StubCache::ComputeCallConstant(int argc,
    780                                             InLoopFlag in_loop,
    781                                             Code::Kind kind,
    782                                             Code::ExtraICState extra_ic_state,
    783                                             String* name,
    784                                             Object* object,
    785                                             JSObject* holder,
    786                                             JSFunction* function) {
    787   // Compute the check type and the map.
    788   InlineCacheHolderFlag cache_holder =
    789       IC::GetCodeCacheForObject(object, holder);
    790   JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
    791 
    792   // Compute check type based on receiver/holder.
    793   CheckType check = RECEIVER_MAP_CHECK;
    794   if (object->IsString()) {
    795     check = STRING_CHECK;
    796   } else if (object->IsNumber()) {
    797     check = NUMBER_CHECK;
    798   } else if (object->IsBoolean()) {
    799     check = BOOLEAN_CHECK;
    800   }
    801 
    802   Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
    803                                                     CONSTANT_FUNCTION,
    804                                                     extra_ic_state,
    805                                                     cache_holder,
    806                                                     in_loop,
    807                                                     argc);
    808   Object* code = map_holder->map()->FindInCodeCache(name, flags);
    809   if (code->IsUndefined()) {
    810     // If the function hasn't been compiled yet, we cannot do it now
    811     // because it may cause GC. To avoid this issue, we return an
    812     // internal error which will make sure we do not update any
    813     // caches.
    814     if (!function->is_compiled()) return Failure::InternalError();
    815     // Compile the stub - only create stubs for fully compiled functions.
    816     CallStubCompiler compiler(
    817         argc, in_loop, kind, extra_ic_state, cache_holder);
    818     { MaybeObject* maybe_code =
    819           compiler.CompileCallConstant(object, holder, function, name, check);
    820       if (!maybe_code->ToObject(&code)) return maybe_code;
    821     }
    822     Code::cast(code)->set_check_type(check);
    823     ASSERT_EQ(flags, Code::cast(code)->flags());
    824     PROFILE(isolate_,
    825             CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
    826                             Code::cast(code), name));
    827     GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
    828     Object* result;
    829     { MaybeObject* maybe_result =
    830           map_holder->UpdateMapCodeCache(name, Code::cast(code));
    831       if (!maybe_result->ToObject(&result)) return maybe_result;
    832     }
    833   }
    834   return code;
    835 }
    836 
    837 
    838 MaybeObject* StubCache::ComputeCallField(int argc,
    839                                          InLoopFlag in_loop,
    840                                          Code::Kind kind,
    841                                          String* name,
    842                                          Object* object,
    843                                          JSObject* holder,
    844                                          int index) {
    845   // Compute the check type and the map.
    846   InlineCacheHolderFlag cache_holder =
    847       IC::GetCodeCacheForObject(object, holder);
    848   JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
    849 
    850   // TODO(1233596): We cannot do receiver map check for non-JS objects
    851   // because they may be represented as immediates without a
    852   // map. Instead, we check against the map in the holder.
    853   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    854     object = holder;
    855   }
    856 
    857   Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
    858                                                     FIELD,
    859                                                     Code::kNoExtraICState,
    860                                                     cache_holder,
    861                                                     in_loop,
    862                                                     argc);
    863   Object* code = map_holder->map()->FindInCodeCache(name, flags);
    864   if (code->IsUndefined()) {
    865     CallStubCompiler compiler(
    866         argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
    867     { MaybeObject* maybe_code =
    868           compiler.CompileCallField(JSObject::cast(object),
    869                                     holder,
    870                                     index,
    871                                     name);
    872       if (!maybe_code->ToObject(&code)) return maybe_code;
    873     }
    874     ASSERT_EQ(flags, Code::cast(code)->flags());
    875     PROFILE(isolate_,
    876             CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
    877                             Code::cast(code), name));
    878     GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
    879     Object* result;
    880     { MaybeObject* maybe_result =
    881           map_holder->UpdateMapCodeCache(name, Code::cast(code));
    882       if (!maybe_result->ToObject(&result)) return maybe_result;
    883     }
    884   }
    885   return code;
    886 }
    887 
    888 
    889 MaybeObject* StubCache::ComputeCallInterceptor(int argc,
    890                                                Code::Kind kind,
    891                                                String* name,
    892                                                Object* object,
    893                                                JSObject* holder) {
    894   // Compute the check type and the map.
    895   InlineCacheHolderFlag cache_holder =
    896       IC::GetCodeCacheForObject(object, holder);
    897   JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
    898 
    899   // TODO(1233596): We cannot do receiver map check for non-JS objects
    900   // because they may be represented as immediates without a
    901   // map. Instead, we check against the map in the holder.
    902   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    903     object = holder;
    904   }
    905 
    906   Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
    907                                                     INTERCEPTOR,
    908                                                     Code::kNoExtraICState,
    909                                                     cache_holder,
    910                                                     NOT_IN_LOOP,
    911                                                     argc);
    912   Object* code = map_holder->map()->FindInCodeCache(name, flags);
    913   if (code->IsUndefined()) {
    914     CallStubCompiler compiler(
    915         argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
    916     { MaybeObject* maybe_code =
    917           compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
    918       if (!maybe_code->ToObject(&code)) return maybe_code;
    919     }
    920     ASSERT_EQ(flags, Code::cast(code)->flags());
    921     PROFILE(isolate(),
    922             CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
    923                             Code::cast(code), name));
    924     GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
    925     Object* result;
    926     { MaybeObject* maybe_result =
    927           map_holder->UpdateMapCodeCache(name, Code::cast(code));
    928       if (!maybe_result->ToObject(&result)) return maybe_result;
    929     }
    930   }
    931   return code;
    932 }
    933 
    934 
    935 MaybeObject* StubCache::ComputeCallNormal(int argc,
    936                                           InLoopFlag in_loop,
    937                                           Code::Kind kind,
    938                                           String* name,
    939                                           JSObject* receiver) {
    940   Object* code;
    941   { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
    942     if (!maybe_code->ToObject(&code)) return maybe_code;
    943   }
    944   return code;
    945 }
    946 
    947 
    948 MaybeObject* StubCache::ComputeCallGlobal(int argc,
    949                                           InLoopFlag in_loop,
    950                                           Code::Kind kind,
    951                                           String* name,
    952                                           JSObject* receiver,
    953                                           GlobalObject* holder,
    954                                           JSGlobalPropertyCell* cell,
    955                                           JSFunction* function) {
    956   InlineCacheHolderFlag cache_holder =
    957       IC::GetCodeCacheForObject(receiver, holder);
    958   JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
    959   Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
    960                                                     NORMAL,
    961                                                     Code::kNoExtraICState,
    962                                                     cache_holder,
    963                                                     in_loop,
    964                                                     argc);
    965   Object* code = map_holder->map()->FindInCodeCache(name, flags);
    966   if (code->IsUndefined()) {
    967     // If the function hasn't been compiled yet, we cannot do it now
    968     // because it may cause GC. To avoid this issue, we return an
    969     // internal error which will make sure we do not update any
    970     // caches.
    971     if (!function->is_compiled()) return Failure::InternalError();
    972     CallStubCompiler compiler(
    973         argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
    974     { MaybeObject* maybe_code =
    975           compiler.CompileCallGlobal(receiver, holder, cell, function, name);
    976       if (!maybe_code->ToObject(&code)) return maybe_code;
    977     }
    978     ASSERT_EQ(flags, Code::cast(code)->flags());
    979     PROFILE(isolate(),
    980             CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
    981                             Code::cast(code), name));
    982     GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
    983     Object* result;
    984     { MaybeObject* maybe_result =
    985           map_holder->UpdateMapCodeCache(name, Code::cast(code));
    986       if (!maybe_result->ToObject(&result)) return maybe_result;
    987     }
    988   }
    989   return code;
    990 }
    991 
    992 
    993 static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
    994   // Use raw_unchecked... so we don't get assert failures during GC.
    995   NumberDictionary* dictionary =
    996       isolate->heap()->raw_unchecked_non_monomorphic_cache();
    997   int entry = dictionary->FindEntry(isolate, flags);
    998   if (entry != -1) return dictionary->ValueAt(entry);
    999   return isolate->heap()->raw_unchecked_undefined_value();
   1000 }
   1001 
   1002 
   1003 MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
   1004                                                Code::Flags flags) {
   1005   Heap* heap = isolate->heap();
   1006   Object* probe = GetProbeValue(isolate, flags);
   1007   if (probe != heap->undefined_value()) return probe;
   1008   // Seed the cache with an undefined value to make sure that any
   1009   // generated code object can always be inserted into the cache
   1010   // without causing  allocation failures.
   1011   Object* result;
   1012   { MaybeObject* maybe_result =
   1013         heap->non_monomorphic_cache()->AtNumberPut(flags,
   1014                                                    heap->undefined_value());
   1015     if (!maybe_result->ToObject(&result)) return maybe_result;
   1016   }
   1017   heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
   1018   return probe;
   1019 }
   1020 
   1021 
   1022 static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
   1023   Object* code;
   1024   if (maybe_code->ToObject(&code)) {
   1025     if (code->IsCode()) {
   1026       Heap* heap = isolate->heap();
   1027       int entry = heap->non_monomorphic_cache()->FindEntry(
   1028           Code::cast(code)->flags());
   1029       // The entry must be present see comment in ProbeCache.
   1030       ASSERT(entry != -1);
   1031       ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
   1032              heap->undefined_value());
   1033       heap->non_monomorphic_cache()->ValueAtPut(entry, code);
   1034       CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
   1035     }
   1036   }
   1037   return maybe_code;
   1038 }
   1039 
   1040 
   1041 Code* StubCache::FindCallInitialize(int argc,
   1042                                     InLoopFlag in_loop,
   1043                                     Code::Kind kind) {
   1044   Code::Flags flags = Code::ComputeFlags(kind,
   1045                                          in_loop,
   1046                                          UNINITIALIZED,
   1047                                          Code::kNoExtraICState,
   1048                                          NORMAL,
   1049                                          argc);
   1050   Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
   1051   ASSERT(result != heap()->undefined_value());
   1052   // This might be called during the marking phase of the collector
   1053   // hence the unchecked cast.
   1054   return reinterpret_cast<Code*>(result);
   1055 }
   1056 
   1057 
   1058 MaybeObject* StubCache::ComputeCallInitialize(int argc,
   1059                                               InLoopFlag in_loop,
   1060                                               Code::Kind kind) {
   1061   Code::Flags flags = Code::ComputeFlags(kind,
   1062                                          in_loop,
   1063                                          UNINITIALIZED,
   1064                                          Code::kNoExtraICState,
   1065                                          NORMAL,
   1066                                          argc);
   1067   Object* probe;
   1068   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1069     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1070   }
   1071   if (!probe->IsUndefined()) return probe;
   1072   StubCompiler compiler;
   1073   return FillCache(isolate_, compiler.CompileCallInitialize(flags));
   1074 }
   1075 
   1076 
   1077 Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
   1078   if (in_loop == IN_LOOP) {
   1079     // Force the creation of the corresponding stub outside loops,
   1080     // because it may be used when clearing the ICs later - it is
   1081     // possible for a series of IC transitions to lose the in-loop
   1082     // information, and the IC clearing code can't generate a stub
   1083     // that it needs so we need to ensure it is generated already.
   1084     ComputeCallInitialize(argc, NOT_IN_LOOP);
   1085   }
   1086   CALL_HEAP_FUNCTION(isolate_,
   1087                      ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
   1088 }
   1089 
   1090 
   1091 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
   1092                                                    InLoopFlag in_loop) {
   1093   if (in_loop == IN_LOOP) {
   1094     // Force the creation of the corresponding stub outside loops,
   1095     // because it may be used when clearing the ICs later - it is
   1096     // possible for a series of IC transitions to lose the in-loop
   1097     // information, and the IC clearing code can't generate a stub
   1098     // that it needs so we need to ensure it is generated already.
   1099     ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
   1100   }
   1101   CALL_HEAP_FUNCTION(
   1102       isolate_,
   1103       ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
   1104 }
   1105 
   1106 
   1107 MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
   1108                                                   InLoopFlag in_loop,
   1109                                                   Code::Kind kind) {
   1110   Code::Flags flags = Code::ComputeFlags(kind,
   1111                                          in_loop,
   1112                                          PREMONOMORPHIC,
   1113                                          Code::kNoExtraICState,
   1114                                          NORMAL,
   1115                                          argc);
   1116   Object* probe;
   1117   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1118     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1119   }
   1120   if (!probe->IsUndefined()) return probe;
   1121   StubCompiler compiler;
   1122   return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
   1123 }
   1124 
   1125 
   1126 MaybeObject* StubCache::ComputeCallNormal(int argc,
   1127                                           InLoopFlag in_loop,
   1128                                           Code::Kind kind) {
   1129   Code::Flags flags = Code::ComputeFlags(kind,
   1130                                          in_loop,
   1131                                          MONOMORPHIC,
   1132                                          Code::kNoExtraICState,
   1133                                          NORMAL,
   1134                                          argc);
   1135   Object* probe;
   1136   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1137     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1138   }
   1139   if (!probe->IsUndefined()) return probe;
   1140   StubCompiler compiler;
   1141   return FillCache(isolate_, compiler.CompileCallNormal(flags));
   1142 }
   1143 
   1144 
   1145 MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
   1146                                                InLoopFlag in_loop,
   1147                                                Code::Kind kind) {
   1148   Code::Flags flags = Code::ComputeFlags(kind,
   1149                                          in_loop,
   1150                                          MEGAMORPHIC,
   1151                                          Code::kNoExtraICState,
   1152                                          NORMAL,
   1153                                          argc);
   1154   Object* probe;
   1155   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1156     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1157   }
   1158   if (!probe->IsUndefined()) return probe;
   1159   StubCompiler compiler;
   1160   return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
   1161 }
   1162 
   1163 
   1164 MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
   1165   // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
   1166   // and monomorphic stubs are not mixed up together in the stub cache.
   1167   Code::Flags flags = Code::ComputeFlags(kind,
   1168                                          NOT_IN_LOOP,
   1169                                          MONOMORPHIC_PROTOTYPE_FAILURE,
   1170                                          Code::kNoExtraICState,
   1171                                          NORMAL,
   1172                                          argc,
   1173                                          OWN_MAP);
   1174   Object* probe;
   1175   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1176     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1177   }
   1178   if (!probe->IsUndefined()) return probe;
   1179   StubCompiler compiler;
   1180   return FillCache(isolate_, compiler.CompileCallMiss(flags));
   1181 }
   1182 
   1183 
   1184 #ifdef ENABLE_DEBUGGER_SUPPORT
   1185 MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
   1186   Code::Flags flags = Code::ComputeFlags(kind,
   1187                                          NOT_IN_LOOP,
   1188                                          DEBUG_BREAK,
   1189                                          Code::kNoExtraICState,
   1190                                          NORMAL,
   1191                                          argc);
   1192   Object* probe;
   1193   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1194     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1195   }
   1196   if (!probe->IsUndefined()) return probe;
   1197   StubCompiler compiler;
   1198   return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
   1199 }
   1200 
   1201 
   1202 MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
   1203                                                       Code::Kind kind) {
   1204   Code::Flags flags = Code::ComputeFlags(kind,
   1205                                          NOT_IN_LOOP,
   1206                                          DEBUG_PREPARE_STEP_IN,
   1207                                          Code::kNoExtraICState,
   1208                                          NORMAL,
   1209                                          argc);
   1210   Object* probe;
   1211   { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
   1212     if (!maybe_probe->ToObject(&probe)) return maybe_probe;
   1213   }
   1214   if (!probe->IsUndefined()) return probe;
   1215   StubCompiler compiler;
   1216   return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
   1217 }
   1218 #endif
   1219 
   1220 
   1221 void StubCache::Clear() {
   1222   for (int i = 0; i < kPrimaryTableSize; i++) {
   1223     primary_[i].key = heap()->empty_string();
   1224     primary_[i].value = isolate_->builtins()->builtin(
   1225         Builtins::kIllegal);
   1226   }
   1227   for (int j = 0; j < kSecondaryTableSize; j++) {
   1228     secondary_[j].key = heap()->empty_string();
   1229     secondary_[j].value = isolate_->builtins()->builtin(
   1230         Builtins::kIllegal);
   1231   }
   1232 }
   1233 
   1234 
   1235 void StubCache::CollectMatchingMaps(ZoneMapList* types,
   1236                                     String* name,
   1237                                     Code::Flags flags) {
   1238   for (int i = 0; i < kPrimaryTableSize; i++) {
   1239     if (primary_[i].key == name) {
   1240       Map* map = primary_[i].value->FindFirstMap();
   1241       // Map can be NULL, if the stub is constant function call
   1242       // with a primitive receiver.
   1243       if (map == NULL) continue;
   1244 
   1245       int offset = PrimaryOffset(name, flags, map);
   1246       if (entry(primary_, offset) == &primary_[i]) {
   1247         types->Add(Handle<Map>(map));
   1248       }
   1249     }
   1250   }
   1251 
   1252   for (int i = 0; i < kSecondaryTableSize; i++) {
   1253     if (secondary_[i].key == name) {
   1254       Map* map = secondary_[i].value->FindFirstMap();
   1255       // Map can be NULL, if the stub is constant function call
   1256       // with a primitive receiver.
   1257       if (map == NULL) continue;
   1258 
   1259       // Lookup in primary table and skip duplicates.
   1260       int primary_offset = PrimaryOffset(name, flags, map);
   1261       Entry* primary_entry = entry(primary_, primary_offset);
   1262       if (primary_entry->key == name) {
   1263         Map* primary_map = primary_entry->value->FindFirstMap();
   1264         if (map == primary_map) continue;
   1265       }
   1266 
   1267       // Lookup in secondary table and add matches.
   1268       int offset = SecondaryOffset(name, flags, primary_offset);
   1269       if (entry(secondary_, offset) == &secondary_[i]) {
   1270         types->Add(Handle<Map>(map));
   1271       }
   1272     }
   1273   }
   1274 }
   1275 
   1276 
   1277 // ------------------------------------------------------------------------
   1278 // StubCompiler implementation.
   1279 
   1280 
   1281 RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
   1282   ASSERT(args[0]->IsJSObject());
   1283   ASSERT(args[1]->IsJSObject());
   1284   AccessorInfo* callback = AccessorInfo::cast(args[3]);
   1285   Address getter_address = v8::ToCData<Address>(callback->getter());
   1286   v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
   1287   ASSERT(fun != NULL);
   1288   v8::AccessorInfo info(&args[0]);
   1289   HandleScope scope(isolate);
   1290   v8::Handle<v8::Value> result;
   1291   {
   1292     // Leaving JavaScript.
   1293     VMState state(isolate, EXTERNAL);
   1294     ExternalCallbackScope call_scope(isolate, getter_address);
   1295     result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
   1296   }
   1297   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1298   if (result.IsEmpty()) return HEAP->undefined_value();
   1299   return *v8::Utils::OpenHandle(*result);
   1300 }
   1301 
   1302 
   1303 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
   1304   JSObject* recv = JSObject::cast(args[0]);
   1305   AccessorInfo* callback = AccessorInfo::cast(args[1]);
   1306   Address setter_address = v8::ToCData<Address>(callback->setter());
   1307   v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
   1308   ASSERT(fun != NULL);
   1309   Handle<String> name = args.at<String>(2);
   1310   Handle<Object> value = args.at<Object>(3);
   1311   HandleScope scope(isolate);
   1312   LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
   1313   CustomArguments custom_args(isolate, callback->data(), recv, recv);
   1314   v8::AccessorInfo info(custom_args.end());
   1315   {
   1316     // Leaving JavaScript.
   1317     VMState state(isolate, EXTERNAL);
   1318     ExternalCallbackScope call_scope(isolate, setter_address);
   1319     fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
   1320   }
   1321   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1322   return *value;
   1323 }
   1324 
   1325 
   1326 static const int kAccessorInfoOffsetInInterceptorArgs = 2;
   1327 
   1328 
   1329 /**
   1330  * Attempts to load a property with an interceptor (which must be present),
   1331  * but doesn't search the prototype chain.
   1332  *
   1333  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
   1334  * provide any value for the given name.
   1335  */
   1336 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
   1337   Handle<String> name_handle = args.at<String>(0);
   1338   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
   1339   ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
   1340   ASSERT(args[2]->IsJSObject());  // Receiver.
   1341   ASSERT(args[3]->IsJSObject());  // Holder.
   1342   ASSERT(args.length() == 5);  // Last arg is data object.
   1343 
   1344   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   1345   v8::NamedPropertyGetter getter =
   1346       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   1347   ASSERT(getter != NULL);
   1348 
   1349   {
   1350     // Use the interceptor getter.
   1351     v8::AccessorInfo info(args.arguments() -
   1352                           kAccessorInfoOffsetInInterceptorArgs);
   1353     HandleScope scope(isolate);
   1354     v8::Handle<v8::Value> r;
   1355     {
   1356       // Leaving JavaScript.
   1357       VMState state(isolate, EXTERNAL);
   1358       r = getter(v8::Utils::ToLocal(name_handle), info);
   1359     }
   1360     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1361     if (!r.IsEmpty()) {
   1362       return *v8::Utils::OpenHandle(*r);
   1363     }
   1364   }
   1365 
   1366   return isolate->heap()->no_interceptor_result_sentinel();
   1367 }
   1368 
   1369 
   1370 static MaybeObject* ThrowReferenceError(String* name) {
   1371   // If the load is non-contextual, just return the undefined result.
   1372   // Note that both keyed and non-keyed loads may end up here, so we
   1373   // can't use either LoadIC or KeyedLoadIC constructors.
   1374   IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
   1375   ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
   1376   if (!ic.SlowIsContextual()) return HEAP->undefined_value();
   1377 
   1378   // Throw a reference error.
   1379   HandleScope scope;
   1380   Handle<String> name_handle(name);
   1381   Handle<Object> error =
   1382       FACTORY->NewReferenceError("not_defined",
   1383                                   HandleVector(&name_handle, 1));
   1384   return Isolate::Current()->Throw(*error);
   1385 }
   1386 
   1387 
   1388 static MaybeObject* LoadWithInterceptor(Arguments* args,
   1389                                         PropertyAttributes* attrs) {
   1390   Handle<String> name_handle = args->at<String>(0);
   1391   Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
   1392   ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
   1393   Handle<JSObject> receiver_handle = args->at<JSObject>(2);
   1394   Handle<JSObject> holder_handle = args->at<JSObject>(3);
   1395   ASSERT(args->length() == 5);  // Last arg is data object.
   1396 
   1397   Isolate* isolate = receiver_handle->GetIsolate();
   1398 
   1399   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
   1400   v8::NamedPropertyGetter getter =
   1401       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   1402   ASSERT(getter != NULL);
   1403 
   1404   {
   1405     // Use the interceptor getter.
   1406     v8::AccessorInfo info(args->arguments() -
   1407                           kAccessorInfoOffsetInInterceptorArgs);
   1408     HandleScope scope(isolate);
   1409     v8::Handle<v8::Value> r;
   1410     {
   1411       // Leaving JavaScript.
   1412       VMState state(isolate, EXTERNAL);
   1413       r = getter(v8::Utils::ToLocal(name_handle), info);
   1414     }
   1415     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1416     if (!r.IsEmpty()) {
   1417       *attrs = NONE;
   1418       return *v8::Utils::OpenHandle(*r);
   1419     }
   1420   }
   1421 
   1422   MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
   1423       *receiver_handle,
   1424       *name_handle,
   1425       attrs);
   1426   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1427   return result;
   1428 }
   1429 
   1430 
   1431 /**
   1432  * Loads a property with an interceptor performing post interceptor
   1433  * lookup if interceptor failed.
   1434  */
   1435 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
   1436   PropertyAttributes attr = NONE;
   1437   Object* result;
   1438   { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
   1439     if (!maybe_result->ToObject(&result)) return maybe_result;
   1440   }
   1441 
   1442   // If the property is present, return it.
   1443   if (attr != ABSENT) return result;
   1444   return ThrowReferenceError(String::cast(args[0]));
   1445 }
   1446 
   1447 
   1448 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
   1449   PropertyAttributes attr;
   1450   MaybeObject* result = LoadWithInterceptor(&args, &attr);
   1451   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   1452   // This is call IC. In this case, we simply return the undefined result which
   1453   // will lead to an exception when trying to invoke the result as a
   1454   // function.
   1455   return result;
   1456 }
   1457 
   1458 
   1459 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
   1460   ASSERT(args.length() == 4);
   1461   JSObject* recv = JSObject::cast(args[0]);
   1462   String* name = String::cast(args[1]);
   1463   Object* value = args[2];
   1464   StrictModeFlag strict_mode =
   1465       static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
   1466   ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
   1467   ASSERT(recv->HasNamedInterceptor());
   1468   PropertyAttributes attr = NONE;
   1469   MaybeObject* result = recv->SetPropertyWithInterceptor(
   1470       name, value, attr, strict_mode);
   1471   return result;
   1472 }
   1473 
   1474 
   1475 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
   1476   JSObject* receiver = JSObject::cast(args[0]);
   1477   ASSERT(Smi::cast(args[1])->value() >= 0);
   1478   uint32_t index = Smi::cast(args[1])->value();
   1479   return receiver->GetElementWithInterceptor(receiver, index);
   1480 }
   1481 
   1482 
   1483 MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
   1484   HandleScope scope(isolate());
   1485   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1486   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1487   if (kind == Code::CALL_IC) {
   1488     CallIC::GenerateInitialize(masm(), argc);
   1489   } else {
   1490     KeyedCallIC::GenerateInitialize(masm(), argc);
   1491   }
   1492   Object* result;
   1493   { MaybeObject* maybe_result =
   1494         GetCodeWithFlags(flags, "CompileCallInitialize");
   1495     if (!maybe_result->ToObject(&result)) return maybe_result;
   1496   }
   1497   isolate()->counters()->call_initialize_stubs()->Increment();
   1498   Code* code = Code::cast(result);
   1499   USE(code);
   1500   PROFILE(isolate(),
   1501           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
   1502                           code, code->arguments_count()));
   1503   GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
   1504   return result;
   1505 }
   1506 
   1507 
   1508 MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
   1509   HandleScope scope(isolate());
   1510   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1511   // The code of the PreMonomorphic stub is the same as the code
   1512   // of the Initialized stub.  They just differ on the code object flags.
   1513   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1514   if (kind == Code::CALL_IC) {
   1515     CallIC::GenerateInitialize(masm(), argc);
   1516   } else {
   1517     KeyedCallIC::GenerateInitialize(masm(), argc);
   1518   }
   1519   Object* result;
   1520   { MaybeObject* maybe_result =
   1521         GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
   1522     if (!maybe_result->ToObject(&result)) return maybe_result;
   1523   }
   1524   isolate()->counters()->call_premonomorphic_stubs()->Increment();
   1525   Code* code = Code::cast(result);
   1526   USE(code);
   1527   PROFILE(isolate(),
   1528           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
   1529                           code, code->arguments_count()));
   1530   GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
   1531   return result;
   1532 }
   1533 
   1534 
   1535 MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
   1536   HandleScope scope(isolate());
   1537   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1538   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1539   if (kind == Code::CALL_IC) {
   1540     CallIC::GenerateNormal(masm(), argc);
   1541   } else {
   1542     KeyedCallIC::GenerateNormal(masm(), argc);
   1543   }
   1544   Object* result;
   1545   { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
   1546     if (!maybe_result->ToObject(&result)) return maybe_result;
   1547   }
   1548   isolate()->counters()->call_normal_stubs()->Increment();
   1549   Code* code = Code::cast(result);
   1550   USE(code);
   1551   PROFILE(isolate(),
   1552           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
   1553                           code, code->arguments_count()));
   1554   GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
   1555   return result;
   1556 }
   1557 
   1558 
   1559 MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
   1560   HandleScope scope(isolate());
   1561   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1562   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1563   if (kind == Code::CALL_IC) {
   1564     CallIC::GenerateMegamorphic(masm(), argc);
   1565   } else {
   1566     KeyedCallIC::GenerateMegamorphic(masm(), argc);
   1567   }
   1568   Object* result;
   1569   { MaybeObject* maybe_result =
   1570         GetCodeWithFlags(flags, "CompileCallMegamorphic");
   1571     if (!maybe_result->ToObject(&result)) return maybe_result;
   1572   }
   1573   isolate()->counters()->call_megamorphic_stubs()->Increment();
   1574   Code* code = Code::cast(result);
   1575   USE(code);
   1576   PROFILE(isolate(),
   1577           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
   1578                           code, code->arguments_count()));
   1579   GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
   1580   return result;
   1581 }
   1582 
   1583 
   1584 MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
   1585   HandleScope scope(isolate());
   1586   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1587   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1588   if (kind == Code::CALL_IC) {
   1589     CallIC::GenerateMiss(masm(), argc);
   1590   } else {
   1591     KeyedCallIC::GenerateMiss(masm(), argc);
   1592   }
   1593   Object* result;
   1594   { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
   1595     if (!maybe_result->ToObject(&result)) return maybe_result;
   1596   }
   1597   isolate()->counters()->call_megamorphic_stubs()->Increment();
   1598   Code* code = Code::cast(result);
   1599   USE(code);
   1600   PROFILE(isolate(),
   1601           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
   1602                           code, code->arguments_count()));
   1603   GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
   1604   return result;
   1605 }
   1606 
   1607 
   1608 #ifdef ENABLE_DEBUGGER_SUPPORT
   1609 MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
   1610   HandleScope scope(isolate());
   1611   Debug::GenerateCallICDebugBreak(masm());
   1612   Object* result;
   1613   { MaybeObject* maybe_result =
   1614         GetCodeWithFlags(flags, "CompileCallDebugBreak");
   1615     if (!maybe_result->ToObject(&result)) return maybe_result;
   1616   }
   1617   Code* code = Code::cast(result);
   1618   USE(code);
   1619   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1620   USE(kind);
   1621   PROFILE(isolate(),
   1622           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
   1623                           code, code->arguments_count()));
   1624   return result;
   1625 }
   1626 
   1627 
   1628 MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
   1629   HandleScope scope(isolate());
   1630   // Use the same code for the the step in preparations as we do for
   1631   // the miss case.
   1632   int argc = Code::ExtractArgumentsCountFromFlags(flags);
   1633   Code::Kind kind = Code::ExtractKindFromFlags(flags);
   1634   if (kind == Code::CALL_IC) {
   1635     CallIC::GenerateMiss(masm(), argc);
   1636   } else {
   1637     KeyedCallIC::GenerateMiss(masm(), argc);
   1638   }
   1639   Object* result;
   1640   { MaybeObject* maybe_result =
   1641         GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
   1642     if (!maybe_result->ToObject(&result)) return maybe_result;
   1643   }
   1644   Code* code = Code::cast(result);
   1645   USE(code);
   1646   PROFILE(isolate(),
   1647           CodeCreateEvent(
   1648               CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
   1649               code,
   1650               code->arguments_count()));
   1651   return result;
   1652 }
   1653 #endif
   1654 
   1655 #undef CALL_LOGGER_TAG
   1656 
   1657 MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
   1658                                             const char* name) {
   1659   // Check for allocation failures during stub compilation.
   1660   if (failure_->IsFailure()) return failure_;
   1661 
   1662   // Create code object in the heap.
   1663   CodeDesc desc;
   1664   masm_.GetCode(&desc);
   1665   MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
   1666 #ifdef ENABLE_DISASSEMBLER
   1667   if (FLAG_print_code_stubs && !result->IsFailure()) {
   1668     Code::cast(result->ToObjectUnchecked())->Disassemble(name);
   1669   }
   1670 #endif
   1671   return result;
   1672 }
   1673 
   1674 
   1675 MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
   1676   if (FLAG_print_code_stubs && (name != NULL)) {
   1677     return GetCodeWithFlags(flags, *name->ToCString());
   1678   }
   1679   return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
   1680 }
   1681 
   1682 
   1683 void StubCompiler::LookupPostInterceptor(JSObject* holder,
   1684                                          String* name,
   1685                                          LookupResult* lookup) {
   1686   holder->LocalLookupRealNamedProperty(name, lookup);
   1687   if (!lookup->IsProperty()) {
   1688     lookup->NotFound();
   1689     Object* proto = holder->GetPrototype();
   1690     if (!proto->IsNull()) {
   1691       proto->Lookup(name, lookup);
   1692     }
   1693   }
   1694 }
   1695 
   1696 
   1697 
   1698 MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
   1699   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
   1700   MaybeObject* result = GetCodeWithFlags(flags, name);
   1701   if (!result->IsFailure()) {
   1702     PROFILE(isolate(),
   1703             CodeCreateEvent(Logger::LOAD_IC_TAG,
   1704                             Code::cast(result->ToObjectUnchecked()),
   1705                             name));
   1706     GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
   1707                    name,
   1708                    Code::cast(result->ToObjectUnchecked())));
   1709   }
   1710   return result;
   1711 }
   1712 
   1713 
   1714 MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
   1715   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
   1716   MaybeObject* result = GetCodeWithFlags(flags, name);
   1717   if (!result->IsFailure()) {
   1718     PROFILE(isolate(),
   1719             CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
   1720                             Code::cast(result->ToObjectUnchecked()),
   1721                             name));
   1722     GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
   1723                    name,
   1724                    Code::cast(result->ToObjectUnchecked())));
   1725   }
   1726   return result;
   1727 }
   1728 
   1729 
   1730 MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
   1731   Code::Flags flags = Code::ComputeMonomorphicFlags(
   1732       Code::STORE_IC, type, strict_mode_);
   1733   MaybeObject* result = GetCodeWithFlags(flags, name);
   1734   if (!result->IsFailure()) {
   1735     PROFILE(isolate(),
   1736             CodeCreateEvent(Logger::STORE_IC_TAG,
   1737                             Code::cast(result->ToObjectUnchecked()),
   1738                             name));
   1739     GDBJIT(AddCode(GDBJITInterface::STORE_IC,
   1740                    name,
   1741                    Code::cast(result->ToObjectUnchecked())));
   1742   }
   1743   return result;
   1744 }
   1745 
   1746 
   1747 MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
   1748   Code::Flags flags = Code::ComputeMonomorphicFlags(
   1749       Code::KEYED_STORE_IC, type, strict_mode_);
   1750   MaybeObject* result = GetCodeWithFlags(flags, name);
   1751   if (!result->IsFailure()) {
   1752     PROFILE(isolate(),
   1753             CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
   1754                             Code::cast(result->ToObjectUnchecked()),
   1755                             name));
   1756     GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
   1757                    name,
   1758                    Code::cast(result->ToObjectUnchecked())));
   1759   }
   1760   return result;
   1761 }
   1762 
   1763 
   1764 CallStubCompiler::CallStubCompiler(int argc,
   1765                                    InLoopFlag in_loop,
   1766                                    Code::Kind kind,
   1767                                    Code::ExtraICState extra_ic_state,
   1768                                    InlineCacheHolderFlag cache_holder)
   1769     : arguments_(argc),
   1770       in_loop_(in_loop),
   1771       kind_(kind),
   1772       extra_ic_state_(extra_ic_state),
   1773       cache_holder_(cache_holder) {
   1774 }
   1775 
   1776 
   1777 bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
   1778   SharedFunctionInfo* info = function->shared();
   1779   if (info->HasBuiltinFunctionId()) {
   1780     BuiltinFunctionId id = info->builtin_function_id();
   1781 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
   1782     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
   1783 #undef CALL_GENERATOR_CASE
   1784   }
   1785   CallOptimization optimization(function);
   1786   if (optimization.is_simple_api_call()) {
   1787     return true;
   1788   }
   1789   return false;
   1790 }
   1791 
   1792 
   1793 MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
   1794                                                  JSObject* holder,
   1795                                                  JSGlobalPropertyCell* cell,
   1796                                                  JSFunction* function,
   1797                                                  String* fname) {
   1798   ASSERT(HasCustomCallGenerator(function));
   1799 
   1800   SharedFunctionInfo* info = function->shared();
   1801   if (info->HasBuiltinFunctionId()) {
   1802     BuiltinFunctionId id = info->builtin_function_id();
   1803 #define CALL_GENERATOR_CASE(name)                           \
   1804     if (id == k##name) {                                    \
   1805       return CallStubCompiler::Compile##name##Call(object,  \
   1806                                                   holder,   \
   1807                                                   cell,     \
   1808                                                   function, \
   1809                                                   fname);   \
   1810     }
   1811     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
   1812 #undef CALL_GENERATOR_CASE
   1813   }
   1814   CallOptimization optimization(function);
   1815   ASSERT(optimization.is_simple_api_call());
   1816   return CompileFastApiCall(optimization,
   1817                             object,
   1818                             holder,
   1819                             cell,
   1820                             function,
   1821                             fname);
   1822 }
   1823 
   1824 
   1825 MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
   1826   int argc = arguments_.immediate();
   1827   Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
   1828                                                     type,
   1829                                                     extra_ic_state_,
   1830                                                     cache_holder_,
   1831                                                     in_loop_,
   1832                                                     argc);
   1833   return GetCodeWithFlags(flags, name);
   1834 }
   1835 
   1836 
   1837 MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
   1838   String* function_name = NULL;
   1839   if (function->shared()->name()->IsString()) {
   1840     function_name = String::cast(function->shared()->name());
   1841   }
   1842   return GetCode(CONSTANT_FUNCTION, function_name);
   1843 }
   1844 
   1845 
   1846 MaybeObject* ConstructStubCompiler::GetCode() {
   1847   Code::Flags flags = Code::ComputeFlags(Code::STUB);
   1848   Object* result;
   1849   { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
   1850     if (!maybe_result->ToObject(&result)) return maybe_result;
   1851   }
   1852   Code* code = Code::cast(result);
   1853   USE(code);
   1854   PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
   1855   GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
   1856   return result;
   1857 }
   1858 
   1859 
   1860 CallOptimization::CallOptimization(LookupResult* lookup) {
   1861   if (!lookup->IsProperty() || !lookup->IsCacheable() ||
   1862       lookup->type() != CONSTANT_FUNCTION) {
   1863     Initialize(NULL);
   1864   } else {
   1865     // We only optimize constant function calls.
   1866     Initialize(lookup->GetConstantFunction());
   1867   }
   1868 }
   1869 
   1870 CallOptimization::CallOptimization(JSFunction* function) {
   1871   Initialize(function);
   1872 }
   1873 
   1874 
   1875 int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
   1876                                                       JSObject* holder) const {
   1877   ASSERT(is_simple_api_call_);
   1878   if (expected_receiver_type_ == NULL) return 0;
   1879   int depth = 0;
   1880   while (object != holder) {
   1881     if (object->IsInstanceOf(expected_receiver_type_)) return depth;
   1882     object = JSObject::cast(object->GetPrototype());
   1883     ++depth;
   1884   }
   1885   if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
   1886   return kInvalidProtoDepth;
   1887 }
   1888 
   1889 
   1890 void CallOptimization::Initialize(JSFunction* function) {
   1891   constant_function_ = NULL;
   1892   is_simple_api_call_ = false;
   1893   expected_receiver_type_ = NULL;
   1894   api_call_info_ = NULL;
   1895 
   1896   if (function == NULL || !function->is_compiled()) return;
   1897 
   1898   constant_function_ = function;
   1899   AnalyzePossibleApiFunction(function);
   1900 }
   1901 
   1902 
   1903 void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
   1904   SharedFunctionInfo* sfi = function->shared();
   1905   if (!sfi->IsApiFunction()) return;
   1906   FunctionTemplateInfo* info = sfi->get_api_func_data();
   1907 
   1908   // Require a C++ callback.
   1909   if (info->call_code()->IsUndefined()) return;
   1910   api_call_info_ = CallHandlerInfo::cast(info->call_code());
   1911 
   1912   // Accept signatures that either have no restrictions at all or
   1913   // only have restrictions on the receiver.
   1914   if (!info->signature()->IsUndefined()) {
   1915     SignatureInfo* signature = SignatureInfo::cast(info->signature());
   1916     if (!signature->args()->IsUndefined()) return;
   1917     if (!signature->receiver()->IsUndefined()) {
   1918       expected_receiver_type_ =
   1919           FunctionTemplateInfo::cast(signature->receiver());
   1920     }
   1921   }
   1922 
   1923   is_simple_api_call_ = true;
   1924 }
   1925 
   1926 
   1927 MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
   1928   Object* result;
   1929   { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
   1930     if (!maybe_result->ToObject(&result)) return maybe_result;
   1931   }
   1932   Code* code = Code::cast(result);
   1933   USE(code);
   1934   PROFILE(isolate(),
   1935           CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
   1936   return result;
   1937 }
   1938 
   1939 
   1940 } }  // namespace v8::internal
   1941