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   STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
    115                 LoadWithVectorDescriptor::kVector);
    116   STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
    117                 StoreWithVectorDescriptor::kVector);
    118   STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
    119                 StoreTransitionDescriptor::kVector);
    120   __ push(slot);
    121   __ push(vector);
    122 }
    123 
    124 
    125 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
    126   MacroAssembler* masm = this->masm();
    127   __ pop(vector);
    128   __ pop(slot);
    129 }
    130 
    131 
    132 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
    133   MacroAssembler* masm = this->masm();
    134   // Remove vector and slot.
    135   __ add(sp, sp, Operand(2 * kPointerSize));
    136 }
    137 
    138 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
    139     MacroAssembler* masm, Label* miss_label, Register receiver,
    140     Handle<Name> name, Register scratch0, Register scratch1) {
    141   DCHECK(name->IsUniqueName());
    142   DCHECK(!receiver.is(scratch0));
    143   Counters* counters = masm->isolate()->counters();
    144   __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
    145   __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
    146 
    147   Label done;
    148 
    149   const int kInterceptorOrAccessCheckNeededMask =
    150       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
    151 
    152   // Bail out if the receiver has a named interceptor or requires access checks.
    153   Register map = scratch1;
    154   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    155   __ ldrb(scratch0, FieldMemOperand(map, Map::kBitFieldOffset));
    156   __ tst(scratch0, Operand(kInterceptorOrAccessCheckNeededMask));
    157   __ b(ne, miss_label);
    158 
    159   // Check that receiver is a JSObject.
    160   __ ldrb(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset));
    161   __ cmp(scratch0, Operand(FIRST_JS_RECEIVER_TYPE));
    162   __ b(lt, miss_label);
    163 
    164   // Load properties array.
    165   Register properties = scratch0;
    166   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    167   // Check that the properties array is a dictionary.
    168   __ ldr(map, FieldMemOperand(properties, HeapObject::kMapOffset));
    169   Register tmp = properties;
    170   __ LoadRoot(tmp, Heap::kHashTableMapRootIndex);
    171   __ cmp(map, tmp);
    172   __ b(ne, miss_label);
    173 
    174   // Restore the temporarily used register.
    175   __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
    176 
    177 
    178   NameDictionaryLookupStub::GenerateNegativeLookup(
    179       masm, miss_label, &done, receiver, properties, name, scratch1);
    180   __ bind(&done);
    181   __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
    182 }
    183 
    184 // Generate code to check that a global property cell is empty. Create
    185 // the property cell at compilation time if no cell exists for the
    186 // property.
    187 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
    188     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
    189     Register scratch, Label* miss) {
    190   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
    191       global, name, PropertyCellType::kInvalidated);
    192   Isolate* isolate = masm->isolate();
    193   DCHECK(cell->value()->IsTheHole(isolate));
    194   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
    195   __ LoadWeakValue(scratch, weak_cell, miss);
    196   __ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
    197   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
    198   __ cmp(scratch, ip);
    199   __ b(ne, miss);
    200 }
    201 
    202 static void CompileCallLoadPropertyWithInterceptor(
    203     MacroAssembler* masm, Register receiver, Register holder, Register name,
    204     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
    205   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
    206          Runtime::FunctionForId(id)->nargs);
    207 
    208   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    209   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    210   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    211   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    212   __ push(name);
    213   __ push(receiver);
    214   __ push(holder);
    215 
    216   __ CallRuntime(id);
    217 }
    218 
    219 
    220 // Generate call to api function.
    221 void PropertyHandlerCompiler::GenerateApiAccessorCall(
    222     MacroAssembler* masm, const CallOptimization& optimization,
    223     Handle<Map> receiver_map, Register receiver, Register scratch_in,
    224     bool is_store, Register store_parameter, Register accessor_holder,
    225     int accessor_index) {
    226   DCHECK(!accessor_holder.is(scratch_in));
    227   DCHECK(!receiver.is(scratch_in));
    228   __ push(receiver);
    229   // Write the arguments to stack frame.
    230   if (is_store) {
    231     DCHECK(!receiver.is(store_parameter));
    232     DCHECK(!scratch_in.is(store_parameter));
    233     __ push(store_parameter);
    234   }
    235   DCHECK(optimization.is_simple_api_call());
    236 
    237   // Abi for CallApiCallbackStub.
    238   Register callee = r0;
    239   Register data = r4;
    240   Register holder = r2;
    241   Register api_function_address = r1;
    242 
    243   // Put callee in place.
    244   __ LoadAccessor(callee, accessor_holder, accessor_index,
    245                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
    246 
    247   // Put holder in place.
    248   CallOptimization::HolderLookup holder_lookup;
    249   int holder_depth = 0;
    250   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
    251                                           &holder_depth);
    252   switch (holder_lookup) {
    253     case CallOptimization::kHolderIsReceiver:
    254       __ Move(holder, receiver);
    255       break;
    256     case CallOptimization::kHolderFound:
    257       __ ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
    258       __ ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
    259       for (int i = 1; i < holder_depth; i++) {
    260         __ ldr(holder, FieldMemOperand(holder, HeapObject::kMapOffset));
    261         __ ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
    262       }
    263       break;
    264     case CallOptimization::kHolderNotFound:
    265       UNREACHABLE();
    266       break;
    267   }
    268 
    269   Isolate* isolate = masm->isolate();
    270   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    271   bool call_data_undefined = false;
    272   // Put call data in place.
    273   if (api_call_info->data()->IsUndefined(isolate)) {
    274     call_data_undefined = true;
    275     __ LoadRoot(data, Heap::kUndefinedValueRootIndex);
    276   } else {
    277     if (optimization.is_constant_call()) {
    278       __ ldr(data,
    279              FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
    280       __ ldr(data,
    281              FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
    282       __ ldr(data,
    283              FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
    284     } else {
    285       __ ldr(data,
    286              FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
    287     }
    288     __ ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
    289   }
    290 
    291   if (api_call_info->fast_handler()->IsCode()) {
    292     // Just tail call into the fast handler if present.
    293     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
    294             RelocInfo::CODE_TARGET);
    295     return;
    296   }
    297 
    298   // Put api_function_address in place.
    299   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    300   ApiFunction fun(function_address);
    301   ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
    302   ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
    303   __ mov(api_function_address, Operand(ref));
    304 
    305   // Jump to stub.
    306   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
    307                            !optimization.is_constant_call());
    308   __ TailCallStub(&stub);
    309 }
    310 
    311 #undef __
    312 #define __ ACCESS_MASM(masm())
    313 
    314 
    315 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
    316                                                     Handle<Name> name) {
    317   if (!label->is_unused()) {
    318     __ bind(label);
    319     __ mov(this->name(), Operand(name));
    320   }
    321 }
    322 
    323 void PropertyHandlerCompiler::GenerateAccessCheck(
    324     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
    325     Label* miss, bool compare_native_contexts_only) {
    326   Label done;
    327   // Load current native context.
    328   __ ldr(scratch1, NativeContextMemOperand());
    329   // Load expected native context.
    330   __ LoadWeakValue(scratch2, native_context_cell, miss);
    331   __ cmp(scratch1, scratch2);
    332 
    333   if (!compare_native_contexts_only) {
    334     __ b(eq, &done);
    335 
    336     // Compare security tokens of current and expected native contexts.
    337     __ ldr(scratch1,
    338            ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
    339     __ ldr(scratch2,
    340            ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
    341     __ cmp(scratch1, scratch2);
    342   }
    343   __ b(ne, miss);
    344 
    345   __ bind(&done);
    346 }
    347 
    348 Register PropertyHandlerCompiler::CheckPrototypes(
    349     Register object_reg, Register holder_reg, Register scratch1,
    350     Register scratch2, Handle<Name> name, Label* miss,
    351     ReturnHolder return_what) {
    352   Handle<Map> receiver_map = map();
    353 
    354   // Make sure there's no overlap between holder and object registers.
    355   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
    356   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
    357          !scratch2.is(scratch1));
    358 
    359   Handle<Cell> validity_cell =
    360       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
    361   if (!validity_cell.is_null()) {
    362     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
    363     __ mov(scratch1, Operand(validity_cell));
    364     __ ldr(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset));
    365     __ cmp(scratch1, Operand(Smi::FromInt(Map::kPrototypeChainValid)));
    366     __ b(ne, miss);
    367   }
    368 
    369   // Keep track of the current object in register reg.
    370   Register reg = object_reg;
    371   int depth = 0;
    372 
    373   Handle<JSObject> current = Handle<JSObject>::null();
    374   if (receiver_map->IsJSGlobalObjectMap()) {
    375     current = isolate()->global_object();
    376   }
    377 
    378   Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
    379                           isolate());
    380   Handle<Map> holder_map(holder()->map());
    381   // Traverse the prototype chain and check the maps in the prototype chain for
    382   // fast and global objects or do negative lookup for normal objects.
    383   while (!current_map.is_identical_to(holder_map)) {
    384     ++depth;
    385 
    386     if (current_map->IsJSGlobalObjectMap()) {
    387       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
    388                                 name, scratch2, miss);
    389     } else if (current_map->is_dictionary_map()) {
    390       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
    391       DCHECK(name->IsUniqueName());
    392       DCHECK(current.is_null() ||
    393              current->property_dictionary()->FindEntry(name) ==
    394                  NameDictionary::kNotFound);
    395 
    396       if (depth > 1) {
    397         Handle<WeakCell> weak_cell =
    398             Map::GetOrCreatePrototypeWeakCell(current, isolate());
    399         __ LoadWeakValue(reg, weak_cell, miss);
    400       }
    401       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
    402                                        scratch2);
    403     }
    404 
    405     reg = holder_reg;  // From now on the object will be in holder_reg.
    406     // Go to the next object in the prototype chain.
    407     current = handle(JSObject::cast(current_map->prototype()));
    408     current_map = handle(current->map());
    409   }
    410 
    411   DCHECK(!current_map->IsJSGlobalProxyMap());
    412 
    413   // Log the check depth.
    414   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
    415 
    416   bool return_holder = return_what == RETURN_HOLDER;
    417   if (return_holder && depth != 0) {
    418     Handle<WeakCell> weak_cell =
    419         Map::GetOrCreatePrototypeWeakCell(current, isolate());
    420     __ LoadWeakValue(reg, weak_cell, miss);
    421   }
    422 
    423   // Return the register containing the holder.
    424   return return_holder ? reg : no_reg;
    425 }
    426 
    427 
    428 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    429   if (!miss->is_unused()) {
    430     Label success;
    431     __ b(&success);
    432     __ bind(miss);
    433     if (IC::ICUseVector(kind())) {
    434       DCHECK(kind() == Code::LOAD_IC);
    435       PopVectorAndSlot();
    436     }
    437     TailCallBuiltin(masm(), MissBuiltin(kind()));
    438     __ bind(&success);
    439   }
    440 }
    441 
    442 
    443 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    444   if (!miss->is_unused()) {
    445     Label success;
    446     __ b(&success);
    447     GenerateRestoreName(miss, name);
    448     if (IC::ICUseVector(kind())) PopVectorAndSlot();
    449     TailCallBuiltin(masm(), MissBuiltin(kind()));
    450     __ bind(&success);
    451   }
    452 }
    453 
    454 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
    455     LookupIterator* it, Register holder_reg) {
    456   DCHECK(holder()->HasNamedInterceptor());
    457   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    458 
    459   // Compile the interceptor call, followed by inline code to load the
    460   // property from further up the prototype chain if the call fails.
    461   // Check that the maps haven't changed.
    462   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
    463 
    464   // Preserve the receiver register explicitly whenever it is different from the
    465   // holder and it is needed should the interceptor return without any result.
    466   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
    467   // case might cause a miss during the prototype check.
    468   bool must_perform_prototype_check =
    469       !holder().is_identical_to(it->GetHolder<JSObject>());
    470   bool must_preserve_receiver_reg =
    471       !receiver().is(holder_reg) &&
    472       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
    473 
    474   // Save necessary data before invoking an interceptor.
    475   // Requires a frame to make GC aware of pushed pointers.
    476   {
    477     FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
    478     if (must_preserve_receiver_reg) {
    479       __ Push(receiver(), holder_reg, this->name());
    480     } else {
    481       __ Push(holder_reg, this->name());
    482     }
    483     InterceptorVectorSlotPush(holder_reg);
    484     // Invoke an interceptor.  Note: map checks from receiver to
    485     // interceptor's holder has been compiled before (see a caller
    486     // of this method.)
    487     CompileCallLoadPropertyWithInterceptor(
    488         masm(), receiver(), holder_reg, this->name(), holder(),
    489         Runtime::kLoadPropertyWithInterceptorOnly);
    490 
    491     // Check if interceptor provided a value for property.  If it's
    492     // the case, return immediately.
    493     Label interceptor_failed;
    494     __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
    495     __ cmp(r0, scratch1());
    496     __ b(eq, &interceptor_failed);
    497     frame_scope.GenerateLeaveFrame();
    498     __ Ret();
    499 
    500     __ bind(&interceptor_failed);
    501     InterceptorVectorSlotPop(holder_reg);
    502     __ pop(this->name());
    503     __ pop(holder_reg);
    504     if (must_preserve_receiver_reg) {
    505       __ pop(receiver());
    506     }
    507     // Leave the internal frame.
    508   }
    509 
    510   GenerateLoadPostInterceptor(it, holder_reg);
    511 }
    512 
    513 
    514 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
    515   // Call the runtime system to load the interceptor.
    516   DCHECK(holder()->HasNamedInterceptor());
    517   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    518 
    519   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    520   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    521   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    522   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    523   __ Push(name(), receiver(), holder_reg);
    524   // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
    525   if (holder_reg.is(receiver())) {
    526     __ Push(slot(), vector());
    527   } else {
    528     __ Push(scratch3(), scratch2());  // slot, vector
    529   }
    530 
    531   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
    532 }
    533 
    534 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
    535   STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
    536 }
    537 
    538 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    539     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
    540     LanguageMode language_mode) {
    541   Register holder_reg = Frontend(name);
    542 
    543   __ push(receiver());  // receiver
    544   __ push(holder_reg);
    545 
    546   // If the callback cannot leak, then push the callback directly,
    547   // otherwise wrap it in a weak cell.
    548   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
    549     __ mov(ip, Operand(callback));
    550   } else {
    551     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
    552     __ mov(ip, Operand(cell));
    553   }
    554   __ push(ip);
    555   __ mov(ip, Operand(name));
    556   __ Push(ip, value());
    557   __ Push(Smi::FromInt(language_mode));
    558 
    559   // Do tail-call to the runtime system.
    560   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
    561 
    562   // Return the generated code.
    563   return GetCode(kind(), name);
    564 }
    565 
    566 
    567 Register NamedStoreHandlerCompiler::value() {
    568   return StoreDescriptor::ValueRegister();
    569 }
    570 
    571 
    572 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
    573     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
    574   Label miss;
    575   if (IC::ICUseVector(kind())) {
    576     PushVectorAndSlot();
    577   }
    578   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    579 
    580   // Get the value from the cell.
    581   Register result = StoreDescriptor::ValueRegister();
    582   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
    583   __ LoadWeakValue(result, weak_cell, &miss);
    584   __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
    585 
    586   // Check for deleted property if property can actually be deleted.
    587   if (is_configurable) {
    588     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
    589     __ cmp(result, ip);
    590     __ b(eq, &miss);
    591   }
    592 
    593   Counters* counters = isolate()->counters();
    594   __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r1, r3);
    595   if (IC::ICUseVector(kind())) {
    596     DiscardVectorAndSlot();
    597   }
    598   __ Ret();
    599 
    600   FrontendFooter(name, &miss);
    601 
    602   // Return the generated code.
    603   return GetCode(kind(), name);
    604 }
    605 
    606 
    607 #undef __
    608 }  // namespace internal
    609 }  // namespace v8
    610 
    611 #endif  // V8_TARGET_ARCH_ARM
    612