Home | History | Annotate | Download | only in ic
      1 // Copyright 2014 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/ic/handler-compiler.h"
      6 
      7 #include "src/field-type.h"
      8 #include "src/ic/call-optimization.h"
      9 #include "src/ic/ic-inl.h"
     10 #include "src/ic/ic.h"
     11 #include "src/isolate-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
     17                                            Handle<Map> stub_holder,
     18                                            Code::Kind kind,
     19                                            CacheHolderFlag cache_holder) {
     20   Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
     21   Code* code = stub_holder->LookupInCodeCache(*name, flags);
     22   if (code == nullptr) return Handle<Code>();
     23   return handle(code);
     24 }
     25 
     26 
     27 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
     28     Handle<Name> name, Handle<Map> receiver_map) {
     29   Isolate* isolate = name->GetIsolate();
     30   if (receiver_map->prototype()->IsNull(isolate)) {
     31     // TODO(jkummerow/verwaest): If there is no prototype and the property
     32     // is nonexistent, introduce a builtin to handle this (fast properties
     33     // -> return undefined, dictionary properties -> do negative lookup).
     34     return Handle<Code>();
     35   }
     36   CacheHolderFlag flag;
     37   Handle<Map> stub_holder_map =
     38       IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);
     39 
     40   // If no dictionary mode objects are present in the prototype chain, the load
     41   // nonexistent IC stub can be shared for all names for a given map and we use
     42   // the empty string for the map cache in that case. If there are dictionary
     43   // mode objects involved, we need to do negative lookups in the stub and
     44   // therefore the stub will be specific to the name.
     45   Handle<Name> cache_name =
     46       receiver_map->is_dictionary_map()
     47           ? name
     48           : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
     49   Handle<Map> current_map = stub_holder_map;
     50   Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
     51   while (true) {
     52     if (current_map->is_dictionary_map()) cache_name = name;
     53     if (current_map->prototype()->IsNull(isolate)) break;
     54     if (name->IsPrivate()) {
     55       // TODO(verwaest): Use nonexistent_private_symbol.
     56       cache_name = name;
     57       if (!current_map->has_hidden_prototype()) break;
     58     }
     59 
     60     last = handle(JSObject::cast(current_map->prototype()));
     61     current_map = handle(last->map());
     62   }
     63   // Compile the stub that is either shared for all names or
     64   // name specific if there are global objects involved.
     65   Handle<Code> handler = PropertyHandlerCompiler::Find(
     66       cache_name, stub_holder_map, Code::LOAD_IC, flag);
     67   if (!handler.is_null()) return handler;
     68 
     69   TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
     70   NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
     71   handler = compiler.CompileLoadNonexistent(cache_name);
     72   Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
     73   return handler;
     74 }
     75 
     76 
     77 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
     78                                               Handle<Name> name) {
     79   Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
     80   Handle<Code> code = GetCodeWithFlags(flags, name);
     81   PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
     82                                      AbstractCode::cast(*code), *name));
     83 #ifdef DEBUG
     84   code->VerifyEmbeddedObjects();
     85 #endif
     86   return code;
     87 }
     88 
     89 
     90 #define __ ACCESS_MASM(masm())
     91 
     92 
     93 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
     94                                                   Handle<Name> name,
     95                                                   Label* miss,
     96                                                   ReturnHolder return_what) {
     97   PrototypeCheckType check_type = SKIP_RECEIVER;
     98   int function_index = map()->IsPrimitiveMap()
     99                            ? map()->GetConstructorFunctionIndex()
    100                            : Map::kNoConstructorFunctionIndex;
    101   if (function_index != Map::kNoConstructorFunctionIndex) {
    102     GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
    103                                               scratch1(), miss);
    104     Object* function = isolate()->native_context()->get(function_index);
    105     Object* prototype = JSFunction::cast(function)->instance_prototype();
    106     Handle<Map> map(JSObject::cast(prototype)->map());
    107     set_map(map);
    108     object_reg = scratch1();
    109     check_type = CHECK_ALL_MAPS;
    110   }
    111 
    112   // Check that the maps starting from the prototype haven't changed.
    113   return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
    114                          miss, check_type, return_what);
    115 }
    116 
    117 
    118 // Frontend for store uses the name register. It has to be restored before a
    119 // miss.
    120 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
    121                                                    Handle<Name> name,
    122                                                    Label* miss,
    123                                                    ReturnHolder return_what) {
    124   return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
    125                          miss, SKIP_RECEIVER, return_what);
    126 }
    127 
    128 
    129 Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
    130   Label miss;
    131   if (IC::ICUseVector(kind())) {
    132     PushVectorAndSlot();
    133   }
    134   Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
    135   FrontendFooter(name, &miss);
    136   // The footer consumes the vector and slot from the stack if miss occurs.
    137   if (IC::ICUseVector(kind())) {
    138     DiscardVectorAndSlot();
    139   }
    140   return reg;
    141 }
    142 
    143 
    144 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
    145                                                         Label* miss,
    146                                                         Register scratch1,
    147                                                         Register scratch2) {
    148   Register holder_reg;
    149   Handle<Map> last_map;
    150   if (holder().is_null()) {
    151     holder_reg = receiver();
    152     last_map = map();
    153     // If |type| has null as its prototype, |holder()| is
    154     // Handle<JSObject>::null().
    155     DCHECK(last_map->prototype() == isolate()->heap()->null_value());
    156   } else {
    157     last_map = handle(holder()->map());
    158     // This condition matches the branches below.
    159     bool need_holder =
    160         last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
    161     holder_reg =
    162         FrontendHeader(receiver(), name, miss,
    163                        need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
    164   }
    165 
    166   if (last_map->is_dictionary_map()) {
    167     if (last_map->IsJSGlobalObjectMap()) {
    168       Handle<JSGlobalObject> global =
    169           holder().is_null()
    170               ? Handle<JSGlobalObject>::cast(isolate()->global_object())
    171               : Handle<JSGlobalObject>::cast(holder());
    172       GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
    173     } else {
    174       if (!name->IsUniqueName()) {
    175         DCHECK(name->IsString());
    176         name = factory()->InternalizeString(Handle<String>::cast(name));
    177       }
    178       DCHECK(holder().is_null() ||
    179              holder()->property_dictionary()->FindEntry(name) ==
    180                  NameDictionary::kNotFound);
    181       GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
    182                                        scratch2);
    183     }
    184   }
    185 }
    186 
    187 
    188 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
    189                                                         FieldIndex field) {
    190   Register reg = Frontend(name);
    191   __ Move(receiver(), reg);
    192   LoadFieldStub stub(isolate(), field);
    193   GenerateTailCall(masm(), stub.GetCode());
    194   return GetCode(kind(), name);
    195 }
    196 
    197 
    198 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
    199                                                            int constant_index) {
    200   Register reg = Frontend(name);
    201   __ Move(receiver(), reg);
    202   LoadConstantStub stub(isolate(), constant_index);
    203   GenerateTailCall(masm(), stub.GetCode());
    204   return GetCode(kind(), name);
    205 }
    206 
    207 
    208 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
    209     Handle<Name> name) {
    210   Label miss;
    211   if (IC::ICUseVector(kind())) {
    212     DCHECK(kind() == Code::LOAD_IC);
    213     PushVectorAndSlot();
    214   }
    215   NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
    216   if (IC::ICUseVector(kind())) {
    217     DiscardVectorAndSlot();
    218   }
    219   GenerateLoadConstant(isolate()->factory()->undefined_value());
    220   FrontendFooter(name, &miss);
    221   return GetCode(kind(), name);
    222 }
    223 
    224 
    225 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
    226     Handle<Name> name, Handle<AccessorInfo> callback) {
    227   Register reg = Frontend(name);
    228   if (FLAG_runtime_call_stats) {
    229     TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
    230   } else {
    231     GenerateLoadCallback(reg, callback);
    232   }
    233   return GetCode(kind(), name);
    234 }
    235 
    236 
    237 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
    238     Handle<Name> name, const CallOptimization& call_optimization,
    239     int accessor_index) {
    240   DCHECK(call_optimization.is_simple_api_call());
    241   Register holder = Frontend(name);
    242   if (FLAG_runtime_call_stats) {
    243     TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
    244   } else {
    245     GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
    246                             scratch2(), false, no_reg, holder, accessor_index);
    247   }
    248   return GetCode(kind(), name);
    249 }
    250 
    251 
    252 void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
    253   if (IC::ICUseVector(kind())) {
    254     if (holder_reg.is(receiver())) {
    255       PushVectorAndSlot();
    256     } else {
    257       DCHECK(holder_reg.is(scratch1()));
    258       PushVectorAndSlot(scratch2(), scratch3());
    259     }
    260   }
    261 }
    262 
    263 
    264 void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
    265                                                         PopMode mode) {
    266   if (IC::ICUseVector(kind())) {
    267     if (mode == DISCARD) {
    268       DiscardVectorAndSlot();
    269     } else {
    270       if (holder_reg.is(receiver())) {
    271         PopVectorAndSlot();
    272       } else {
    273         DCHECK(holder_reg.is(scratch1()));
    274         PopVectorAndSlot(scratch2(), scratch3());
    275       }
    276     }
    277   }
    278 }
    279 
    280 
    281 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
    282     LookupIterator* it) {
    283   // So far the most popular follow ups for interceptor loads are DATA and
    284   // AccessorInfo, so inline only them. Other cases may be added
    285   // later.
    286   bool inline_followup = false;
    287   switch (it->state()) {
    288     case LookupIterator::TRANSITION:
    289       UNREACHABLE();
    290     case LookupIterator::ACCESS_CHECK:
    291     case LookupIterator::INTERCEPTOR:
    292     case LookupIterator::JSPROXY:
    293     case LookupIterator::NOT_FOUND:
    294     case LookupIterator::INTEGER_INDEXED_EXOTIC:
    295       break;
    296     case LookupIterator::DATA:
    297       inline_followup =
    298           it->property_details().type() == DATA && !it->is_dictionary_holder();
    299       break;
    300     case LookupIterator::ACCESSOR: {
    301       Handle<Object> accessors = it->GetAccessors();
    302       if (accessors->IsAccessorInfo()) {
    303         Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
    304         inline_followup =
    305             info->getter() != NULL &&
    306             AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
    307       } else if (accessors->IsAccessorPair()) {
    308         Handle<JSObject> property_holder(it->GetHolder<JSObject>());
    309         Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
    310                               isolate());
    311         if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
    312           break;
    313         }
    314         if (!property_holder->HasFastProperties()) break;
    315         CallOptimization call_optimization(getter);
    316         Handle<Map> receiver_map = map();
    317         inline_followup = call_optimization.is_simple_api_call() &&
    318                           call_optimization.IsCompatibleReceiverMap(
    319                               receiver_map, property_holder);
    320       }
    321     }
    322   }
    323 
    324   Label miss;
    325   InterceptorVectorSlotPush(receiver());
    326   bool lost_holder_register = false;
    327   auto holder_orig = holder();
    328   // non masking interceptors must check the entire chain, so temporarily reset
    329   // the holder to be that last element for the FrontendHeader call.
    330   if (holder()->GetNamedInterceptor()->non_masking()) {
    331     DCHECK(!inline_followup);
    332     JSObject* last = *holder();
    333     PrototypeIterator iter(isolate(), last);
    334     while (!iter.IsAtEnd()) {
    335       lost_holder_register = true;
    336       // Casting to JSObject is fine here. The LookupIterator makes sure to
    337       // look behind non-masking interceptors during the original lookup, and
    338       // we wouldn't try to compile a handler if there was a Proxy anywhere.
    339       last = iter.GetCurrent<JSObject>();
    340       iter.Advance();
    341     }
    342     auto last_handle = handle(last);
    343     set_holder(last_handle);
    344   }
    345   Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
    346   // Reset the holder so further calculations are correct.
    347   set_holder(holder_orig);
    348   if (lost_holder_register) {
    349     if (*it->GetReceiver() == *holder()) {
    350       reg = receiver();
    351     } else {
    352       // Reload lost holder register.
    353       auto cell = isolate()->factory()->NewWeakCell(holder());
    354       __ LoadWeakValue(reg, cell, &miss);
    355     }
    356   }
    357   FrontendFooter(it->name(), &miss);
    358   InterceptorVectorSlotPop(reg);
    359   if (inline_followup) {
    360     // TODO(368): Compile in the whole chain: all the interceptors in
    361     // prototypes and ultimate answer.
    362     GenerateLoadInterceptorWithFollowup(it, reg);
    363   } else {
    364     GenerateLoadInterceptor(reg);
    365   }
    366   return GetCode(kind(), it->name());
    367 }
    368 
    369 void NamedLoadHandlerCompiler::GenerateLoadCallback(
    370     Register reg, Handle<AccessorInfo> callback) {
    371   DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
    372   __ Move(ApiGetterDescriptor::HolderRegister(), reg);
    373   // The callback is alive if this instruction is executed,
    374   // so the weak cell is not cleared and points to data.
    375   Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
    376   __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
    377 
    378   CallApiGetterStub stub(isolate());
    379   __ TailCallStub(&stub);
    380 }
    381 
    382 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
    383     LookupIterator* it, Register interceptor_reg) {
    384   Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
    385 
    386   Handle<Map> holder_map(holder()->map());
    387   set_map(holder_map);
    388   set_holder(real_named_property_holder);
    389 
    390   Label miss;
    391   InterceptorVectorSlotPush(interceptor_reg);
    392   Register reg =
    393       FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
    394   FrontendFooter(it->name(), &miss);
    395   // We discard the vector and slot now because we don't miss below this point.
    396   InterceptorVectorSlotPop(reg, DISCARD);
    397 
    398   switch (it->state()) {
    399     case LookupIterator::ACCESS_CHECK:
    400     case LookupIterator::INTERCEPTOR:
    401     case LookupIterator::JSPROXY:
    402     case LookupIterator::NOT_FOUND:
    403     case LookupIterator::INTEGER_INDEXED_EXOTIC:
    404     case LookupIterator::TRANSITION:
    405       UNREACHABLE();
    406     case LookupIterator::DATA: {
    407       DCHECK_EQ(DATA, it->property_details().type());
    408       __ Move(receiver(), reg);
    409       LoadFieldStub stub(isolate(), it->GetFieldIndex());
    410       GenerateTailCall(masm(), stub.GetCode());
    411       break;
    412     }
    413     case LookupIterator::ACCESSOR:
    414       if (it->GetAccessors()->IsAccessorInfo()) {
    415         Handle<AccessorInfo> info =
    416             Handle<AccessorInfo>::cast(it->GetAccessors());
    417         DCHECK_NOT_NULL(info->getter());
    418         GenerateLoadCallback(reg, info);
    419       } else {
    420         Handle<Object> function = handle(
    421             AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
    422         CallOptimization call_optimization(function);
    423         GenerateApiAccessorCall(masm(), call_optimization, holder_map,
    424                                 receiver(), scratch2(), false, no_reg, reg,
    425                                 it->GetAccessorIndex());
    426       }
    427   }
    428 }
    429 
    430 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
    431     Handle<Name> name, int accessor_index, int expected_arguments) {
    432   Register holder = Frontend(name);
    433   GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
    434                         expected_arguments, scratch2());
    435   return GetCode(kind(), name);
    436 }
    437 
    438 
    439 // TODO(verwaest): Cleanup. holder() is actually the receiver.
    440 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
    441     Handle<Map> transition, Handle<Name> name) {
    442   Label miss;
    443 
    444   PushVectorAndSlot();
    445 
    446   // Check that we are allowed to write this.
    447   bool is_nonexistent = holder()->map() == transition->GetBackPointer();
    448   if (is_nonexistent) {
    449     // Find the top object.
    450     Handle<JSObject> last;
    451     PrototypeIterator::WhereToEnd end =
    452         name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
    453                           : PrototypeIterator::END_AT_NULL;
    454     PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
    455     while (!iter.IsAtEnd()) {
    456       last = PrototypeIterator::GetCurrent<JSObject>(iter);
    457       iter.Advance();
    458     }
    459     if (!last.is_null()) set_holder(last);
    460     NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
    461   } else {
    462     FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    463     DCHECK(holder()->HasFastProperties());
    464   }
    465 
    466   int descriptor = transition->LastAdded();
    467   Handle<DescriptorArray> descriptors(transition->instance_descriptors());
    468   PropertyDetails details = descriptors->GetDetails(descriptor);
    469   Representation representation = details.representation();
    470   DCHECK(!representation.IsNone());
    471 
    472   // Stub is never generated for objects that require access checks.
    473   DCHECK(!transition->is_access_check_needed());
    474 
    475   // Call to respective StoreTransitionStub.
    476   bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
    477   Register map_reg = StoreTransitionHelper::MapRegister();
    478 
    479   if (details.type() == DATA_CONSTANT) {
    480     DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
    481     Register tmp =
    482         virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
    483     GenerateRestoreMap(transition, tmp, scratch2(), &miss);
    484     GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
    485     if (virtual_args) {
    486       // This will move the map from tmp into map_reg.
    487       RearrangeVectorAndSlot(tmp, map_reg);
    488     } else {
    489       PopVectorAndSlot();
    490     }
    491     GenerateRestoreName(name);
    492     StoreTransitionStub stub(isolate());
    493     GenerateTailCall(masm(), stub.GetCode());
    494 
    495   } else {
    496     if (representation.IsHeapObject()) {
    497       GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
    498                               &miss);
    499     }
    500     StoreTransitionStub::StoreMode store_mode =
    501         Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
    502             ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
    503             : StoreTransitionStub::StoreMapAndValue;
    504 
    505     Register tmp =
    506         virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
    507     GenerateRestoreMap(transition, tmp, scratch2(), &miss);
    508     if (virtual_args) {
    509       RearrangeVectorAndSlot(tmp, map_reg);
    510     } else {
    511       PopVectorAndSlot();
    512     }
    513     GenerateRestoreName(name);
    514     StoreTransitionStub stub(isolate(),
    515                              FieldIndex::ForDescriptor(*transition, descriptor),
    516                              representation, store_mode);
    517     GenerateTailCall(masm(), stub.GetCode());
    518   }
    519 
    520   GenerateRestoreName(&miss, name);
    521   PopVectorAndSlot();
    522   TailCallBuiltin(masm(), MissBuiltin(kind()));
    523 
    524   return GetCode(kind(), name);
    525 }
    526 
    527 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
    528     FieldType* field_type) const {
    529   return field_type->IsClass();
    530 }
    531 
    532 
    533 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
    534   Label miss;
    535   DCHECK(it->representation().IsHeapObject());
    536 
    537   FieldType* field_type = *it->GetFieldType();
    538   bool need_save_restore = false;
    539   if (RequiresFieldTypeChecks(field_type)) {
    540     need_save_restore = IC::ICUseVector(kind());
    541     if (need_save_restore) PushVectorAndSlot();
    542     GenerateFieldTypeChecks(field_type, value(), &miss);
    543     if (need_save_restore) PopVectorAndSlot();
    544   }
    545 
    546   StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
    547   GenerateTailCall(masm(), stub.GetCode());
    548 
    549   __ bind(&miss);
    550   if (need_save_restore) PopVectorAndSlot();
    551   TailCallBuiltin(masm(), MissBuiltin(kind()));
    552   return GetCode(kind(), it->name());
    553 }
    554 
    555 
    556 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
    557     Handle<JSObject> object, Handle<Name> name, int accessor_index,
    558     int expected_arguments) {
    559   Register holder = Frontend(name);
    560   GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
    561                          expected_arguments, scratch2());
    562 
    563   return GetCode(kind(), name);
    564 }
    565 
    566 
    567 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    568     Handle<JSObject> object, Handle<Name> name,
    569     const CallOptimization& call_optimization, int accessor_index) {
    570   Register holder = Frontend(name);
    571   if (FLAG_runtime_call_stats) {
    572     GenerateRestoreName(name);
    573     TailCallBuiltin(masm(), Builtins::kStoreIC_Slow);
    574   } else {
    575     GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
    576                             receiver(), scratch2(), true, value(), holder,
    577                             accessor_index);
    578   }
    579   return GetCode(kind(), name);
    580 }
    581 
    582 
    583 #undef __
    584 
    585 void ElementHandlerCompiler::CompileElementHandlers(
    586     MapHandleList* receiver_maps, CodeHandleList* handlers) {
    587   for (int i = 0; i < receiver_maps->length(); ++i) {
    588     Handle<Map> receiver_map = receiver_maps->at(i);
    589     Handle<Code> cached_stub;
    590 
    591     if (receiver_map->IsStringMap()) {
    592       cached_stub = LoadIndexedStringStub(isolate()).GetCode();
    593     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
    594       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
    595     } else {
    596       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
    597       ElementsKind elements_kind = receiver_map->elements_kind();
    598 
    599       // No need to check for an elements-free prototype chain here, the
    600       // generated stub code needs to check that dynamically anyway.
    601       bool convert_hole_to_undefined =
    602           (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
    603            *receiver_map == isolate()->get_initial_js_array_map(elements_kind));
    604 
    605       if (receiver_map->has_indexed_interceptor() &&
    606           !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
    607               isolate()) &&
    608           !receiver_map->GetIndexedInterceptor()->non_masking()) {
    609         cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
    610       } else if (IsSloppyArgumentsElements(elements_kind)) {
    611         cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
    612       } else if (IsFastElementsKind(elements_kind) ||
    613                  IsFixedTypedArrayElementsKind(elements_kind)) {
    614         cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
    615                                           convert_hole_to_undefined).GetCode();
    616       } else {
    617         DCHECK(elements_kind == DICTIONARY_ELEMENTS);
    618         cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
    619       }
    620     }
    621 
    622     handlers->Add(cached_stub);
    623   }
    624 }
    625 }  // namespace internal
    626 }  // namespace v8
    627