Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8.h"
      6 
      7 #include "src/api.h"
      8 #include "src/arguments.h"
      9 #include "src/ast.h"
     10 #include "src/code-stubs.h"
     11 #include "src/cpu-profiler.h"
     12 #include "src/gdb-jit.h"
     13 #include "src/ic-inl.h"
     14 #include "src/stub-cache.h"
     15 #include "src/type-info.h"
     16 #include "src/vm-state-inl.h"
     17 
     18 namespace v8 {
     19 namespace internal {
     20 
     21 // -----------------------------------------------------------------------
     22 // StubCache implementation.
     23 
     24 
     25 StubCache::StubCache(Isolate* isolate)
     26     : isolate_(isolate) { }
     27 
     28 
     29 void StubCache::Initialize() {
     30   ASSERT(IsPowerOf2(kPrimaryTableSize));
     31   ASSERT(IsPowerOf2(kSecondaryTableSize));
     32   Clear();
     33 }
     34 
     35 
     36 Code* StubCache::Set(Name* name, Map* map, Code* code) {
     37   // Get the flags from the code.
     38   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
     39 
     40   // Validate that the name does not move on scavenge, and that we
     41   // can use identity checks instead of structural equality checks.
     42   ASSERT(!heap()->InNewSpace(name));
     43   ASSERT(name->IsUniqueName());
     44 
     45   // The state bits are not important to the hash function because
     46   // the stub cache only contains monomorphic stubs. Make sure that
     47   // the bits are the least significant so they will be the ones
     48   // masked out.
     49   ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
     50   STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
     51 
     52   // Make sure that the code type is not included in the hash.
     53   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
     54 
     55   // Compute the primary entry.
     56   int primary_offset = PrimaryOffset(name, flags, map);
     57   Entry* primary = entry(primary_, primary_offset);
     58   Code* old_code = primary->value;
     59 
     60   // If the primary entry has useful data in it, we retire it to the
     61   // secondary cache before overwriting it.
     62   if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
     63     Map* old_map = primary->map;
     64     Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
     65     int seed = PrimaryOffset(primary->key, old_flags, old_map);
     66     int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
     67     Entry* secondary = entry(secondary_, secondary_offset);
     68     *secondary = *primary;
     69   }
     70 
     71   // Update primary cache.
     72   primary->key = name;
     73   primary->value = code;
     74   primary->map = map;
     75   isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
     76   return code;
     77 }
     78 
     79 
     80 Handle<Code> StubCache::FindIC(Handle<Name> name,
     81                                Handle<Map> stub_holder,
     82                                Code::Kind kind,
     83                                ExtraICState extra_state,
     84                                InlineCacheHolderFlag cache_holder) {
     85   Code::Flags flags = Code::ComputeMonomorphicFlags(
     86       kind, extra_state, cache_holder);
     87   Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
     88   if (probe->IsCode()) return Handle<Code>::cast(probe);
     89   return Handle<Code>::null();
     90 }
     91 
     92 
     93 Handle<Code> StubCache::FindHandler(Handle<Name> name,
     94                                     Handle<Map> stub_holder,
     95                                     Code::Kind kind,
     96                                     InlineCacheHolderFlag cache_holder,
     97                                     Code::StubType type) {
     98   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
     99 
    100   Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
    101   if (probe->IsCode()) return Handle<Code>::cast(probe);
    102   return Handle<Code>::null();
    103 }
    104 
    105 
    106 Handle<Code> StubCache::ComputeMonomorphicIC(
    107     Code::Kind kind,
    108     Handle<Name> name,
    109     Handle<HeapType> type,
    110     Handle<Code> handler,
    111     ExtraICState extra_ic_state) {
    112   InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
    113 
    114   Handle<Map> stub_holder;
    115   Handle<Code> ic;
    116   // There are multiple string maps that all use the same prototype. That
    117   // prototype cannot hold multiple handlers, one for each of the string maps,
    118   // for a single name. Hence, turn off caching of the IC.
    119   bool can_be_cached = !type->Is(HeapType::String());
    120   if (can_be_cached) {
    121     stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
    122     ic = FindIC(name, stub_holder, kind, extra_ic_state, flag);
    123     if (!ic.is_null()) return ic;
    124   }
    125 
    126   if (kind == Code::LOAD_IC) {
    127     LoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag);
    128     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
    129   } else if (kind == Code::KEYED_LOAD_IC) {
    130     KeyedLoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag);
    131     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
    132   } else if (kind == Code::STORE_IC) {
    133     StoreStubCompiler ic_compiler(isolate(), extra_ic_state);
    134     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
    135   } else {
    136     ASSERT(kind == Code::KEYED_STORE_IC);
    137     ASSERT(STANDARD_STORE ==
    138            KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
    139     KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state);
    140     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
    141   }
    142 
    143   if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
    144   return ic;
    145 }
    146 
    147 
    148 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
    149                                                Handle<HeapType> type) {
    150   InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
    151   Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
    152   // If no dictionary mode objects are present in the prototype chain, the load
    153   // nonexistent IC stub can be shared for all names for a given map and we use
    154   // the empty string for the map cache in that case. If there are dictionary
    155   // mode objects involved, we need to do negative lookups in the stub and
    156   // therefore the stub will be specific to the name.
    157   Handle<Map> current_map = stub_holder;
    158   Handle<Name> cache_name = current_map->is_dictionary_map()
    159       ? name : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol());
    160   Handle<Object> next(current_map->prototype(), isolate());
    161   Handle<JSObject> last = Handle<JSObject>::null();
    162   while (!next->IsNull()) {
    163     last = Handle<JSObject>::cast(next);
    164     next = handle(current_map->prototype(), isolate());
    165     current_map = handle(Handle<HeapObject>::cast(next)->map());
    166     if (current_map->is_dictionary_map()) cache_name = name;
    167   }
    168 
    169   // Compile the stub that is either shared for all names or
    170   // name specific if there are global objects involved.
    171   Handle<Code> handler = FindHandler(
    172       cache_name, stub_holder, Code::LOAD_IC, flag, Code::FAST);
    173   if (!handler.is_null()) {
    174     return handler;
    175   }
    176 
    177   LoadStubCompiler compiler(isolate_, kNoExtraICState, flag);
    178   handler = compiler.CompileLoadNonexistent(type, last, cache_name);
    179   Map::UpdateCodeCache(stub_holder, cache_name, handler);
    180   return handler;
    181 }
    182 
    183 
    184 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
    185   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
    186   Handle<Name> name =
    187       isolate()->factory()->KeyedLoadElementMonomorphic_string();
    188 
    189   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
    190   if (probe->IsCode()) return Handle<Code>::cast(probe);
    191 
    192   KeyedLoadStubCompiler compiler(isolate());
    193   Handle<Code> code = compiler.CompileLoadElement(receiver_map);
    194 
    195   Map::UpdateCodeCache(receiver_map, name, code);
    196   return code;
    197 }
    198 
    199 
    200 Handle<Code> StubCache::ComputeKeyedStoreElement(
    201     Handle<Map> receiver_map,
    202     StrictMode strict_mode,
    203     KeyedAccessStoreMode store_mode) {
    204   ExtraICState extra_state =
    205       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
    206   Code::Flags flags = Code::ComputeMonomorphicFlags(
    207       Code::KEYED_STORE_IC, extra_state);
    208 
    209   ASSERT(store_mode == STANDARD_STORE ||
    210          store_mode == STORE_AND_GROW_NO_TRANSITION ||
    211          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
    212          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
    213 
    214   Handle<String> name =
    215       isolate()->factory()->KeyedStoreElementMonomorphic_string();
    216   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
    217   if (probe->IsCode()) return Handle<Code>::cast(probe);
    218 
    219   KeyedStoreStubCompiler compiler(isolate(), extra_state);
    220   Handle<Code> code = compiler.CompileStoreElement(receiver_map);
    221 
    222   Map::UpdateCodeCache(receiver_map, name, code);
    223   ASSERT(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
    224          == store_mode);
    225   return code;
    226 }
    227 
    228 
    229 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
    230 
    231 static void FillCache(Isolate* isolate, Handle<Code> code) {
    232   Handle<UnseededNumberDictionary> dictionary =
    233       UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
    234                                     code->flags(),
    235                                     code);
    236   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
    237 }
    238 
    239 
    240 Code* StubCache::FindPreMonomorphicIC(Code::Kind kind, ExtraICState state) {
    241   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
    242   UnseededNumberDictionary* dictionary =
    243       isolate()->heap()->non_monomorphic_cache();
    244   int entry = dictionary->FindEntry(isolate(), flags);
    245   ASSERT(entry != -1);
    246   Object* code = dictionary->ValueAt(entry);
    247   // This might be called during the marking phase of the collector
    248   // hence the unchecked cast.
    249   return reinterpret_cast<Code*>(code);
    250 }
    251 
    252 
    253 Handle<Code> StubCache::ComputeLoad(InlineCacheState ic_state,
    254                                     ExtraICState extra_state) {
    255   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
    256   Handle<UnseededNumberDictionary> cache =
    257       isolate_->factory()->non_monomorphic_cache();
    258   int entry = cache->FindEntry(isolate_, flags);
    259   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    260 
    261   StubCompiler compiler(isolate_);
    262   Handle<Code> code;
    263   if (ic_state == UNINITIALIZED) {
    264     code = compiler.CompileLoadInitialize(flags);
    265   } else if (ic_state == PREMONOMORPHIC) {
    266     code = compiler.CompileLoadPreMonomorphic(flags);
    267   } else if (ic_state == MEGAMORPHIC) {
    268     code = compiler.CompileLoadMegamorphic(flags);
    269   } else {
    270     UNREACHABLE();
    271   }
    272   FillCache(isolate_, code);
    273   return code;
    274 }
    275 
    276 
    277 Handle<Code> StubCache::ComputeStore(InlineCacheState ic_state,
    278                                      ExtraICState extra_state) {
    279   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
    280   Handle<UnseededNumberDictionary> cache =
    281       isolate_->factory()->non_monomorphic_cache();
    282   int entry = cache->FindEntry(isolate_, flags);
    283   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
    284 
    285   StubCompiler compiler(isolate_);
    286   Handle<Code> code;
    287   if (ic_state == UNINITIALIZED) {
    288     code = compiler.CompileStoreInitialize(flags);
    289   } else if (ic_state == PREMONOMORPHIC) {
    290     code = compiler.CompileStorePreMonomorphic(flags);
    291   } else if (ic_state == GENERIC) {
    292     code = compiler.CompileStoreGeneric(flags);
    293   } else if (ic_state == MEGAMORPHIC) {
    294     code = compiler.CompileStoreMegamorphic(flags);
    295   } else {
    296     UNREACHABLE();
    297   }
    298 
    299   FillCache(isolate_, code);
    300   return code;
    301 }
    302 
    303 
    304 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
    305                                           CompareNilICStub* stub) {
    306   Handle<String> name(isolate_->heap()->empty_string());
    307   if (!receiver_map->is_shared()) {
    308     Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC,
    309                                     stub->GetExtraICState());
    310     if (!cached_ic.is_null()) return cached_ic;
    311   }
    312 
    313   Code::FindAndReplacePattern pattern;
    314   pattern.Add(isolate_->factory()->meta_map(), receiver_map);
    315   Handle<Code> ic = stub->GetCodeCopy(pattern);
    316 
    317   if (!receiver_map->is_shared()) {
    318     Map::UpdateCodeCache(receiver_map, name, ic);
    319   }
    320 
    321   return ic;
    322 }
    323 
    324 
    325 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
    326 Handle<Code> StubCache::ComputeLoadElementPolymorphic(
    327     MapHandleList* receiver_maps) {
    328   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
    329   Handle<PolymorphicCodeCache> cache =
    330       isolate_->factory()->polymorphic_code_cache();
    331   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
    332   if (probe->IsCode()) return Handle<Code>::cast(probe);
    333 
    334   TypeHandleList types(receiver_maps->length());
    335   for (int i = 0; i < receiver_maps->length(); i++) {
    336     types.Add(HeapType::Class(receiver_maps->at(i), isolate()));
    337   }
    338   CodeHandleList handlers(receiver_maps->length());
    339   KeyedLoadStubCompiler compiler(isolate_);
    340   compiler.CompileElementHandlers(receiver_maps, &handlers);
    341   Handle<Code> code = compiler.CompilePolymorphicIC(
    342       &types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT);
    343 
    344   isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
    345 
    346   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
    347   return code;
    348 }
    349 
    350 
    351 Handle<Code> StubCache::ComputePolymorphicIC(
    352     Code::Kind kind,
    353     TypeHandleList* types,
    354     CodeHandleList* handlers,
    355     int number_of_valid_types,
    356     Handle<Name> name,
    357     ExtraICState extra_ic_state) {
    358   Handle<Code> handler = handlers->at(0);
    359   Code::StubType type = number_of_valid_types == 1 ? handler->type()
    360                                                    : Code::NORMAL;
    361   if (kind == Code::LOAD_IC) {
    362     LoadStubCompiler ic_compiler(isolate_, extra_ic_state);
    363     return ic_compiler.CompilePolymorphicIC(
    364         types, handlers, name, type, PROPERTY);
    365   } else {
    366     ASSERT(kind == Code::STORE_IC);
    367     StoreStubCompiler ic_compiler(isolate_, extra_ic_state);
    368     return ic_compiler.CompilePolymorphicIC(
    369         types, handlers, name, type, PROPERTY);
    370   }
    371 }
    372 
    373 
    374 Handle<Code> StubCache::ComputeStoreElementPolymorphic(
    375     MapHandleList* receiver_maps,
    376     KeyedAccessStoreMode store_mode,
    377     StrictMode strict_mode) {
    378   ASSERT(store_mode == STANDARD_STORE ||
    379          store_mode == STORE_AND_GROW_NO_TRANSITION ||
    380          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
    381          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
    382   Handle<PolymorphicCodeCache> cache =
    383       isolate_->factory()->polymorphic_code_cache();
    384   ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
    385       strict_mode, store_mode);
    386   Code::Flags flags =
    387       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
    388   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
    389   if (probe->IsCode()) return Handle<Code>::cast(probe);
    390 
    391   KeyedStoreStubCompiler compiler(isolate_, extra_state);
    392   Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
    393   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
    394   return code;
    395 }
    396 
    397 
    398 void StubCache::Clear() {
    399   Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
    400   for (int i = 0; i < kPrimaryTableSize; i++) {
    401     primary_[i].key = heap()->empty_string();
    402     primary_[i].map = NULL;
    403     primary_[i].value = empty;
    404   }
    405   for (int j = 0; j < kSecondaryTableSize; j++) {
    406     secondary_[j].key = heap()->empty_string();
    407     secondary_[j].map = NULL;
    408     secondary_[j].value = empty;
    409   }
    410 }
    411 
    412 
    413 void StubCache::CollectMatchingMaps(SmallMapList* types,
    414                                     Handle<Name> name,
    415                                     Code::Flags flags,
    416                                     Handle<Context> native_context,
    417                                     Zone* zone) {
    418   for (int i = 0; i < kPrimaryTableSize; i++) {
    419     if (primary_[i].key == *name) {
    420       Map* map = primary_[i].map;
    421       // Map can be NULL, if the stub is constant function call
    422       // with a primitive receiver.
    423       if (map == NULL) continue;
    424 
    425       int offset = PrimaryOffset(*name, flags, map);
    426       if (entry(primary_, offset) == &primary_[i] &&
    427           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
    428         types->AddMapIfMissing(Handle<Map>(map), zone);
    429       }
    430     }
    431   }
    432 
    433   for (int i = 0; i < kSecondaryTableSize; i++) {
    434     if (secondary_[i].key == *name) {
    435       Map* map = secondary_[i].map;
    436       // Map can be NULL, if the stub is constant function call
    437       // with a primitive receiver.
    438       if (map == NULL) continue;
    439 
    440       // Lookup in primary table and skip duplicates.
    441       int primary_offset = PrimaryOffset(*name, flags, map);
    442 
    443       // Lookup in secondary table and add matches.
    444       int offset = SecondaryOffset(*name, flags, primary_offset);
    445       if (entry(secondary_, offset) == &secondary_[i] &&
    446           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
    447         types->AddMapIfMissing(Handle<Map>(map), zone);
    448       }
    449     }
    450   }
    451 }
    452 
    453 
    454 // ------------------------------------------------------------------------
    455 // StubCompiler implementation.
    456 
    457 
    458 RUNTIME_FUNCTION(StoreCallbackProperty) {
    459   JSObject* receiver = JSObject::cast(args[0]);
    460   JSObject* holder = JSObject::cast(args[1]);
    461   ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[2]);
    462   Address setter_address = v8::ToCData<Address>(callback->setter());
    463   v8::AccessorSetterCallback fun =
    464       FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
    465   ASSERT(fun != NULL);
    466   ASSERT(callback->IsCompatibleReceiver(receiver));
    467   Handle<Name> name = args.at<Name>(3);
    468   Handle<Object> value = args.at<Object>(4);
    469   HandleScope scope(isolate);
    470 
    471   // TODO(rossberg): Support symbols in the API.
    472   if (name->IsSymbol()) return *value;
    473   Handle<String> str = Handle<String>::cast(name);
    474 
    475   LOG(isolate, ApiNamedPropertyAccess("store", receiver, *name));
    476   PropertyCallbackArguments
    477       custom_args(isolate, callback->data(), receiver, holder);
    478   custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
    479   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
    480   return *value;
    481 }
    482 
    483 
    484 /**
    485  * Attempts to load a property with an interceptor (which must be present),
    486  * but doesn't search the prototype chain.
    487  *
    488  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
    489  * provide any value for the given name.
    490  */
    491 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
    492   ASSERT(args.length() == StubCache::kInterceptorArgsLength);
    493   Handle<Name> name_handle =
    494       args.at<Name>(StubCache::kInterceptorArgsNameIndex);
    495   Handle<InterceptorInfo> interceptor_info =
    496       args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
    497 
    498   // TODO(rossberg): Support symbols in the API.
    499   if (name_handle->IsSymbol())
    500     return isolate->heap()->no_interceptor_result_sentinel();
    501   Handle<String> name = Handle<String>::cast(name_handle);
    502 
    503   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
    504   v8::NamedPropertyGetterCallback getter =
    505       FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
    506   ASSERT(getter != NULL);
    507 
    508   Handle<JSObject> receiver =
    509       args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
    510   Handle<JSObject> holder =
    511       args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
    512   PropertyCallbackArguments callback_args(
    513       isolate, interceptor_info->data(), *receiver, *holder);
    514   {
    515     // Use the interceptor getter.
    516     HandleScope scope(isolate);
    517     v8::Handle<v8::Value> r =
    518         callback_args.Call(getter, v8::Utils::ToLocal(name));
    519     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
    520     if (!r.IsEmpty()) {
    521       Handle<Object> result = v8::Utils::OpenHandle(*r);
    522       result->VerifyApiCallResultType();
    523       return *v8::Utils::OpenHandle(*r);
    524     }
    525   }
    526 
    527   return isolate->heap()->no_interceptor_result_sentinel();
    528 }
    529 
    530 
    531 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
    532   // If the load is non-contextual, just return the undefined result.
    533   // Note that both keyed and non-keyed loads may end up here.
    534   HandleScope scope(isolate);
    535   LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
    536   if (ic.contextual_mode() != CONTEXTUAL) {
    537     return isolate->heap()->undefined_value();
    538   }
    539 
    540   // Throw a reference error.
    541   Handle<Name> name_handle(name);
    542   Handle<Object> error =
    543       isolate->factory()->NewReferenceError("not_defined",
    544                                             HandleVector(&name_handle, 1));
    545   return isolate->Throw(*error);
    546 }
    547 
    548 
    549 /**
    550  * Loads a property with an interceptor performing post interceptor
    551  * lookup if interceptor failed.
    552  */
    553 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
    554   HandleScope scope(isolate);
    555   ASSERT(args.length() == StubCache::kInterceptorArgsLength);
    556   Handle<Name> name =
    557       args.at<Name>(StubCache::kInterceptorArgsNameIndex);
    558   Handle<JSObject> receiver =
    559       args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
    560   Handle<JSObject> holder =
    561       args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
    562 
    563   Handle<Object> result;
    564   LookupIterator it(receiver, name, holder);
    565   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    566       isolate, result, JSObject::GetProperty(&it));
    567 
    568   if (it.IsFound()) return *result;
    569 
    570   return ThrowReferenceError(isolate, Name::cast(args[0]));
    571 }
    572 
    573 
    574 RUNTIME_FUNCTION(StoreInterceptorProperty) {
    575   HandleScope scope(isolate);
    576   ASSERT(args.length() == 3);
    577   StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
    578   Handle<JSObject> receiver = args.at<JSObject>(0);
    579   Handle<Name> name = args.at<Name>(1);
    580   Handle<Object> value = args.at<Object>(2);
    581   ASSERT(receiver->HasNamedInterceptor());
    582   PropertyAttributes attr = NONE;
    583   Handle<Object> result;
    584   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    585       isolate, result,
    586       JSObject::SetPropertyWithInterceptor(
    587           receiver, name, value, attr, ic.strict_mode()));
    588   return *result;
    589 }
    590 
    591 
    592 RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor) {
    593   HandleScope scope(isolate);
    594   Handle<JSObject> receiver = args.at<JSObject>(0);
    595   ASSERT(args.smi_at(1) >= 0);
    596   uint32_t index = args.smi_at(1);
    597   Handle<Object> result;
    598   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    599       isolate, result,
    600       JSObject::GetElementWithInterceptor(receiver, receiver, index));
    601   return *result;
    602 }
    603 
    604 
    605 Handle<Code> StubCompiler::CompileLoadInitialize(Code::Flags flags) {
    606   LoadIC::GenerateInitialize(masm());
    607   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
    608   PROFILE(isolate(),
    609           CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
    610   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
    611   return code;
    612 }
    613 
    614 
    615 Handle<Code> StubCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
    616   LoadIC::GeneratePreMonomorphic(masm());
    617   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
    618   PROFILE(isolate(),
    619           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
    620   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
    621   return code;
    622 }
    623 
    624 
    625 Handle<Code> StubCompiler::CompileLoadMegamorphic(Code::Flags flags) {
    626   LoadIC::GenerateMegamorphic(masm());
    627   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
    628   PROFILE(isolate(),
    629           CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
    630   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
    631   return code;
    632 }
    633 
    634 
    635 Handle<Code> StubCompiler::CompileStoreInitialize(Code::Flags flags) {
    636   StoreIC::GenerateInitialize(masm());
    637   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
    638   PROFILE(isolate(),
    639           CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
    640   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
    641   return code;
    642 }
    643 
    644 
    645 Handle<Code> StubCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
    646   StoreIC::GeneratePreMonomorphic(masm());
    647   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
    648   PROFILE(isolate(),
    649           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
    650   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
    651   return code;
    652 }
    653 
    654 
    655 Handle<Code> StubCompiler::CompileStoreGeneric(Code::Flags flags) {
    656   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
    657   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
    658   StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
    659   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
    660   PROFILE(isolate(),
    661           CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
    662   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
    663   return code;
    664 }
    665 
    666 
    667 Handle<Code> StubCompiler::CompileStoreMegamorphic(Code::Flags flags) {
    668   StoreIC::GenerateMegamorphic(masm());
    669   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
    670   PROFILE(isolate(),
    671           CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
    672   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
    673   return code;
    674 }
    675 
    676 
    677 #undef CALL_LOGGER_TAG
    678 
    679 
    680 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
    681                                             const char* name) {
    682   // Create code object in the heap.
    683   CodeDesc desc;
    684   masm_.GetCode(&desc);
    685   Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
    686   if (code->has_major_key()) {
    687     code->set_major_key(CodeStub::NoCache);
    688   }
    689 #ifdef ENABLE_DISASSEMBLER
    690   if (FLAG_print_code_stubs) code->Disassemble(name);
    691 #endif
    692   return code;
    693 }
    694 
    695 
    696 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
    697                                             Handle<Name> name) {
    698   return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
    699       ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
    700       : GetCodeWithFlags(flags, NULL);
    701 }
    702 
    703 
    704 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
    705                                          Handle<Name> name,
    706                                          LookupResult* lookup) {
    707   holder->LookupOwnRealNamedProperty(name, lookup);
    708   if (lookup->IsFound()) return;
    709   if (holder->GetPrototype()->IsNull()) return;
    710   holder->GetPrototype()->Lookup(name, lookup);
    711 }
    712 
    713 
    714 #define __ ACCESS_MASM(masm())
    715 
    716 
    717 Register LoadStubCompiler::HandlerFrontendHeader(
    718     Handle<HeapType> type,
    719     Register object_reg,
    720     Handle<JSObject> holder,
    721     Handle<Name> name,
    722     Label* miss) {
    723   PrototypeCheckType check_type = CHECK_ALL_MAPS;
    724   int function_index = -1;
    725   if (type->Is(HeapType::String())) {
    726     function_index = Context::STRING_FUNCTION_INDEX;
    727   } else if (type->Is(HeapType::Symbol())) {
    728     function_index = Context::SYMBOL_FUNCTION_INDEX;
    729   } else if (type->Is(HeapType::Number())) {
    730     function_index = Context::NUMBER_FUNCTION_INDEX;
    731   } else if (type->Is(HeapType::Boolean())) {
    732     function_index = Context::BOOLEAN_FUNCTION_INDEX;
    733   } else {
    734     check_type = SKIP_RECEIVER;
    735   }
    736 
    737   if (check_type == CHECK_ALL_MAPS) {
    738     GenerateDirectLoadGlobalFunctionPrototype(
    739         masm(), function_index, scratch1(), miss);
    740     Object* function = isolate()->native_context()->get(function_index);
    741     Object* prototype = JSFunction::cast(function)->instance_prototype();
    742     type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate());
    743     object_reg = scratch1();
    744   }
    745 
    746   // Check that the maps starting from the prototype haven't changed.
    747   return CheckPrototypes(
    748       type, object_reg, holder, scratch1(), scratch2(), scratch3(),
    749       name, miss, check_type);
    750 }
    751 
    752 
    753 // HandlerFrontend for store uses the name register. It has to be restored
    754 // before a miss.
    755 Register StoreStubCompiler::HandlerFrontendHeader(
    756     Handle<HeapType> type,
    757     Register object_reg,
    758     Handle<JSObject> holder,
    759     Handle<Name> name,
    760     Label* miss) {
    761   return CheckPrototypes(type, object_reg, holder, this->name(),
    762                          scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
    763 }
    764 
    765 
    766 bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) {
    767   for (int i = 0; i < types->length(); ++i) {
    768     if (types->at(i)->Is(HeapType::Number())) return true;
    769   }
    770   return false;
    771 }
    772 
    773 
    774 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<HeapType> type,
    775                                                     Register object_reg,
    776                                                     Handle<JSObject> holder,
    777                                                     Handle<Name> name) {
    778   Label miss;
    779 
    780   Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
    781 
    782   HandlerFrontendFooter(name, &miss);
    783 
    784   return reg;
    785 }
    786 
    787 
    788 void LoadStubCompiler::NonexistentHandlerFrontend(Handle<HeapType> type,
    789                                                   Handle<JSObject> last,
    790                                                   Handle<Name> name) {
    791   Label miss;
    792 
    793   Register holder;
    794   Handle<Map> last_map;
    795   if (last.is_null()) {
    796     holder = receiver();
    797     last_map = IC::TypeToMap(*type, isolate());
    798     // If |type| has null as its prototype, |last| is Handle<JSObject>::null().
    799     ASSERT(last_map->prototype() == isolate()->heap()->null_value());
    800   } else {
    801     holder = HandlerFrontendHeader(type, receiver(), last, name, &miss);
    802     last_map = handle(last->map());
    803   }
    804 
    805   if (last_map->is_dictionary_map() &&
    806       !last_map->IsJSGlobalObjectMap() &&
    807       !last_map->IsJSGlobalProxyMap()) {
    808     if (!name->IsUniqueName()) {
    809       ASSERT(name->IsString());
    810       name = factory()->InternalizeString(Handle<String>::cast(name));
    811     }
    812     ASSERT(last.is_null() ||
    813            last->property_dictionary()->FindEntry(name) ==
    814                NameDictionary::kNotFound);
    815     GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
    816                                      scratch2(), scratch3());
    817   }
    818 
    819   // If the last object in the prototype chain is a global object,
    820   // check that the global property cell is empty.
    821   if (last_map->IsJSGlobalObjectMap()) {
    822     Handle<JSGlobalObject> global = last.is_null()
    823         ? Handle<JSGlobalObject>::cast(type->AsConstant()->Value())
    824         : Handle<JSGlobalObject>::cast(last);
    825     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
    826   }
    827 
    828   HandlerFrontendFooter(name, &miss);
    829 }
    830 
    831 
    832 Handle<Code> LoadStubCompiler::CompileLoadField(
    833     Handle<HeapType> type,
    834     Handle<JSObject> holder,
    835     Handle<Name> name,
    836     FieldIndex field,
    837     Representation representation) {
    838   Register reg = HandlerFrontend(type, receiver(), holder, name);
    839   GenerateLoadField(reg, holder, field, representation);
    840 
    841   // Return the generated code.
    842   return GetCode(kind(), Code::FAST, name);
    843 }
    844 
    845 
    846 Handle<Code> LoadStubCompiler::CompileLoadConstant(
    847     Handle<HeapType> type,
    848     Handle<JSObject> holder,
    849     Handle<Name> name,
    850     Handle<Object> value) {
    851   HandlerFrontend(type, receiver(), holder, name);
    852   GenerateLoadConstant(value);
    853 
    854   // Return the generated code.
    855   return GetCode(kind(), Code::FAST, name);
    856 }
    857 
    858 
    859 Handle<Code> LoadStubCompiler::CompileLoadCallback(
    860     Handle<HeapType> type,
    861     Handle<JSObject> holder,
    862     Handle<Name> name,
    863     Handle<ExecutableAccessorInfo> callback) {
    864   Register reg = CallbackHandlerFrontend(
    865       type, receiver(), holder, name, callback);
    866   GenerateLoadCallback(reg, callback);
    867 
    868   // Return the generated code.
    869   return GetCode(kind(), Code::FAST, name);
    870 }
    871 
    872 
    873 Handle<Code> LoadStubCompiler::CompileLoadCallback(
    874     Handle<HeapType> type,
    875     Handle<JSObject> holder,
    876     Handle<Name> name,
    877     const CallOptimization& call_optimization) {
    878   ASSERT(call_optimization.is_simple_api_call());
    879   Handle<JSFunction> callback = call_optimization.constant_function();
    880   CallbackHandlerFrontend(type, receiver(), holder, name, callback);
    881   Handle<Map>receiver_map = IC::TypeToMap(*type, isolate());
    882   GenerateFastApiCall(
    883       masm(), call_optimization, receiver_map,
    884       receiver(), scratch1(), false, 0, NULL);
    885   // Return the generated code.
    886   return GetCode(kind(), Code::FAST, name);
    887 }
    888 
    889 
    890 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
    891     Handle<HeapType> type,
    892     Handle<JSObject> holder,
    893     Handle<Name> name) {
    894   LookupResult lookup(isolate());
    895   LookupPostInterceptor(holder, name, &lookup);
    896 
    897   Register reg = HandlerFrontend(type, receiver(), holder, name);
    898   // TODO(368): Compile in the whole chain: all the interceptors in
    899   // prototypes and ultimate answer.
    900   GenerateLoadInterceptor(reg, type, holder, &lookup, name);
    901 
    902   // Return the generated code.
    903   return GetCode(kind(), Code::FAST, name);
    904 }
    905 
    906 
    907 void LoadStubCompiler::GenerateLoadPostInterceptor(
    908     Register interceptor_reg,
    909     Handle<JSObject> interceptor_holder,
    910     Handle<Name> name,
    911     LookupResult* lookup) {
    912   Handle<JSObject> holder(lookup->holder());
    913   if (lookup->IsField()) {
    914     FieldIndex field = lookup->GetFieldIndex();
    915     if (interceptor_holder.is_identical_to(holder)) {
    916       GenerateLoadField(
    917           interceptor_reg, holder, field, lookup->representation());
    918     } else {
    919       // We found FIELD property in prototype chain of interceptor's holder.
    920       // Retrieve a field from field's holder.
    921       Register reg = HandlerFrontend(
    922           IC::CurrentTypeOf(interceptor_holder, isolate()),
    923           interceptor_reg, holder, name);
    924       GenerateLoadField(
    925           reg, holder, field, lookup->representation());
    926     }
    927   } else {
    928     // We found CALLBACKS property in prototype chain of interceptor's
    929     // holder.
    930     ASSERT(lookup->type() == CALLBACKS);
    931     Handle<ExecutableAccessorInfo> callback(
    932         ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
    933     ASSERT(callback->getter() != NULL);
    934 
    935     Register reg = CallbackHandlerFrontend(
    936         IC::CurrentTypeOf(interceptor_holder, isolate()),
    937         interceptor_reg, holder, name, callback);
    938     GenerateLoadCallback(reg, callback);
    939   }
    940 }
    941 
    942 
    943 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
    944     Handle<HeapType> type,
    945     Handle<Code> handler,
    946     Handle<Name> name) {
    947   TypeHandleList types(1);
    948   CodeHandleList handlers(1);
    949   types.Add(type);
    950   handlers.Add(handler);
    951   Code::StubType stub_type = handler->type();
    952   return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY);
    953 }
    954 
    955 
    956 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
    957     Handle<HeapType> type,
    958     Handle<JSObject> holder,
    959     Handle<Name> name,
    960     Handle<JSFunction> getter) {
    961   HandlerFrontend(type, receiver(), holder, name);
    962   GenerateLoadViaGetter(masm(), type, receiver(), getter);
    963 
    964   // Return the generated code.
    965   return GetCode(kind(), Code::FAST, name);
    966 }
    967 
    968 
    969 Handle<Code> StoreStubCompiler::CompileStoreTransition(
    970     Handle<JSObject> object,
    971     LookupResult* lookup,
    972     Handle<Map> transition,
    973     Handle<Name> name) {
    974   Label miss, slow;
    975 
    976   // Ensure no transitions to deprecated maps are followed.
    977   __ CheckMapDeprecated(transition, scratch1(), &miss);
    978 
    979   // Check that we are allowed to write this.
    980   if (object->GetPrototype()->IsJSObject()) {
    981     Handle<JSObject> holder;
    982     // holder == object indicates that no property was found.
    983     if (lookup->holder() != *object) {
    984       holder = Handle<JSObject>(lookup->holder());
    985     } else {
    986       // Find the top object.
    987       holder = object;
    988       do {
    989         holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
    990       } while (holder->GetPrototype()->IsJSObject());
    991     }
    992 
    993     Register holder_reg = HandlerFrontendHeader(
    994         IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss);
    995 
    996     // If no property was found, and the holder (the last object in the
    997     // prototype chain) is in slow mode, we need to do a negative lookup on the
    998     // holder.
    999     if (lookup->holder() == *object) {
   1000       GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
   1001     }
   1002   }
   1003 
   1004   GenerateStoreTransition(masm(),
   1005                           object,
   1006                           lookup,
   1007                           transition,
   1008                           name,
   1009                           receiver(), this->name(), value(),
   1010                           scratch1(), scratch2(), scratch3(),
   1011                           &miss,
   1012                           &slow);
   1013 
   1014   // Handle store cache miss.
   1015   GenerateRestoreName(masm(), &miss, name);
   1016   TailCallBuiltin(masm(), MissBuiltin(kind()));
   1017 
   1018   GenerateRestoreName(masm(), &slow, name);
   1019   TailCallBuiltin(masm(), SlowBuiltin(kind()));
   1020 
   1021   // Return the generated code.
   1022   return GetCode(kind(), Code::FAST, name);
   1023 }
   1024 
   1025 
   1026 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
   1027                                                   LookupResult* lookup,
   1028                                                   Handle<Name> name) {
   1029   Label miss;
   1030 
   1031   HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()),
   1032                         receiver(), object, name, &miss);
   1033 
   1034   // Generate store field code.
   1035   GenerateStoreField(masm(),
   1036                      object,
   1037                      lookup,
   1038                      receiver(), this->name(), value(), scratch1(), scratch2(),
   1039                      &miss);
   1040 
   1041   // Handle store cache miss.
   1042   __ bind(&miss);
   1043   TailCallBuiltin(masm(), MissBuiltin(kind()));
   1044 
   1045   // Return the generated code.
   1046   return GetCode(kind(), Code::FAST, name);
   1047 }
   1048 
   1049 
   1050 Handle<Code> StoreStubCompiler::CompileStoreArrayLength(Handle<JSObject> object,
   1051                                                         LookupResult* lookup,
   1052                                                         Handle<Name> name) {
   1053   // This accepts as a receiver anything JSArray::SetElementsLength accepts
   1054   // (currently anything except for external arrays which means anything with
   1055   // elements of FixedArray type).  Value must be a number, but only smis are
   1056   // accepted as the most common case.
   1057   Label miss;
   1058 
   1059   // Check that value is a smi.
   1060   __ JumpIfNotSmi(value(), &miss);
   1061 
   1062   // Generate tail call to StoreIC_ArrayLength.
   1063   GenerateStoreArrayLength();
   1064 
   1065   // Handle miss case.
   1066   __ bind(&miss);
   1067   TailCallBuiltin(masm(), MissBuiltin(kind()));
   1068 
   1069   // Return the generated code.
   1070   return GetCode(kind(), Code::FAST, name);
   1071 }
   1072 
   1073 
   1074 Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
   1075     Handle<JSObject> object,
   1076     Handle<JSObject> holder,
   1077     Handle<Name> name,
   1078     Handle<JSFunction> setter) {
   1079   Handle<HeapType> type = IC::CurrentTypeOf(object, isolate());
   1080   HandlerFrontend(type, receiver(), holder, name);
   1081   GenerateStoreViaSetter(masm(), type, receiver(), setter);
   1082 
   1083   return GetCode(kind(), Code::FAST, name);
   1084 }
   1085 
   1086 
   1087 Handle<Code> StoreStubCompiler::CompileStoreCallback(
   1088     Handle<JSObject> object,
   1089     Handle<JSObject> holder,
   1090     Handle<Name> name,
   1091     const CallOptimization& call_optimization) {
   1092   HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
   1093                   receiver(), holder, name);
   1094   Register values[] = { value() };
   1095   GenerateFastApiCall(
   1096       masm(), call_optimization, handle(object->map()),
   1097       receiver(), scratch1(), true, 1, values);
   1098   // Return the generated code.
   1099   return GetCode(kind(), Code::FAST, name);
   1100 }
   1101 
   1102 
   1103 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
   1104     Handle<Map> receiver_map) {
   1105   ElementsKind elements_kind = receiver_map->elements_kind();
   1106   if (receiver_map->has_fast_elements() ||
   1107       receiver_map->has_external_array_elements() ||
   1108       receiver_map->has_fixed_typed_array_elements()) {
   1109     Handle<Code> stub = KeyedLoadFastElementStub(
   1110         isolate(),
   1111         receiver_map->instance_type() == JS_ARRAY_TYPE,
   1112         elements_kind).GetCode();
   1113     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
   1114   } else {
   1115     Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
   1116         ? KeyedLoadDictionaryElementStub(isolate()).GetCode()
   1117         : KeyedLoadDictionaryElementPlatformStub(isolate()).GetCode();
   1118     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
   1119   }
   1120 
   1121   TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
   1122 
   1123   // Return the generated code.
   1124   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
   1125 }
   1126 
   1127 
   1128 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
   1129     Handle<Map> receiver_map) {
   1130   ElementsKind elements_kind = receiver_map->elements_kind();
   1131   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
   1132   Handle<Code> stub;
   1133   if (receiver_map->has_fast_elements() ||
   1134       receiver_map->has_external_array_elements() ||
   1135       receiver_map->has_fixed_typed_array_elements()) {
   1136     stub = KeyedStoreFastElementStub(
   1137         isolate(),
   1138         is_jsarray,
   1139         elements_kind,
   1140         store_mode()).GetCode();
   1141   } else {
   1142     stub = KeyedStoreElementStub(isolate(),
   1143                                  is_jsarray,
   1144                                  elements_kind,
   1145                                  store_mode()).GetCode();
   1146   }
   1147 
   1148   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
   1149 
   1150   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
   1151 
   1152   // Return the generated code.
   1153   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
   1154 }
   1155 
   1156 
   1157 #undef __
   1158 
   1159 
   1160 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
   1161   Handle<Code> code(masm->isolate()->builtins()->builtin(name));
   1162   GenerateTailCall(masm, code);
   1163 }
   1164 
   1165 
   1166 void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
   1167 #ifdef ENABLE_GDB_JIT_INTERFACE
   1168   GDBJITInterface::CodeTag tag;
   1169   if (kind_ == Code::LOAD_IC) {
   1170     tag = GDBJITInterface::LOAD_IC;
   1171   } else if (kind_ == Code::KEYED_LOAD_IC) {
   1172     tag = GDBJITInterface::KEYED_LOAD_IC;
   1173   } else if (kind_ == Code::STORE_IC) {
   1174     tag = GDBJITInterface::STORE_IC;
   1175   } else {
   1176     tag = GDBJITInterface::KEYED_STORE_IC;
   1177   }
   1178   GDBJIT(AddCode(tag, *name, *code));
   1179 #endif
   1180 }
   1181 
   1182 
   1183 void BaseLoadStoreStubCompiler::InitializeRegisters() {
   1184   if (kind_ == Code::LOAD_IC) {
   1185     registers_ = LoadStubCompiler::registers();
   1186   } else if (kind_ == Code::KEYED_LOAD_IC) {
   1187     registers_ = KeyedLoadStubCompiler::registers();
   1188   } else if (kind_ == Code::STORE_IC) {
   1189     registers_ = StoreStubCompiler::registers();
   1190   } else {
   1191     registers_ = KeyedStoreStubCompiler::registers();
   1192   }
   1193 }
   1194 
   1195 
   1196 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
   1197                                                   Code::StubType type,
   1198                                                   Handle<Name> name,
   1199                                                   InlineCacheState state) {
   1200   Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
   1201   Handle<Code> code = GetCodeWithFlags(flags, name);
   1202   IC::RegisterWeakMapDependency(code);
   1203   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
   1204   JitEvent(name, code);
   1205   return code;
   1206 }
   1207 
   1208 
   1209 Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
   1210                                                 Code::StubType type,
   1211                                                 Handle<Name> name) {
   1212   ASSERT_EQ(kNoExtraICState, extra_state());
   1213   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder_);
   1214   Handle<Code> code = GetCodeWithFlags(flags, name);
   1215   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
   1216   JitEvent(name, code);
   1217   return code;
   1218 }
   1219 
   1220 
   1221 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
   1222                                                    CodeHandleList* handlers) {
   1223   for (int i = 0; i < receiver_maps->length(); ++i) {
   1224     Handle<Map> receiver_map = receiver_maps->at(i);
   1225     Handle<Code> cached_stub;
   1226 
   1227     if ((receiver_map->instance_type() & kNotStringTag) == 0) {
   1228       cached_stub = isolate()->builtins()->KeyedLoadIC_String();
   1229     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
   1230       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
   1231     } else {
   1232       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
   1233       ElementsKind elements_kind = receiver_map->elements_kind();
   1234 
   1235       if (IsFastElementsKind(elements_kind) ||
   1236           IsExternalArrayElementsKind(elements_kind) ||
   1237           IsFixedTypedArrayElementsKind(elements_kind)) {
   1238         cached_stub =
   1239             KeyedLoadFastElementStub(isolate(),
   1240                                      is_js_array,
   1241                                      elements_kind).GetCode();
   1242       } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
   1243         cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
   1244       } else {
   1245         ASSERT(elements_kind == DICTIONARY_ELEMENTS);
   1246         cached_stub =
   1247             KeyedLoadDictionaryElementStub(isolate()).GetCode();
   1248       }
   1249     }
   1250 
   1251     handlers->Add(cached_stub);
   1252   }
   1253 }
   1254 
   1255 
   1256 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
   1257     MapHandleList* receiver_maps) {
   1258   // Collect MONOMORPHIC stubs for all |receiver_maps|.
   1259   CodeHandleList handlers(receiver_maps->length());
   1260   MapHandleList transitioned_maps(receiver_maps->length());
   1261   for (int i = 0; i < receiver_maps->length(); ++i) {
   1262     Handle<Map> receiver_map(receiver_maps->at(i));
   1263     Handle<Code> cached_stub;
   1264     Handle<Map> transitioned_map =
   1265         receiver_map->FindTransitionedMap(receiver_maps);
   1266 
   1267     // TODO(mvstanton): The code below is doing pessimistic elements
   1268     // transitions. I would like to stop doing that and rely on Allocation Site
   1269     // Tracking to do a better job of ensuring the data types are what they need
   1270     // to be. Not all the elements are in place yet, pessimistic elements
   1271     // transitions are still important for performance.
   1272     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
   1273     ElementsKind elements_kind = receiver_map->elements_kind();
   1274     if (!transitioned_map.is_null()) {
   1275       cached_stub = ElementsTransitionAndStoreStub(
   1276           isolate(),
   1277           elements_kind,
   1278           transitioned_map->elements_kind(),
   1279           is_js_array,
   1280           store_mode()).GetCode();
   1281     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
   1282       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
   1283     } else {
   1284       if (receiver_map->has_fast_elements() ||
   1285           receiver_map->has_external_array_elements() ||
   1286           receiver_map->has_fixed_typed_array_elements()) {
   1287         cached_stub = KeyedStoreFastElementStub(
   1288             isolate(),
   1289             is_js_array,
   1290             elements_kind,
   1291             store_mode()).GetCode();
   1292       } else {
   1293         cached_stub = KeyedStoreElementStub(
   1294             isolate(),
   1295             is_js_array,
   1296             elements_kind,
   1297             store_mode()).GetCode();
   1298       }
   1299     }
   1300     ASSERT(!cached_stub.is_null());
   1301     handlers.Add(cached_stub);
   1302     transitioned_maps.Add(transitioned_map);
   1303   }
   1304   Handle<Code> code =
   1305       CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
   1306   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
   1307   PROFILE(isolate(),
   1308           CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
   1309   return code;
   1310 }
   1311 
   1312 
   1313 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
   1314     MacroAssembler* masm) {
   1315   KeyedStoreIC::GenerateSlow(masm);
   1316 }
   1317 
   1318 
   1319 CallOptimization::CallOptimization(LookupResult* lookup) {
   1320   if (lookup->IsFound() &&
   1321       lookup->IsCacheable() &&
   1322       lookup->IsConstantFunction()) {
   1323     // We only optimize constant function calls.
   1324     Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
   1325   } else {
   1326     Initialize(Handle<JSFunction>::null());
   1327   }
   1328 }
   1329 
   1330 
   1331 CallOptimization::CallOptimization(Handle<JSFunction> function) {
   1332   Initialize(function);
   1333 }
   1334 
   1335 
   1336 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
   1337     Handle<Map> object_map,
   1338     HolderLookup* holder_lookup) const {
   1339   ASSERT(is_simple_api_call());
   1340   if (!object_map->IsJSObjectMap()) {
   1341     *holder_lookup = kHolderNotFound;
   1342     return Handle<JSObject>::null();
   1343   }
   1344   if (expected_receiver_type_.is_null() ||
   1345       expected_receiver_type_->IsTemplateFor(*object_map)) {
   1346     *holder_lookup = kHolderIsReceiver;
   1347     return Handle<JSObject>::null();
   1348   }
   1349   while (true) {
   1350     if (!object_map->prototype()->IsJSObject()) break;
   1351     Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
   1352     if (!prototype->map()->is_hidden_prototype()) break;
   1353     object_map = handle(prototype->map());
   1354     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
   1355       *holder_lookup = kHolderFound;
   1356       return prototype;
   1357     }
   1358   }
   1359   *holder_lookup = kHolderNotFound;
   1360   return Handle<JSObject>::null();
   1361 }
   1362 
   1363 
   1364 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
   1365                                             Handle<JSObject> holder) const {
   1366   ASSERT(is_simple_api_call());
   1367   if (!receiver->IsJSObject()) return false;
   1368   Handle<Map> map(JSObject::cast(*receiver)->map());
   1369   HolderLookup holder_lookup;
   1370   Handle<JSObject> api_holder =
   1371       LookupHolderOfExpectedType(map, &holder_lookup);
   1372   switch (holder_lookup) {
   1373     case kHolderNotFound:
   1374       return false;
   1375     case kHolderIsReceiver:
   1376       return true;
   1377     case kHolderFound:
   1378       if (api_holder.is_identical_to(holder)) return true;
   1379       // Check if holder is in prototype chain of api_holder.
   1380       {
   1381         JSObject* object = *api_holder;
   1382         while (true) {
   1383           Object* prototype = object->map()->prototype();
   1384           if (!prototype->IsJSObject()) return false;
   1385           if (prototype == *holder) return true;
   1386           object = JSObject::cast(prototype);
   1387         }
   1388       }
   1389       break;
   1390   }
   1391   UNREACHABLE();
   1392   return false;
   1393 }
   1394 
   1395 
   1396 void CallOptimization::Initialize(Handle<JSFunction> function) {
   1397   constant_function_ = Handle<JSFunction>::null();
   1398   is_simple_api_call_ = false;
   1399   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
   1400   api_call_info_ = Handle<CallHandlerInfo>::null();
   1401 
   1402   if (function.is_null() || !function->is_compiled()) return;
   1403 
   1404   constant_function_ = function;
   1405   AnalyzePossibleApiFunction(function);
   1406 }
   1407 
   1408 
   1409 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
   1410   if (!function->shared()->IsApiFunction()) return;
   1411   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
   1412 
   1413   // Require a C++ callback.
   1414   if (info->call_code()->IsUndefined()) return;
   1415   api_call_info_ =
   1416       Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
   1417 
   1418   // Accept signatures that either have no restrictions at all or
   1419   // only have restrictions on the receiver.
   1420   if (!info->signature()->IsUndefined()) {
   1421     Handle<SignatureInfo> signature =
   1422         Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
   1423     if (!signature->args()->IsUndefined()) return;
   1424     if (!signature->receiver()->IsUndefined()) {
   1425       expected_receiver_type_ =
   1426           Handle<FunctionTemplateInfo>(
   1427               FunctionTemplateInfo::cast(signature->receiver()));
   1428     }
   1429   }
   1430 
   1431   is_simple_api_call_ = true;
   1432 }
   1433 
   1434 
   1435 } }  // namespace v8::internal
   1436