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