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