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