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