Home | History | Annotate | Download | only in arm64
      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 #if V8_TARGET_ARCH_ARM64
      6 
      7 #include "src/ic/handler-compiler.h"
      8 
      9 #include "src/api-arguments.h"
     10 #include "src/field-type.h"
     11 #include "src/ic/call-optimization.h"
     12 #include "src/ic/ic.h"
     13 #include "src/isolate-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 #define __ ACCESS_MASM(masm)
     19 
     20 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
     21                                                 Register slot) {
     22   MacroAssembler* masm = this->masm();
     23   __ Push(vector);
     24   __ Push(slot);
     25 }
     26 
     27 
     28 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
     29   MacroAssembler* masm = this->masm();
     30   __ Pop(slot);
     31   __ Pop(vector);
     32 }
     33 
     34 
     35 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
     36   MacroAssembler* masm = this->masm();
     37   // Remove vector and slot.
     38   __ Drop(2);
     39 }
     40 
     41 
     42 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     43     MacroAssembler* masm, Label* miss_label, Register receiver,
     44     Handle<Name> name, Register scratch0, Register scratch1) {
     45   DCHECK(!AreAliased(receiver, scratch0, scratch1));
     46   DCHECK(name->IsUniqueName());
     47   Counters* counters = masm->isolate()->counters();
     48   __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
     49   __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
     50 
     51   Label done;
     52 
     53   const int kInterceptorOrAccessCheckNeededMask =
     54       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
     55 
     56   // Bail out if the receiver has a named interceptor or requires access checks.
     57   Register map = scratch1;
     58   __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
     59   __ Ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
     60   __ Tst(scratch0, kInterceptorOrAccessCheckNeededMask);
     61   __ B(ne, miss_label);
     62 
     63   // Check that receiver is a JSObject.
     64   __ Ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
     65   __ Cmp(scratch0, FIRST_JS_RECEIVER_TYPE);
     66   __ B(lt, miss_label);
     67 
     68   // Load properties array.
     69   Register properties = scratch0;
     70   __ Ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
     71   // Check that the properties array is a dictionary.
     72   __ Ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
     73   __ JumpIfNotRoot(map, Heap::kHashTableMapRootIndex, miss_label);
     74 
     75   NameDictionaryLookupStub::GenerateNegativeLookup(
     76       masm, miss_label, &done, receiver, properties, name, scratch1);
     77   __ Bind(&done);
     78   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
     79 }
     80 
     81 
     82 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
     83     MacroAssembler* masm, int index, Register result, Label* miss) {
     84   __ LoadNativeContextSlot(index, result);
     85   // Load its initial map. The global functions all have initial maps.
     86   __ Ldr(result,
     87          FieldMemOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
     88   // Load the prototype from the initial map.
     89   __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
     90 }
     91 
     92 
     93 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
     94     MacroAssembler* masm, Register receiver, Register scratch1,
     95     Register scratch2, Label* miss_label) {
     96   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
     97   // TryGetFunctionPrototype can't put the result directly in x0 because the
     98   // 3 inputs registers can't alias and we call this function from
     99   // LoadIC::GenerateFunctionPrototype, where receiver is x0. So we explicitly
    100   // move the result in x0.
    101   __ Mov(x0, scratch1);
    102   __ Ret();
    103 }
    104 
    105 
    106 // Generate code to check that a global property cell is empty. Create
    107 // the property cell at compilation time if no cell exists for the
    108 // property.
    109 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
    110     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
    111     Register scratch, Label* miss) {
    112   Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
    113   Isolate* isolate = masm->isolate();
    114   DCHECK(cell->value()->IsTheHole(isolate));
    115   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
    116   __ LoadWeakValue(scratch, weak_cell, miss);
    117   __ Ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
    118   __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
    119 }
    120 
    121 
    122 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
    123                                      Register holder, Register name,
    124                                      Handle<JSObject> holder_obj) {
    125   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    126   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    127   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    128   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    129 
    130   __ Push(name, receiver, holder);
    131 }
    132 
    133 
    134 static void CompileCallLoadPropertyWithInterceptor(
    135     MacroAssembler* masm, Register receiver, Register holder, Register name,
    136     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
    137   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
    138          Runtime::FunctionForId(id)->nargs);
    139   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    140   __ CallRuntime(id);
    141 }
    142 
    143 
    144 // Generate call to api function.
    145 void PropertyHandlerCompiler::GenerateApiAccessorCall(
    146     MacroAssembler* masm, const CallOptimization& optimization,
    147     Handle<Map> receiver_map, Register receiver, Register scratch,
    148     bool is_store, Register store_parameter, Register accessor_holder,
    149     int accessor_index) {
    150   DCHECK(!AreAliased(accessor_holder, scratch));
    151   DCHECK(!AreAliased(receiver, scratch));
    152 
    153   MacroAssembler::PushPopQueue queue(masm);
    154   queue.Queue(receiver);
    155   // Write the arguments to the stack frame.
    156   if (is_store) {
    157     DCHECK(!receiver.is(store_parameter));
    158     DCHECK(!scratch.is(store_parameter));
    159     queue.Queue(store_parameter);
    160   }
    161   queue.PushQueued();
    162 
    163   DCHECK(optimization.is_simple_api_call());
    164 
    165   // Abi for CallApiCallbackStub.
    166   Register callee = x0;
    167   Register data = x4;
    168   Register holder = x2;
    169   Register api_function_address = x1;
    170 
    171   // Put callee in place.
    172   __ LoadAccessor(callee, accessor_holder, accessor_index,
    173                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
    174 
    175   // Put holder in place.
    176   CallOptimization::HolderLookup holder_lookup;
    177   int holder_depth = 0;
    178   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
    179                                           &holder_depth);
    180   switch (holder_lookup) {
    181     case CallOptimization::kHolderIsReceiver:
    182       __ Mov(holder, receiver);
    183       break;
    184     case CallOptimization::kHolderFound:
    185       __ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
    186       __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
    187       for (int i = 1; i < holder_depth; i++) {
    188         __ Ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
    189         __ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
    190       }
    191       break;
    192     case CallOptimization::kHolderNotFound:
    193       UNREACHABLE();
    194       break;
    195   }
    196 
    197   Isolate* isolate = masm->isolate();
    198   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    199   bool call_data_undefined = false;
    200   // Put call data in place.
    201   if (api_call_info->data()->IsUndefined(isolate)) {
    202     call_data_undefined = true;
    203     __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
    204   } else {
    205     if (optimization.is_constant_call()) {
    206       __ Ldr(data,
    207              FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
    208       __ Ldr(data,
    209              FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
    210       __ Ldr(data,
    211              FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
    212     } else {
    213       __ Ldr(data,
    214              FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
    215     }
    216     __ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
    217   }
    218 
    219   if (api_call_info->fast_handler()->IsCode()) {
    220     // Just tail call into the fast handler if present.
    221     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
    222             RelocInfo::CODE_TARGET);
    223     return;
    224   }
    225 
    226   // Put api_function_address in place.
    227   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    228   ApiFunction fun(function_address);
    229   ExternalReference ref = ExternalReference(
    230       &fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
    231   __ Mov(api_function_address, ref);
    232 
    233   // Jump to stub.
    234   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
    235                            !optimization.is_constant_call());
    236   __ TailCallStub(&stub);
    237 }
    238 
    239 
    240 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
    241     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
    242     int accessor_index, int expected_arguments, Register scratch) {
    243   // ----------- S t a t e -------------
    244   //  -- lr    : return address
    245   // -----------------------------------
    246   Label miss;
    247   {
    248     FrameScope scope(masm, StackFrame::INTERNAL);
    249 
    250     // Save context register
    251     __ Push(cp);
    252     // Save value register, so we can restore it later.
    253     __ Push(value());
    254 
    255     if (accessor_index >= 0) {
    256       DCHECK(!AreAliased(holder, scratch));
    257       DCHECK(!AreAliased(receiver, scratch));
    258       DCHECK(!AreAliased(value(), scratch));
    259       // Call the JavaScript setter with receiver and value on the stack.
    260       if (map->IsJSGlobalObjectMap()) {
    261         // Swap in the global receiver.
    262         __ Ldr(scratch,
    263                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
    264         receiver = scratch;
    265       }
    266       __ Push(receiver, value());
    267       __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_SETTER);
    268       __ Mov(x0, 1);
    269       __ Call(masm->isolate()->builtins()->CallFunction(
    270                   ConvertReceiverMode::kNotNullOrUndefined),
    271               RelocInfo::CODE_TARGET);
    272     } else {
    273       // If we generate a global code snippet for deoptimization only, remember
    274       // the place to continue after deoptimization.
    275       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
    276     }
    277 
    278     // We have to return the passed value, not the return value of the setter.
    279     __ Pop(x0);
    280 
    281     // Restore context register.
    282     __ Pop(cp);
    283   }
    284   __ Ret();
    285 }
    286 
    287 
    288 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
    289     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
    290     int accessor_index, int expected_arguments, Register scratch) {
    291   {
    292     FrameScope scope(masm, StackFrame::INTERNAL);
    293 
    294     // Save context register
    295     __ Push(cp);
    296 
    297     if (accessor_index >= 0) {
    298       DCHECK(!AreAliased(holder, scratch));
    299       DCHECK(!AreAliased(receiver, scratch));
    300       // Call the JavaScript getter with the receiver on the stack.
    301       if (map->IsJSGlobalObjectMap()) {
    302         // Swap in the global receiver.
    303         __ Ldr(scratch,
    304                FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
    305         receiver = scratch;
    306       }
    307       __ Push(receiver);
    308       __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
    309       __ Mov(x0, 0);
    310       __ Call(masm->isolate()->builtins()->CallFunction(
    311                   ConvertReceiverMode::kNotNullOrUndefined),
    312               RelocInfo::CODE_TARGET);
    313     } else {
    314       // If we generate a global code snippet for deoptimization only, remember
    315       // the place to continue after deoptimization.
    316       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
    317     }
    318 
    319     // Restore context register.
    320     __ Pop(cp);
    321   }
    322   __ Ret();
    323 }
    324 
    325 
    326 static void StoreIC_PushArgs(MacroAssembler* masm) {
    327   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
    328           StoreDescriptor::ValueRegister(),
    329           VectorStoreICDescriptor::SlotRegister(),
    330           VectorStoreICDescriptor::VectorRegister());
    331 }
    332 
    333 
    334 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
    335   StoreIC_PushArgs(masm);
    336 
    337   // The slow case calls into the runtime to complete the store without causing
    338   // an IC miss that would otherwise cause a transition to the generic stub.
    339   __ TailCallRuntime(Runtime::kStoreIC_Slow);
    340 }
    341 
    342 
    343 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
    344   ASM_LOCATION("ElementHandlerCompiler::GenerateStoreSlow");
    345   StoreIC_PushArgs(masm);
    346 
    347   // The slow case calls into the runtime to complete the store without causing
    348   // an IC miss that would otherwise cause a transition to the generic stub.
    349   __ TailCallRuntime(Runtime::kKeyedStoreIC_Slow);
    350 }
    351 
    352 
    353 #undef __
    354 #define __ ACCESS_MASM(masm())
    355 
    356 
    357 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
    358     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
    359   Label miss;
    360   if (IC::ICUseVector(kind())) {
    361     PushVectorAndSlot();
    362   }
    363   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    364 
    365   // Get the value from the cell.
    366   Register result = StoreDescriptor::ValueRegister();
    367   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
    368   __ LoadWeakValue(result, weak_cell, &miss);
    369   __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
    370 
    371   // Check for deleted property if property can actually be deleted.
    372   if (is_configurable) {
    373     __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
    374   }
    375 
    376   Counters* counters = isolate()->counters();
    377   __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3);
    378   if (IC::ICUseVector(kind())) {
    379     DiscardVectorAndSlot();
    380   }
    381   __ Ret();
    382 
    383   FrontendFooter(name, &miss);
    384 
    385   // Return the generated code.
    386   return GetCode(kind(), name);
    387 }
    388 
    389 
    390 Register NamedStoreHandlerCompiler::value() {
    391   return StoreDescriptor::ValueRegister();
    392 }
    393 
    394 
    395 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
    396                                                     Handle<Name> name) {
    397   if (!label->is_unused()) {
    398     __ Bind(label);
    399     __ Mov(this->name(), Operand(name));
    400   }
    401 }
    402 
    403 
    404 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
    405   __ Mov(this->name(), Operand(name));
    406 }
    407 
    408 
    409 void NamedStoreHandlerCompiler::RearrangeVectorAndSlot(
    410     Register current_map, Register destination_map) {
    411   DCHECK(false);  // Not implemented.
    412 }
    413 
    414 
    415 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
    416                                                    Register map_reg,
    417                                                    Register scratch,
    418                                                    Label* miss) {
    419   Handle<WeakCell> cell = Map::WeakCellForMap(transition);
    420   DCHECK(!map_reg.is(scratch));
    421   __ LoadWeakValue(map_reg, cell, miss);
    422   if (transition->CanBeDeprecated()) {
    423     __ Ldrsw(scratch, FieldMemOperand(map_reg, Map::kBitField3Offset));
    424     __ TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, miss);
    425   }
    426 }
    427 
    428 
    429 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
    430                                                       int descriptor,
    431                                                       Register value_reg,
    432                                                       Register scratch,
    433                                                       Label* miss_label) {
    434   DCHECK(!map_reg.is(scratch));
    435   DCHECK(!map_reg.is(value_reg));
    436   DCHECK(!value_reg.is(scratch));
    437   __ LoadInstanceDescriptors(map_reg, scratch);
    438   __ Ldr(scratch,
    439          FieldMemOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
    440   __ Cmp(value_reg, scratch);
    441   __ B(ne, miss_label);
    442 }
    443 
    444 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
    445                                                         Register value_reg,
    446                                                         Label* miss_label) {
    447   Register map_reg = scratch1();
    448   Register scratch = scratch2();
    449   DCHECK(!value_reg.is(map_reg));
    450   DCHECK(!value_reg.is(scratch));
    451   __ JumpIfSmi(value_reg, miss_label);
    452   if (field_type->IsClass()) {
    453     __ Ldr(map_reg, FieldMemOperand(value_reg, HeapObject::kMapOffset));
    454     __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
    455                     scratch);
    456     __ B(ne, miss_label);
    457   }
    458 }
    459 
    460 
    461 Register PropertyHandlerCompiler::CheckPrototypes(
    462     Register object_reg, Register holder_reg, Register scratch1,
    463     Register scratch2, Handle<Name> name, Label* miss, PrototypeCheckType check,
    464     ReturnHolder return_what) {
    465   Handle<Map> receiver_map = map();
    466 
    467   // object_reg and holder_reg registers can alias.
    468   DCHECK(!AreAliased(object_reg, scratch1, scratch2));
    469   DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
    470 
    471   Handle<Cell> validity_cell =
    472       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
    473   if (!validity_cell.is_null()) {
    474     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
    475     __ Mov(scratch1, Operand(validity_cell));
    476     __ Ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
    477     __ Cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
    478     __ B(ne, miss);
    479   }
    480 
    481   // The prototype chain of primitives (and their JSValue wrappers) depends
    482   // on the native context, which can't be guarded by validity cells.
    483   // |object_reg| holds the native context specific prototype in this case;
    484   // we need to check its map.
    485   if (check == CHECK_ALL_MAPS) {
    486     __ Ldr(scratch1, FieldMemOperand(object_reg, HeapObject::kMapOffset));
    487     Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
    488     __ CmpWeakValue(scratch1, cell, scratch2);
    489     __ B(ne, miss);
    490   }
    491 
    492   // Keep track of the current object in register reg.
    493   Register reg = object_reg;
    494   int depth = 0;
    495 
    496   Handle<JSObject> current = Handle<JSObject>::null();
    497   if (receiver_map->IsJSGlobalObjectMap()) {
    498     current = isolate()->global_object();
    499   }
    500 
    501   // Check access rights to the global object.  This has to happen after
    502   // the map check so that we know that the object is actually a global
    503   // object.
    504   // This allows us to install generated handlers for accesses to the
    505   // global proxy (as opposed to using slow ICs). See corresponding code
    506   // in LookupForRead().
    507   if (receiver_map->IsJSGlobalProxyMap()) {
    508     UseScratchRegisterScope temps(masm());
    509     __ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
    510   }
    511 
    512   Handle<JSObject> prototype = Handle<JSObject>::null();
    513   Handle<Map> current_map = receiver_map;
    514   Handle<Map> holder_map(holder()->map());
    515   // Traverse the prototype chain and check the maps in the prototype chain for
    516   // fast and global objects or do negative lookup for normal objects.
    517   while (!current_map.is_identical_to(holder_map)) {
    518     ++depth;
    519 
    520     // Only global objects and objects that do not require access
    521     // checks are allowed in stubs.
    522     DCHECK(current_map->IsJSGlobalProxyMap() ||
    523            !current_map->is_access_check_needed());
    524 
    525     prototype = handle(JSObject::cast(current_map->prototype()));
    526     if (current_map->IsJSGlobalObjectMap()) {
    527       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
    528                                 name, scratch2, miss);
    529     } else if (current_map->is_dictionary_map()) {
    530       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
    531       if (!name->IsUniqueName()) {
    532         DCHECK(name->IsString());
    533         name = factory()->InternalizeString(Handle<String>::cast(name));
    534       }
    535       DCHECK(current.is_null() || (current->property_dictionary()->FindEntry(
    536                                        name) == NameDictionary::kNotFound));
    537 
    538       if (depth > 1) {
    539         // TODO(jkummerow): Cache and re-use weak cell.
    540         __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
    541       }
    542       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
    543                                        scratch2);
    544     }
    545 
    546     reg = holder_reg;  // From now on the object will be in holder_reg.
    547     // Go to the next object in the prototype chain.
    548     current = prototype;
    549     current_map = handle(current->map());
    550   }
    551 
    552   DCHECK(!current_map->IsJSGlobalProxyMap());
    553 
    554   // Log the check depth.
    555   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
    556 
    557   bool return_holder = return_what == RETURN_HOLDER;
    558   if (return_holder && depth != 0) {
    559     __ LoadWeakValue(reg, isolate()->factory()->NewWeakCell(current), miss);
    560   }
    561 
    562   // Return the register containing the holder.
    563   return return_holder ? reg : no_reg;
    564 }
    565 
    566 
    567 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    568   if (!miss->is_unused()) {
    569     Label success;
    570     __ B(&success);
    571 
    572     __ Bind(miss);
    573     if (IC::ICUseVector(kind())) {
    574       DCHECK(kind() == Code::LOAD_IC);
    575       PopVectorAndSlot();
    576     }
    577     TailCallBuiltin(masm(), MissBuiltin(kind()));
    578 
    579     __ Bind(&success);
    580   }
    581 }
    582 
    583 
    584 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    585   if (!miss->is_unused()) {
    586     Label success;
    587     __ B(&success);
    588 
    589     GenerateRestoreName(miss, name);
    590     if (IC::ICUseVector(kind())) PopVectorAndSlot();
    591     TailCallBuiltin(masm(), MissBuiltin(kind()));
    592 
    593     __ Bind(&success);
    594   }
    595 }
    596 
    597 
    598 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
    599   // Return the constant value.
    600   __ LoadObject(x0, value);
    601   __ Ret();
    602 }
    603 
    604 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
    605     LookupIterator* it, Register holder_reg) {
    606   DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
    607                      scratch3()));
    608   DCHECK(holder()->HasNamedInterceptor());
    609   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    610 
    611   // Compile the interceptor call, followed by inline code to load the
    612   // property from further up the prototype chain if the call fails.
    613   // Check that the maps haven't changed.
    614   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
    615 
    616   // Preserve the receiver register explicitly whenever it is different from the
    617   // holder and it is needed should the interceptor return without any result.
    618   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
    619   // case might cause a miss during the prototype check.
    620   bool must_perform_prototype_check =
    621       !holder().is_identical_to(it->GetHolder<JSObject>());
    622   bool must_preserve_receiver_reg =
    623       !receiver().is(holder_reg) &&
    624       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
    625 
    626   // Save necessary data before invoking an interceptor.
    627   // Requires a frame to make GC aware of pushed pointers.
    628   {
    629     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
    630     if (must_preserve_receiver_reg) {
    631       __ Push(receiver(), holder_reg, this->name());
    632     } else {
    633       __ Push(holder_reg, this->name());
    634     }
    635     InterceptorVectorSlotPush(holder_reg);
    636     // Invoke an interceptor.  Note: map checks from receiver to
    637     // interceptor's holder has been compiled before (see a caller
    638     // of this method.)
    639     CompileCallLoadPropertyWithInterceptor(
    640         masm(), receiver(), holder_reg, this->name(), holder(),
    641         Runtime::kLoadPropertyWithInterceptorOnly);
    642 
    643     // Check if interceptor provided a value for property.  If it's
    644     // the case, return immediately.
    645     Label interceptor_failed;
    646     __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
    647                   &interceptor_failed);
    648     frame_scope.GenerateLeaveFrame();
    649     __ Ret();
    650 
    651     __ Bind(&interceptor_failed);
    652     InterceptorVectorSlotPop(holder_reg);
    653     if (must_preserve_receiver_reg) {
    654       __ Pop(this->name(), holder_reg, receiver());
    655     } else {
    656       __ Pop(this->name(), holder_reg);
    657     }
    658     // Leave the internal frame.
    659   }
    660 
    661   GenerateLoadPostInterceptor(it, holder_reg);
    662 }
    663 
    664 
    665 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
    666   // Call the runtime system to load the interceptor.
    667   DCHECK(holder()->HasNamedInterceptor());
    668   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    669   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
    670                            holder());
    671 
    672   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
    673 }
    674 
    675 
    676 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    677     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
    678     LanguageMode language_mode) {
    679   ASM_LOCATION("NamedStoreHandlerCompiler::CompileStoreCallback");
    680   Register holder_reg = Frontend(name);
    681 
    682   // Stub never generated for non-global objects that require access checks.
    683   DCHECK(holder()->IsJSGlobalProxy() || !holder()->IsAccessCheckNeeded());
    684 
    685   // receiver() and holder_reg can alias.
    686   DCHECK(!AreAliased(receiver(), scratch1(), scratch2(), value()));
    687   DCHECK(!AreAliased(holder_reg, scratch1(), scratch2(), value()));
    688   // If the callback cannot leak, then push the callback directly,
    689   // otherwise wrap it in a weak cell.
    690   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
    691     __ Mov(scratch1(), Operand(callback));
    692   } else {
    693     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
    694     __ Mov(scratch1(), Operand(cell));
    695   }
    696   __ Mov(scratch2(), Operand(name));
    697   __ Push(receiver(), holder_reg, scratch1(), scratch2(), value());
    698   __ Push(Smi::FromInt(language_mode));
    699 
    700   // Do tail-call to the runtime system.
    701   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
    702 
    703   // Return the generated code.
    704   return GetCode(kind(), name);
    705 }
    706 
    707 
    708 #undef __
    709 }  // namespace internal
    710 }  // namespace v8
    711 
    712 #endif  // V8_TARGET_ARCH_IA32
    713