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