Home | History | Annotate | Download | only in x87
      1 // Copyright 2012 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_X87
      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   {
     25     FrameScope scope(masm, StackFrame::INTERNAL);
     26 
     27     // Save context register
     28     __ push(esi);
     29 
     30     if (accessor_index >= 0) {
     31       DCHECK(!holder.is(scratch));
     32       DCHECK(!receiver.is(scratch));
     33       // Call the JavaScript getter with the receiver on the stack.
     34       if (map->IsJSGlobalObjectMap()) {
     35         // Swap in the global receiver.
     36         __ mov(scratch,
     37                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
     38         receiver = scratch;
     39       }
     40       __ push(receiver);
     41       __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER);
     42       __ Set(eax, 0);
     43       __ Call(masm->isolate()->builtins()->CallFunction(
     44                   ConvertReceiverMode::kNotNullOrUndefined),
     45               RelocInfo::CODE_TARGET);
     46     } else {
     47       // If we generate a global code snippet for deoptimization only, remember
     48       // the place to continue after deoptimization.
     49       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
     50     }
     51 
     52     // Restore context register.
     53     __ pop(esi);
     54   }
     55   __ ret(0);
     56 }
     57 
     58 
     59 void PropertyHandlerCompiler::PushVectorAndSlot(Register vector,
     60                                                 Register slot) {
     61   MacroAssembler* masm = this->masm();
     62   STATIC_ASSERT(LoadWithVectorDescriptor::kSlot <
     63                 LoadWithVectorDescriptor::kVector);
     64   STATIC_ASSERT(StoreWithVectorDescriptor::kSlot <
     65                 StoreWithVectorDescriptor::kVector);
     66   STATIC_ASSERT(StoreTransitionDescriptor::kSlot <
     67                 StoreTransitionDescriptor::kVector);
     68   __ push(slot);
     69   __ push(vector);
     70 }
     71 
     72 
     73 void PropertyHandlerCompiler::PopVectorAndSlot(Register vector, Register slot) {
     74   MacroAssembler* masm = this->masm();
     75   __ pop(vector);
     76   __ pop(slot);
     77 }
     78 
     79 
     80 void PropertyHandlerCompiler::DiscardVectorAndSlot() {
     81   MacroAssembler* masm = this->masm();
     82   // Remove vector and slot.
     83   __ add(esp, Immediate(2 * kPointerSize));
     84 }
     85 
     86 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     87     MacroAssembler* masm, Label* miss_label, Register receiver,
     88     Handle<Name> name, Register scratch0, Register scratch1) {
     89   DCHECK(name->IsUniqueName());
     90   DCHECK(!receiver.is(scratch0));
     91   Counters* counters = masm->isolate()->counters();
     92   __ IncrementCounter(counters->negative_lookups(), 1);
     93   __ IncrementCounter(counters->negative_lookups_miss(), 1);
     94 
     95   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
     96 
     97   const int kInterceptorOrAccessCheckNeededMask =
     98       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
     99 
    100   // Bail out if the receiver has a named interceptor or requires access checks.
    101   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
    102             Immediate(kInterceptorOrAccessCheckNeededMask));
    103   __ j(not_zero, miss_label);
    104 
    105   // Check that receiver is a JSObject.
    106   __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
    107   __ j(below, miss_label);
    108 
    109   // Load properties array.
    110   Register properties = scratch0;
    111   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
    112 
    113   // Check that the properties array is a dictionary.
    114   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
    115          Immediate(masm->isolate()->factory()->hash_table_map()));
    116   __ j(not_equal, miss_label);
    117 
    118   Label done;
    119   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
    120                                                    properties, name, scratch1);
    121   __ bind(&done);
    122   __ DecrementCounter(counters->negative_lookups_miss(), 1);
    123 }
    124 
    125 // Generate call to api function.
    126 // This function uses push() to generate smaller, faster code than
    127 // the version above. It is an optimization that should will be removed
    128 // when api call ICs are generated in hydrogen.
    129 void PropertyHandlerCompiler::GenerateApiAccessorCall(
    130     MacroAssembler* masm, const CallOptimization& optimization,
    131     Handle<Map> receiver_map, Register receiver, Register scratch,
    132     bool is_store, Register store_parameter, Register accessor_holder,
    133     int accessor_index) {
    134   DCHECK(!accessor_holder.is(scratch));
    135   // Copy return value.
    136   __ pop(scratch);
    137 
    138   if (is_store) {
    139     // Discard stack arguments.
    140     __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
    141                           kPointerSize));
    142   }
    143   // Write the receiver and arguments to stack frame.
    144   __ push(receiver);
    145   if (is_store) {
    146     DCHECK(!AreAliased(receiver, scratch, store_parameter));
    147     __ push(store_parameter);
    148   }
    149   __ push(scratch);
    150   // Stack now matches JSFunction abi.
    151   DCHECK(optimization.is_simple_api_call());
    152 
    153   // Abi for CallApiCallbackStub.
    154   Register callee = edi;
    155   Register data = ebx;
    156   Register holder = ecx;
    157   Register api_function_address = edx;
    158   scratch = no_reg;
    159 
    160   // Put callee in place.
    161   __ LoadAccessor(callee, accessor_holder, accessor_index,
    162                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
    163 
    164   // Put holder in place.
    165   CallOptimization::HolderLookup holder_lookup;
    166   int holder_depth = 0;
    167   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
    168                                           &holder_depth);
    169   switch (holder_lookup) {
    170     case CallOptimization::kHolderIsReceiver:
    171       __ Move(holder, receiver);
    172       break;
    173     case CallOptimization::kHolderFound:
    174       __ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset));
    175       __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
    176       for (int i = 1; i < holder_depth; i++) {
    177         __ mov(holder, FieldOperand(holder, HeapObject::kMapOffset));
    178         __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
    179       }
    180       break;
    181     case CallOptimization::kHolderNotFound:
    182       UNREACHABLE();
    183       break;
    184   }
    185 
    186   Isolate* isolate = masm->isolate();
    187   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    188   bool call_data_undefined = false;
    189   // Put call data in place.
    190   if (api_call_info->data()->IsUndefined(isolate)) {
    191     call_data_undefined = true;
    192     __ mov(data, Immediate(isolate->factory()->undefined_value()));
    193   } else {
    194     if (optimization.is_constant_call()) {
    195       __ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
    196       __ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
    197       __ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
    198     } else {
    199       __ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
    200     }
    201     __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
    202   }
    203 
    204   if (api_call_info->fast_handler()->IsCode()) {
    205     // Just tail call into the code.
    206     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
    207             RelocInfo::CODE_TARGET);
    208     return;
    209   }
    210   // Put api_function_address in place.
    211   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    212   __ mov(api_function_address, Immediate(function_address));
    213 
    214   // Jump to stub.
    215   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
    216                            !optimization.is_constant_call());
    217   __ TailCallStub(&stub);
    218 }
    219 
    220 
    221 // Generate code to check that a global property cell is empty. Create
    222 // the property cell at compilation time if no cell exists for the
    223 // property.
    224 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
    225     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
    226     Register scratch, Label* miss) {
    227   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
    228       global, name, PropertyCellType::kInvalidated);
    229   Isolate* isolate = masm->isolate();
    230   DCHECK(cell->value()->IsTheHole(isolate));
    231   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
    232   __ LoadWeakValue(scratch, weak_cell, miss);
    233   __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
    234          Immediate(isolate->factory()->the_hole_value()));
    235   __ j(not_equal, miss);
    236 }
    237 
    238 
    239 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
    240     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
    241     int accessor_index, int expected_arguments, Register scratch) {
    242   // ----------- S t a t e -------------
    243   //  -- esp[12] : value
    244   //  -- esp[8]  : slot
    245   //  -- esp[4]  : vector
    246   //  -- esp[0]  : return address
    247   // -----------------------------------
    248   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
    249 
    250   {
    251     FrameScope scope(masm, StackFrame::INTERNAL);
    252 
    253     // Save context register
    254     __ push(esi);
    255     // Save value register, so we can restore it later.
    256     __ push(value());
    257 
    258     if (accessor_index >= 0) {
    259       DCHECK(!holder.is(scratch));
    260       DCHECK(!receiver.is(scratch));
    261       DCHECK(!value().is(scratch));
    262       // Call the JavaScript setter with receiver and value on the stack.
    263       if (map->IsJSGlobalObjectMap()) {
    264         __ mov(scratch,
    265                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
    266         receiver = scratch;
    267       }
    268       __ push(receiver);
    269       __ push(value());
    270       __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER);
    271       __ Set(eax, 1);
    272       __ Call(masm->isolate()->builtins()->CallFunction(
    273                   ConvertReceiverMode::kNotNullOrUndefined),
    274               RelocInfo::CODE_TARGET);
    275     } else {
    276       // If we generate a global code snippet for deoptimization only, remember
    277       // the place to continue after deoptimization.
    278       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
    279     }
    280 
    281     // We have to return the passed value, not the return value of the setter.
    282     __ pop(eax);
    283     // Restore context register.
    284     __ pop(esi);
    285   }
    286   if (accessor_index >= 0) {
    287     __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
    288   } else {
    289     // If we generate a global code snippet for deoptimization only, don't try
    290     // to drop stack arguments for the StoreIC because they are not a part of
    291     // expression stack and deoptimizer does not reconstruct them.
    292     __ ret(0);
    293   }
    294 }
    295 
    296 static void CompileCallLoadPropertyWithInterceptor(
    297     MacroAssembler* masm, Register receiver, Register holder, Register name,
    298     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
    299   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
    300          Runtime::FunctionForId(id)->nargs);
    301 
    302   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    303   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    304   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    305   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    306   __ push(name);
    307   __ push(receiver);
    308   __ push(holder);
    309 
    310   __ CallRuntime(id);
    311 }
    312 
    313 #undef __
    314 #define __ ACCESS_MASM(masm())
    315 
    316 
    317 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
    318                                                     Handle<Name> name) {
    319   if (!label->is_unused()) {
    320     __ bind(label);
    321     __ mov(this->name(), Immediate(name));
    322   }
    323 }
    324 
    325 void PropertyHandlerCompiler::GenerateAccessCheck(
    326     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
    327     Label* miss, bool compare_native_contexts_only) {
    328   Label done;
    329   // Load current native context.
    330   __ mov(scratch1, NativeContextOperand());
    331   // Load expected native context.
    332   __ LoadWeakValue(scratch2, native_context_cell, miss);
    333   __ cmp(scratch1, scratch2);
    334 
    335   if (!compare_native_contexts_only) {
    336     __ j(equal, &done);
    337 
    338     // Compare security tokens of current and expected native contexts.
    339     __ mov(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
    340     __ mov(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
    341     __ cmp(scratch1, scratch2);
    342   }
    343   __ j(not_equal, 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     // Operand::ForCell(...) points to the cell's payload!
    364     __ cmp(Operand::ForCell(validity_cell),
    365            Immediate(Smi::FromInt(Map::kPrototypeChainValid)));
    366     __ j(not_equal, 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     __ jmp(&success);
    432     __ bind(miss);
    433     if (IC::ShouldPushPopSlotAndVector(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     __ jmp(&success);
    447     GenerateRestoreName(miss, name);
    448     DCHECK(!IC::ShouldPushPopSlotAndVector(kind()));
    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     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
    478 
    479     if (must_preserve_receiver_reg) {
    480       __ push(receiver());
    481     }
    482     __ push(holder_reg);
    483     __ push(this->name());
    484     InterceptorVectorSlotPush(holder_reg);
    485     // Invoke an interceptor.  Note: map checks from receiver to
    486     // interceptor's holder has been compiled before (see a caller
    487     // of this method.)
    488     CompileCallLoadPropertyWithInterceptor(
    489         masm(), receiver(), holder_reg, this->name(), holder(),
    490         Runtime::kLoadPropertyWithInterceptorOnly);
    491 
    492     // Check if interceptor provided a value for property.  If it's
    493     // the case, return immediately.
    494     Label interceptor_failed;
    495     __ cmp(eax, factory()->no_interceptor_result_sentinel());
    496     __ j(equal, &interceptor_failed);
    497     frame_scope.GenerateLeaveFrame();
    498     __ ret(0);
    499 
    500     // Clobber registers when generating debug-code to provoke errors.
    501     __ bind(&interceptor_failed);
    502     if (FLAG_debug_code) {
    503       __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
    504       __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
    505       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
    506     }
    507 
    508     InterceptorVectorSlotPop(holder_reg);
    509     __ pop(this->name());
    510     __ pop(holder_reg);
    511     if (must_preserve_receiver_reg) {
    512       __ pop(receiver());
    513     }
    514 
    515     // Leave the internal frame.
    516   }
    517 
    518   GenerateLoadPostInterceptor(it, holder_reg);
    519 }
    520 
    521 
    522 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
    523   DCHECK(holder()->HasNamedInterceptor());
    524   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    525   // Call the runtime system to load the interceptor.
    526 
    527   // Stack:
    528   //   return address
    529 
    530   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    531   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    532   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    533   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    534   __ push(receiver());
    535   __ push(holder_reg);
    536   // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
    537   if (holder_reg.is(receiver())) {
    538     __ push(slot());
    539     __ push(vector());
    540   } else {
    541     __ push(scratch3());  // slot
    542     __ push(scratch2());  // vector
    543   }
    544   __ push(Operand(esp, 4 * kPointerSize));  // return address
    545   __ mov(Operand(esp, 5 * kPointerSize), name());
    546 
    547   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
    548 }
    549 
    550 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
    551   // Zap register aliases of the arguments passed on the stack to ensure they
    552   // are properly loaded by the handler (debug-only).
    553   STATIC_ASSERT(Descriptor::kPassLastArgsOnStack);
    554   STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
    555   __ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue));
    556   __ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue));
    557   __ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue));
    558 }
    559 
    560 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    561     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
    562     LanguageMode language_mode) {
    563   Register holder_reg = Frontend(name);
    564   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
    565 
    566   __ pop(scratch1());  // remove the return address
    567   // Discard stack arguments.
    568   __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
    569                         kPointerSize));
    570   __ push(receiver());
    571   __ push(holder_reg);
    572   // If the callback cannot leak, then push the callback directly,
    573   // otherwise wrap it in a weak cell.
    574   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
    575     __ Push(callback);
    576   } else {
    577     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
    578     __ Push(cell);
    579   }
    580   __ Push(name);
    581   __ push(value());
    582   __ push(Immediate(Smi::FromInt(language_mode)));
    583   __ push(scratch1());  // restore return address
    584 
    585   // Do tail-call to the runtime system.
    586   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
    587 
    588   // Return the generated code.
    589   return GetCode(kind(), name);
    590 }
    591 
    592 
    593 Register NamedStoreHandlerCompiler::value() {
    594   return StoreDescriptor::ValueRegister();
    595 }
    596 
    597 
    598 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
    599     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
    600   Label miss;
    601   if (IC::ShouldPushPopSlotAndVector(kind())) {
    602     PushVectorAndSlot();
    603   }
    604   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    605   // Get the value from the cell.
    606   Register result = StoreDescriptor::ValueRegister();
    607   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
    608   __ LoadWeakValue(result, weak_cell, &miss);
    609   __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
    610 
    611   // Check for deleted property if property can actually be deleted.
    612   if (is_configurable) {
    613     __ cmp(result, factory()->the_hole_value());
    614     __ j(equal, &miss);
    615   } else if (FLAG_debug_code) {
    616     __ cmp(result, factory()->the_hole_value());
    617     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
    618   }
    619 
    620   Counters* counters = isolate()->counters();
    621   __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
    622   // The code above already loads the result into the return register.
    623   if (IC::ShouldPushPopSlotAndVector(kind())) {
    624     DiscardVectorAndSlot();
    625   }
    626   __ ret(0);
    627 
    628   FrontendFooter(name, &miss);
    629 
    630   // Return the generated code.
    631   return GetCode(kind(), name);
    632 }
    633 
    634 
    635 #undef __
    636 }  // namespace internal
    637 }  // namespace v8
    638 
    639 #endif  // V8_TARGET_ARCH_X87
    640