Home | History | Annotate | Download | only in ia32
      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_IA32
      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::PushReturnAddress(Register tmp) {
     87   MacroAssembler* masm = this->masm();
     88   __ push(tmp);
     89 }
     90 
     91 void PropertyHandlerCompiler::PopReturnAddress(Register tmp) {
     92   MacroAssembler* masm = this->masm();
     93   __ pop(tmp);
     94 }
     95 
     96 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     97     MacroAssembler* masm, Label* miss_label, Register receiver,
     98     Handle<Name> name, Register scratch0, Register scratch1) {
     99   DCHECK(name->IsUniqueName());
    100   DCHECK(!receiver.is(scratch0));
    101   Counters* counters = masm->isolate()->counters();
    102   __ IncrementCounter(counters->negative_lookups(), 1);
    103   __ IncrementCounter(counters->negative_lookups_miss(), 1);
    104 
    105   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
    106 
    107   const int kInterceptorOrAccessCheckNeededMask =
    108       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
    109 
    110   // Bail out if the receiver has a named interceptor or requires access checks.
    111   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
    112             Immediate(kInterceptorOrAccessCheckNeededMask));
    113   __ j(not_zero, miss_label);
    114 
    115   // Check that receiver is a JSObject.
    116   __ CmpInstanceType(scratch0, FIRST_JS_RECEIVER_TYPE);
    117   __ j(below, miss_label);
    118 
    119   // Load properties array.
    120   Register properties = scratch0;
    121   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
    122 
    123   // Check that the properties array is a dictionary.
    124   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
    125          Immediate(masm->isolate()->factory()->hash_table_map()));
    126   __ j(not_equal, miss_label);
    127 
    128   Label done;
    129   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
    130                                                    properties, name, scratch1);
    131   __ bind(&done);
    132   __ DecrementCounter(counters->negative_lookups_miss(), 1);
    133 }
    134 
    135 
    136 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
    137     MacroAssembler* masm, int index, Register result, Label* miss) {
    138   __ LoadGlobalFunction(index, result);
    139   // Load its initial map. The global functions all have initial maps.
    140   __ mov(result,
    141          FieldOperand(result, JSFunction::kPrototypeOrInitialMapOffset));
    142   // Load the prototype from the initial map.
    143   __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
    144 }
    145 
    146 
    147 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
    148     MacroAssembler* masm, Register receiver, Register scratch1,
    149     Register scratch2, Label* miss_label) {
    150   // TODO(mvstanton): This isn't used on ia32. Move all the other
    151   // platform implementations into a code stub so this method can be removed.
    152   UNREACHABLE();
    153 }
    154 
    155 
    156 // Generate call to api function.
    157 // This function uses push() to generate smaller, faster code than
    158 // the version above. It is an optimization that should will be removed
    159 // when api call ICs are generated in hydrogen.
    160 void PropertyHandlerCompiler::GenerateApiAccessorCall(
    161     MacroAssembler* masm, const CallOptimization& optimization,
    162     Handle<Map> receiver_map, Register receiver, Register scratch,
    163     bool is_store, Register store_parameter, Register accessor_holder,
    164     int accessor_index) {
    165   DCHECK(!accessor_holder.is(scratch));
    166   // Copy return value.
    167   __ pop(scratch);
    168 
    169   if (is_store) {
    170     // Discard stack arguments.
    171     __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
    172                           kPointerSize));
    173   }
    174   // Write the receiver and arguments to stack frame.
    175   __ push(receiver);
    176   if (is_store) {
    177     DCHECK(!AreAliased(receiver, scratch, store_parameter));
    178     __ push(store_parameter);
    179   }
    180   __ push(scratch);
    181   // Stack now matches JSFunction abi.
    182   DCHECK(optimization.is_simple_api_call());
    183 
    184   // Abi for CallApiCallbackStub.
    185   Register callee = edi;
    186   Register data = ebx;
    187   Register holder = ecx;
    188   Register api_function_address = edx;
    189   scratch = no_reg;
    190 
    191   // Put callee in place.
    192   __ LoadAccessor(callee, accessor_holder, accessor_index,
    193                   is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
    194 
    195   // Put holder in place.
    196   CallOptimization::HolderLookup holder_lookup;
    197   int holder_depth = 0;
    198   optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup,
    199                                           &holder_depth);
    200   switch (holder_lookup) {
    201     case CallOptimization::kHolderIsReceiver:
    202       __ Move(holder, receiver);
    203       break;
    204     case CallOptimization::kHolderFound:
    205       __ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset));
    206       __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
    207       for (int i = 1; i < holder_depth; i++) {
    208         __ mov(holder, FieldOperand(holder, HeapObject::kMapOffset));
    209         __ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
    210       }
    211       break;
    212     case CallOptimization::kHolderNotFound:
    213       UNREACHABLE();
    214       break;
    215   }
    216 
    217   Isolate* isolate = masm->isolate();
    218   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    219   bool call_data_undefined = false;
    220   // Put call data in place.
    221   if (api_call_info->data()->IsUndefined(isolate)) {
    222     call_data_undefined = true;
    223     __ mov(data, Immediate(isolate->factory()->undefined_value()));
    224   } else {
    225     if (optimization.is_constant_call()) {
    226       __ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
    227       __ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
    228       __ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
    229     } else {
    230       __ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
    231     }
    232     __ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
    233   }
    234 
    235   if (api_call_info->fast_handler()->IsCode()) {
    236     // Just tail call into the code.
    237     __ Jump(handle(Code::cast(api_call_info->fast_handler())),
    238             RelocInfo::CODE_TARGET);
    239     return;
    240   }
    241   // Put api_function_address in place.
    242   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    243   __ mov(api_function_address, Immediate(function_address));
    244 
    245   // Jump to stub.
    246   CallApiCallbackStub stub(isolate, is_store, call_data_undefined,
    247                            !optimization.is_constant_call());
    248   __ TailCallStub(&stub);
    249 }
    250 
    251 
    252 // Generate code to check that a global property cell is empty. Create
    253 // the property cell at compilation time if no cell exists for the
    254 // property.
    255 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
    256     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
    257     Register scratch, Label* miss) {
    258   Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
    259       global, name, PropertyCellType::kInvalidated);
    260   Isolate* isolate = masm->isolate();
    261   DCHECK(cell->value()->IsTheHole(isolate));
    262   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
    263   __ LoadWeakValue(scratch, weak_cell, miss);
    264   __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
    265          Immediate(isolate->factory()->the_hole_value()));
    266   __ j(not_equal, miss);
    267 }
    268 
    269 
    270 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
    271     MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
    272     int accessor_index, int expected_arguments, Register scratch) {
    273   // ----------- S t a t e -------------
    274   //  -- esp[12] : value
    275   //  -- esp[8]  : slot
    276   //  -- esp[4]  : vector
    277   //  -- esp[0]  : return address
    278   // -----------------------------------
    279   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
    280 
    281   {
    282     FrameScope scope(masm, StackFrame::INTERNAL);
    283 
    284     // Save context register
    285     __ push(esi);
    286     // Save value register, so we can restore it later.
    287     __ push(value());
    288 
    289     if (accessor_index >= 0) {
    290       DCHECK(!holder.is(scratch));
    291       DCHECK(!receiver.is(scratch));
    292       DCHECK(!value().is(scratch));
    293       // Call the JavaScript setter with receiver and value on the stack.
    294       if (map->IsJSGlobalObjectMap()) {
    295         __ mov(scratch,
    296                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
    297         receiver = scratch;
    298       }
    299       __ push(receiver);
    300       __ push(value());
    301       __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_SETTER);
    302       __ Set(eax, 1);
    303       __ Call(masm->isolate()->builtins()->CallFunction(
    304                   ConvertReceiverMode::kNotNullOrUndefined),
    305               RelocInfo::CODE_TARGET);
    306     } else {
    307       // If we generate a global code snippet for deoptimization only, remember
    308       // the place to continue after deoptimization.
    309       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
    310     }
    311 
    312     // We have to return the passed value, not the return value of the setter.
    313     __ pop(eax);
    314     // Restore context register.
    315     __ pop(esi);
    316   }
    317   if (accessor_index >= 0) {
    318     __ ret(StoreWithVectorDescriptor::kStackArgumentsCount * kPointerSize);
    319   } else {
    320     // If we generate a global code snippet for deoptimization only, don't try
    321     // to drop stack arguments for the StoreIC because they are not a part of
    322     // expression stack and deoptimizer does not reconstruct them.
    323     __ ret(0);
    324   }
    325 }
    326 
    327 
    328 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
    329                                      Register holder, Register name,
    330                                      Handle<JSObject> holder_obj) {
    331   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    332   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
    333   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
    334   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
    335   __ push(name);
    336   __ push(receiver);
    337   __ push(holder);
    338 }
    339 
    340 
    341 static void CompileCallLoadPropertyWithInterceptor(
    342     MacroAssembler* masm, Register receiver, Register holder, Register name,
    343     Handle<JSObject> holder_obj, Runtime::FunctionId id) {
    344   DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
    345          Runtime::FunctionForId(id)->nargs);
    346   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    347   __ CallRuntime(id);
    348 }
    349 
    350 #undef __
    351 #define __ ACCESS_MASM(masm())
    352 
    353 
    354 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
    355                                                     Handle<Name> name) {
    356   if (!label->is_unused()) {
    357     __ bind(label);
    358     __ mov(this->name(), Immediate(name));
    359   }
    360 }
    361 
    362 
    363 void NamedStoreHandlerCompiler::GenerateRestoreName(Handle<Name> name) {
    364   __ mov(this->name(), Immediate(name));
    365 }
    366 
    367 
    368 void NamedStoreHandlerCompiler::GenerateRestoreMap(Handle<Map> transition,
    369                                                    Register map_reg,
    370                                                    Register scratch,
    371                                                    Label* miss) {
    372   Handle<WeakCell> cell = Map::WeakCellForMap(transition);
    373   DCHECK(!map_reg.is(scratch));
    374   __ LoadWeakValue(map_reg, cell, miss);
    375   if (transition->CanBeDeprecated()) {
    376     __ mov(scratch, FieldOperand(map_reg, Map::kBitField3Offset));
    377     __ and_(scratch, Immediate(Map::Deprecated::kMask));
    378     __ j(not_zero, miss);
    379   }
    380 }
    381 
    382 
    383 void NamedStoreHandlerCompiler::GenerateConstantCheck(Register map_reg,
    384                                                       int descriptor,
    385                                                       Register value_reg,
    386                                                       Register scratch,
    387                                                       Label* miss_label) {
    388   DCHECK(!map_reg.is(scratch));
    389   DCHECK(!map_reg.is(value_reg));
    390   DCHECK(!value_reg.is(scratch));
    391   __ LoadInstanceDescriptors(map_reg, scratch);
    392   __ mov(scratch,
    393          FieldOperand(scratch, DescriptorArray::GetValueOffset(descriptor)));
    394   __ cmp(value_reg, scratch);
    395   __ j(not_equal, miss_label);
    396 }
    397 
    398 void NamedStoreHandlerCompiler::GenerateFieldTypeChecks(FieldType* field_type,
    399                                                         Register value_reg,
    400                                                         Label* miss_label) {
    401   Register map_reg = scratch1();
    402   Register scratch = scratch2();
    403   DCHECK(!value_reg.is(map_reg));
    404   DCHECK(!value_reg.is(scratch));
    405   __ JumpIfSmi(value_reg, miss_label);
    406   if (field_type->IsClass()) {
    407     __ mov(map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
    408     __ CmpWeakValue(map_reg, Map::WeakCellForMap(field_type->AsClass()),
    409                     scratch);
    410     __ j(not_equal, miss_label);
    411   }
    412 }
    413 
    414 void PropertyHandlerCompiler::GenerateAccessCheck(
    415     Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2,
    416     Label* miss, bool compare_native_contexts_only) {
    417   Label done;
    418   // Load current native context.
    419   __ mov(scratch1, NativeContextOperand());
    420   // Load expected native context.
    421   __ LoadWeakValue(scratch2, native_context_cell, miss);
    422   __ cmp(scratch1, scratch2);
    423 
    424   if (!compare_native_contexts_only) {
    425     __ j(equal, &done);
    426 
    427     // Compare security tokens of current and expected native contexts.
    428     __ mov(scratch1, ContextOperand(scratch1, Context::SECURITY_TOKEN_INDEX));
    429     __ mov(scratch2, ContextOperand(scratch2, Context::SECURITY_TOKEN_INDEX));
    430     __ cmp(scratch1, scratch2);
    431   }
    432   __ j(not_equal, miss);
    433 
    434   __ bind(&done);
    435 }
    436 
    437 Register PropertyHandlerCompiler::CheckPrototypes(
    438     Register object_reg, Register holder_reg, Register scratch1,
    439     Register scratch2, Handle<Name> name, Label* miss,
    440     ReturnHolder return_what) {
    441   Handle<Map> receiver_map = map();
    442 
    443   // Make sure there's no overlap between holder and object registers.
    444   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
    445   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
    446          !scratch2.is(scratch1));
    447 
    448   Handle<Cell> validity_cell =
    449       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
    450   if (!validity_cell.is_null()) {
    451     DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value());
    452     // Operand::ForCell(...) points to the cell's payload!
    453     __ cmp(Operand::ForCell(validity_cell),
    454            Immediate(Smi::FromInt(Map::kPrototypeChainValid)));
    455     __ j(not_equal, miss);
    456   }
    457 
    458   // Keep track of the current object in register reg.
    459   Register reg = object_reg;
    460   int depth = 0;
    461 
    462   Handle<JSObject> current = Handle<JSObject>::null();
    463   if (receiver_map->IsJSGlobalObjectMap()) {
    464     current = isolate()->global_object();
    465   }
    466 
    467   Handle<Map> current_map(receiver_map->GetPrototypeChainRootMap(isolate()),
    468                           isolate());
    469   Handle<Map> holder_map(holder()->map());
    470   // Traverse the prototype chain and check the maps in the prototype chain for
    471   // fast and global objects or do negative lookup for normal objects.
    472   while (!current_map.is_identical_to(holder_map)) {
    473     ++depth;
    474 
    475     if (current_map->IsJSGlobalObjectMap()) {
    476       GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
    477                                 name, scratch2, miss);
    478     } else if (current_map->is_dictionary_map()) {
    479       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
    480       DCHECK(name->IsUniqueName());
    481       DCHECK(current.is_null() ||
    482              current->property_dictionary()->FindEntry(name) ==
    483                  NameDictionary::kNotFound);
    484 
    485       if (depth > 1) {
    486         Handle<WeakCell> weak_cell =
    487             Map::GetOrCreatePrototypeWeakCell(current, isolate());
    488         __ LoadWeakValue(reg, weak_cell, miss);
    489       }
    490       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
    491                                        scratch2);
    492     }
    493 
    494     reg = holder_reg;  // From now on the object will be in holder_reg.
    495     // Go to the next object in the prototype chain.
    496     current = handle(JSObject::cast(current_map->prototype()));
    497     current_map = handle(current->map());
    498   }
    499 
    500   DCHECK(!current_map->IsJSGlobalProxyMap());
    501 
    502   // Log the check depth.
    503   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
    504 
    505   bool return_holder = return_what == RETURN_HOLDER;
    506   if (return_holder && depth != 0) {
    507     Handle<WeakCell> weak_cell =
    508         Map::GetOrCreatePrototypeWeakCell(current, isolate());
    509     __ LoadWeakValue(reg, weak_cell, miss);
    510   }
    511 
    512   // Return the register containing the holder.
    513   return return_holder ? reg : no_reg;
    514 }
    515 
    516 
    517 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    518   if (!miss->is_unused()) {
    519     Label success;
    520     __ jmp(&success);
    521     __ bind(miss);
    522     if (IC::ShouldPushPopSlotAndVector(kind())) {
    523       DCHECK(kind() == Code::LOAD_IC);
    524       PopVectorAndSlot();
    525     }
    526     TailCallBuiltin(masm(), MissBuiltin(kind()));
    527     __ bind(&success);
    528   }
    529 }
    530 
    531 
    532 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    533   if (!miss->is_unused()) {
    534     Label success;
    535     __ jmp(&success);
    536     GenerateRestoreName(miss, name);
    537     DCHECK(!IC::ShouldPushPopSlotAndVector(kind()));
    538     TailCallBuiltin(masm(), MissBuiltin(kind()));
    539     __ bind(&success);
    540   }
    541 }
    542 
    543 
    544 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
    545   // Return the constant value.
    546   __ LoadObject(eax, value);
    547   __ ret(0);
    548 }
    549 
    550 
    551 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
    552     LookupIterator* it, Register holder_reg) {
    553   DCHECK(holder()->HasNamedInterceptor());
    554   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    555 
    556   // Compile the interceptor call, followed by inline code to load the
    557   // property from further up the prototype chain if the call fails.
    558   // Check that the maps haven't changed.
    559   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
    560 
    561   // Preserve the receiver register explicitly whenever it is different from the
    562   // holder and it is needed should the interceptor return without any result.
    563   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
    564   // case might cause a miss during the prototype check.
    565   bool must_perform_prototype_check =
    566       !holder().is_identical_to(it->GetHolder<JSObject>());
    567   bool must_preserve_receiver_reg =
    568       !receiver().is(holder_reg) &&
    569       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
    570 
    571   // Save necessary data before invoking an interceptor.
    572   // Requires a frame to make GC aware of pushed pointers.
    573   {
    574     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
    575 
    576     if (must_preserve_receiver_reg) {
    577       __ push(receiver());
    578     }
    579     __ push(holder_reg);
    580     __ push(this->name());
    581     InterceptorVectorSlotPush(holder_reg);
    582     // Invoke an interceptor.  Note: map checks from receiver to
    583     // interceptor's holder has been compiled before (see a caller
    584     // of this method.)
    585     CompileCallLoadPropertyWithInterceptor(
    586         masm(), receiver(), holder_reg, this->name(), holder(),
    587         Runtime::kLoadPropertyWithInterceptorOnly);
    588 
    589     // Check if interceptor provided a value for property.  If it's
    590     // the case, return immediately.
    591     Label interceptor_failed;
    592     __ cmp(eax, factory()->no_interceptor_result_sentinel());
    593     __ j(equal, &interceptor_failed);
    594     frame_scope.GenerateLeaveFrame();
    595     __ ret(0);
    596 
    597     // Clobber registers when generating debug-code to provoke errors.
    598     __ bind(&interceptor_failed);
    599     if (FLAG_debug_code) {
    600       __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
    601       __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
    602       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
    603     }
    604 
    605     InterceptorVectorSlotPop(holder_reg);
    606     __ pop(this->name());
    607     __ pop(holder_reg);
    608     if (must_preserve_receiver_reg) {
    609       __ pop(receiver());
    610     }
    611 
    612     // Leave the internal frame.
    613   }
    614 
    615   GenerateLoadPostInterceptor(it, holder_reg);
    616 }
    617 
    618 
    619 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
    620   DCHECK(holder()->HasNamedInterceptor());
    621   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
    622   // Call the runtime system to load the interceptor.
    623   __ pop(scratch2());  // save old return address
    624   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
    625                            holder());
    626   __ push(scratch2());  // restore old return address
    627 
    628   __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
    629 }
    630 
    631 void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
    632   // Zap register aliases of the arguments passed on the stack to ensure they
    633   // are properly loaded by the handler (debug-only).
    634   STATIC_ASSERT(Descriptor::kPassLastArgsOnStack);
    635   STATIC_ASSERT(Descriptor::kStackArgumentsCount == 3);
    636   __ mov(Descriptor::ValueRegister(), Immediate(kDebugZapValue));
    637   __ mov(Descriptor::SlotRegister(), Immediate(kDebugZapValue));
    638   __ mov(Descriptor::VectorRegister(), Immediate(kDebugZapValue));
    639 }
    640 
    641 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    642     Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> callback,
    643     LanguageMode language_mode) {
    644   Register holder_reg = Frontend(name);
    645   __ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
    646 
    647   __ pop(scratch1());  // remove the return address
    648   // Discard stack arguments.
    649   __ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
    650                         kPointerSize));
    651   __ push(receiver());
    652   __ push(holder_reg);
    653   // If the callback cannot leak, then push the callback directly,
    654   // otherwise wrap it in a weak cell.
    655   if (callback->data()->IsUndefined(isolate()) || callback->data()->IsSmi()) {
    656     __ Push(callback);
    657   } else {
    658     Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
    659     __ Push(cell);
    660   }
    661   __ Push(name);
    662   __ push(value());
    663   __ push(Immediate(Smi::FromInt(language_mode)));
    664   __ push(scratch1());  // restore return address
    665 
    666   // Do tail-call to the runtime system.
    667   __ TailCallRuntime(Runtime::kStoreCallbackProperty);
    668 
    669   // Return the generated code.
    670   return GetCode(kind(), name);
    671 }
    672 
    673 
    674 Register NamedStoreHandlerCompiler::value() {
    675   return StoreDescriptor::ValueRegister();
    676 }
    677 
    678 
    679 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
    680     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
    681   Label miss;
    682   if (IC::ShouldPushPopSlotAndVector(kind())) {
    683     PushVectorAndSlot();
    684   }
    685   FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    686   // Get the value from the cell.
    687   Register result = StoreDescriptor::ValueRegister();
    688   Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
    689   __ LoadWeakValue(result, weak_cell, &miss);
    690   __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
    691 
    692   // Check for deleted property if property can actually be deleted.
    693   if (is_configurable) {
    694     __ cmp(result, factory()->the_hole_value());
    695     __ j(equal, &miss);
    696   } else if (FLAG_debug_code) {
    697     __ cmp(result, factory()->the_hole_value());
    698     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
    699   }
    700 
    701   Counters* counters = isolate()->counters();
    702   __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
    703   // The code above already loads the result into the return register.
    704   if (IC::ShouldPushPopSlotAndVector(kind())) {
    705     DiscardVectorAndSlot();
    706   }
    707   __ ret(0);
    708 
    709   FrontendFooter(name, &miss);
    710 
    711   // Return the generated code.
    712   return GetCode(kind(), name);
    713 }
    714 
    715 
    716 #undef __
    717 }  // namespace internal
    718 }  // namespace v8
    719 
    720 #endif  // V8_TARGET_ARCH_IA32
    721