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