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