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