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 #include "src/v8.h"
      6 
      7 #if V8_TARGET_ARCH_X87
      8 
      9 #include "src/ic/call-optimization.h"
     10 #include "src/ic/handler-compiler.h"
     11 #include "src/ic/ic.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 #define __ ACCESS_MASM(masm)
     17 
     18 
     19 void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
     20     MacroAssembler* masm, Handle<HeapType> type, Register receiver,
     21     Handle<JSFunction> getter) {
     22   {
     23     FrameScope scope(masm, StackFrame::INTERNAL);
     24 
     25     if (!getter.is_null()) {
     26       // Call the JavaScript getter with the receiver on the stack.
     27       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
     28         // Swap in the global receiver.
     29         __ mov(receiver,
     30                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
     31       }
     32       __ push(receiver);
     33       ParameterCount actual(0);
     34       ParameterCount expected(getter);
     35       __ InvokeFunction(getter, expected, actual, CALL_FUNCTION,
     36                         NullCallWrapper());
     37     } else {
     38       // If we generate a global code snippet for deoptimization only, remember
     39       // the place to continue after deoptimization.
     40       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
     41     }
     42 
     43     // Restore context register.
     44     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
     45   }
     46   __ ret(0);
     47 }
     48 
     49 
     50 void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
     51     MacroAssembler* masm, Label* miss_label, Register receiver,
     52     Handle<Name> name, Register scratch0, Register scratch1) {
     53   DCHECK(name->IsUniqueName());
     54   DCHECK(!receiver.is(scratch0));
     55   Counters* counters = masm->isolate()->counters();
     56   __ IncrementCounter(counters->negative_lookups(), 1);
     57   __ IncrementCounter(counters->negative_lookups_miss(), 1);
     58 
     59   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
     60 
     61   const int kInterceptorOrAccessCheckNeededMask =
     62       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
     63 
     64   // Bail out if the receiver has a named interceptor or requires access checks.
     65   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
     66             kInterceptorOrAccessCheckNeededMask);
     67   __ j(not_zero, miss_label);
     68 
     69   // Check that receiver is a JSObject.
     70   __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
     71   __ j(below, miss_label);
     72 
     73   // Load properties array.
     74   Register properties = scratch0;
     75   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
     76 
     77   // Check that the properties array is a dictionary.
     78   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
     79          Immediate(masm->isolate()->factory()->hash_table_map()));
     80   __ j(not_equal, miss_label);
     81 
     82   Label done;
     83   NameDictionaryLookupStub::GenerateNegativeLookup(masm, miss_label, &done,
     84                                                    properties, name, scratch1);
     85   __ bind(&done);
     86   __ DecrementCounter(counters->negative_lookups_miss(), 1);
     87 }
     88 
     89 
     90 void NamedLoadHandlerCompiler::GenerateDirectLoadGlobalFunctionPrototype(
     91     MacroAssembler* masm, int index, Register prototype, Label* miss) {
     92   // Get the global function with the given index.
     93   Handle<JSFunction> function(
     94       JSFunction::cast(masm->isolate()->native_context()->get(index)));
     95   // Check we're still in the same context.
     96   Register scratch = prototype;
     97   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
     98   __ mov(scratch, Operand(esi, offset));
     99   __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
    100   __ cmp(Operand(scratch, Context::SlotOffset(index)), function);
    101   __ j(not_equal, miss);
    102 
    103   // Load its initial map. The global functions all have initial maps.
    104   __ Move(prototype, Immediate(Handle<Map>(function->initial_map())));
    105   // Load the prototype from the initial map.
    106   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
    107 }
    108 
    109 
    110 void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
    111     MacroAssembler* masm, Register receiver, Register scratch1,
    112     Register scratch2, Label* miss_label) {
    113   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
    114   __ mov(eax, scratch1);
    115   __ ret(0);
    116 }
    117 
    118 
    119 // Generate call to api function.
    120 // This function uses push() to generate smaller, faster code than
    121 // the version above. It is an optimization that should will be removed
    122 // when api call ICs are generated in hydrogen.
    123 void PropertyHandlerCompiler::GenerateFastApiCall(
    124     MacroAssembler* masm, const CallOptimization& optimization,
    125     Handle<Map> receiver_map, Register receiver, Register scratch_in,
    126     bool is_store, int argc, Register* values) {
    127   // Copy return value.
    128   __ pop(scratch_in);
    129   // receiver
    130   __ push(receiver);
    131   // Write the arguments to stack frame.
    132   for (int i = 0; i < argc; i++) {
    133     Register arg = values[argc - 1 - i];
    134     DCHECK(!receiver.is(arg));
    135     DCHECK(!scratch_in.is(arg));
    136     __ push(arg);
    137   }
    138   __ push(scratch_in);
    139   // Stack now matches JSFunction abi.
    140   DCHECK(optimization.is_simple_api_call());
    141 
    142   // Abi for CallApiFunctionStub.
    143   Register callee = eax;
    144   Register call_data = ebx;
    145   Register holder = ecx;
    146   Register api_function_address = edx;
    147   Register scratch = edi;  // scratch_in is no longer valid.
    148 
    149   // Put holder in place.
    150   CallOptimization::HolderLookup holder_lookup;
    151   Handle<JSObject> api_holder =
    152       optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
    153   switch (holder_lookup) {
    154     case CallOptimization::kHolderIsReceiver:
    155       __ Move(holder, receiver);
    156       break;
    157     case CallOptimization::kHolderFound:
    158       __ LoadHeapObject(holder, api_holder);
    159       break;
    160     case CallOptimization::kHolderNotFound:
    161       UNREACHABLE();
    162       break;
    163   }
    164 
    165   Isolate* isolate = masm->isolate();
    166   Handle<JSFunction> function = optimization.constant_function();
    167   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    168   Handle<Object> call_data_obj(api_call_info->data(), isolate);
    169 
    170   // Put callee in place.
    171   __ LoadHeapObject(callee, function);
    172 
    173   bool call_data_undefined = false;
    174   // Put call_data in place.
    175   if (isolate->heap()->InNewSpace(*call_data_obj)) {
    176     __ mov(scratch, api_call_info);
    177     __ mov(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
    178   } else if (call_data_obj->IsUndefined()) {
    179     call_data_undefined = true;
    180     __ mov(call_data, Immediate(isolate->factory()->undefined_value()));
    181   } else {
    182     __ mov(call_data, call_data_obj);
    183   }
    184 
    185   // Put api_function_address in place.
    186   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    187   __ mov(api_function_address, Immediate(function_address));
    188 
    189   // Jump to stub.
    190   CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
    191   __ TailCallStub(&stub);
    192 }
    193 
    194 
    195 // Generate code to check that a global property cell is empty. Create
    196 // the property cell at compilation time if no cell exists for the
    197 // property.
    198 void PropertyHandlerCompiler::GenerateCheckPropertyCell(
    199     MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
    200     Register scratch, Label* miss) {
    201   Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
    202   DCHECK(cell->value()->IsTheHole());
    203   Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
    204   if (masm->serializer_enabled()) {
    205     __ mov(scratch, Immediate(cell));
    206     __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
    207            Immediate(the_hole));
    208   } else {
    209     __ cmp(Operand::ForCell(cell), Immediate(the_hole));
    210   }
    211   __ j(not_equal, miss);
    212 }
    213 
    214 
    215 void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
    216     MacroAssembler* masm, Handle<HeapType> type, Register receiver,
    217     Handle<JSFunction> setter) {
    218   // ----------- S t a t e -------------
    219   //  -- esp[0] : return address
    220   // -----------------------------------
    221   {
    222     FrameScope scope(masm, StackFrame::INTERNAL);
    223 
    224     // Save value register, so we can restore it later.
    225     __ push(value());
    226 
    227     if (!setter.is_null()) {
    228       // Call the JavaScript setter with receiver and value on the stack.
    229       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
    230         // Swap in the global receiver.
    231         __ mov(receiver,
    232                FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
    233       }
    234       __ push(receiver);
    235       __ push(value());
    236       ParameterCount actual(1);
    237       ParameterCount expected(setter);
    238       __ InvokeFunction(setter, expected, actual, CALL_FUNCTION,
    239                         NullCallWrapper());
    240     } else {
    241       // If we generate a global code snippet for deoptimization only, remember
    242       // the place to continue after deoptimization.
    243       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
    244     }
    245 
    246     // We have to return the passed value, not the return value of the setter.
    247     __ pop(eax);
    248 
    249     // Restore context register.
    250     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
    251   }
    252   __ ret(0);
    253 }
    254 
    255 
    256 static void PushInterceptorArguments(MacroAssembler* masm, Register receiver,
    257                                      Register holder, Register name,
    258                                      Handle<JSObject> holder_obj) {
    259   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
    260   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex == 1);
    261   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 2);
    262   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 3);
    263   STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 4);
    264   __ push(name);
    265   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
    266   DCHECK(!masm->isolate()->heap()->InNewSpace(*interceptor));
    267   Register scratch = name;
    268   __ mov(scratch, Immediate(interceptor));
    269   __ push(scratch);
    270   __ push(receiver);
    271   __ push(holder);
    272 }
    273 
    274 
    275 static void CompileCallLoadPropertyWithInterceptor(
    276     MacroAssembler* masm, Register receiver, Register holder, Register name,
    277     Handle<JSObject> holder_obj, IC::UtilityId id) {
    278   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    279   __ CallExternalReference(ExternalReference(IC_Utility(id), masm->isolate()),
    280                            NamedLoadHandlerCompiler::kInterceptorArgsLength);
    281 }
    282 
    283 
    284 static void StoreIC_PushArgs(MacroAssembler* masm) {
    285   Register receiver = StoreDescriptor::ReceiverRegister();
    286   Register name = StoreDescriptor::NameRegister();
    287   Register value = StoreDescriptor::ValueRegister();
    288 
    289   DCHECK(!ebx.is(receiver) && !ebx.is(name) && !ebx.is(value));
    290 
    291   __ pop(ebx);
    292   __ push(receiver);
    293   __ push(name);
    294   __ push(value);
    295   __ push(ebx);
    296 }
    297 
    298 
    299 void NamedStoreHandlerCompiler::GenerateSlow(MacroAssembler* masm) {
    300   // Return address is on the stack.
    301   StoreIC_PushArgs(masm);
    302 
    303   // Do tail-call to runtime routine.
    304   ExternalReference ref(IC_Utility(IC::kStoreIC_Slow), masm->isolate());
    305   __ TailCallExternalReference(ref, 3, 1);
    306 }
    307 
    308 
    309 void ElementHandlerCompiler::GenerateStoreSlow(MacroAssembler* masm) {
    310   // Return address is on the stack.
    311   StoreIC_PushArgs(masm);
    312 
    313   // Do tail-call to runtime routine.
    314   ExternalReference ref(IC_Utility(IC::kKeyedStoreIC_Slow), masm->isolate());
    315   __ TailCallExternalReference(ref, 3, 1);
    316 }
    317 
    318 
    319 #undef __
    320 #define __ ACCESS_MASM(masm())
    321 
    322 
    323 void NamedStoreHandlerCompiler::GenerateRestoreName(Label* label,
    324                                                     Handle<Name> name) {
    325   if (!label->is_unused()) {
    326     __ bind(label);
    327     __ mov(this->name(), Immediate(name));
    328   }
    329 }
    330 
    331 
    332 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
    333 // store is successful.
    334 void NamedStoreHandlerCompiler::GenerateStoreTransition(
    335     Handle<Map> transition, Handle<Name> name, Register receiver_reg,
    336     Register storage_reg, Register value_reg, Register scratch1,
    337     Register scratch2, Register unused, Label* miss_label, Label* slow) {
    338   int descriptor = transition->LastAdded();
    339   DescriptorArray* descriptors = transition->instance_descriptors();
    340   PropertyDetails details = descriptors->GetDetails(descriptor);
    341   Representation representation = details.representation();
    342   DCHECK(!representation.IsNone());
    343 
    344   if (details.type() == CONSTANT) {
    345     Handle<Object> constant(descriptors->GetValue(descriptor), isolate());
    346     __ CmpObject(value_reg, constant);
    347     __ j(not_equal, miss_label);
    348   } else if (representation.IsSmi()) {
    349     __ JumpIfNotSmi(value_reg, miss_label);
    350   } else if (representation.IsHeapObject()) {
    351     __ JumpIfSmi(value_reg, miss_label);
    352     HeapType* field_type = descriptors->GetFieldType(descriptor);
    353     HeapType::Iterator<Map> it = field_type->Classes();
    354     if (!it.Done()) {
    355       Label do_store;
    356       while (true) {
    357         __ CompareMap(value_reg, it.Current());
    358         it.Advance();
    359         if (it.Done()) {
    360           __ j(not_equal, miss_label);
    361           break;
    362         }
    363         __ j(equal, &do_store, Label::kNear);
    364       }
    365       __ bind(&do_store);
    366     }
    367   } else if (representation.IsDouble()) {
    368     Label do_store, heap_number;
    369     __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE);
    370 
    371     __ JumpIfNotSmi(value_reg, &heap_number);
    372     __ SmiUntag(value_reg);
    373     __ push(value_reg);
    374     __ fild_s(Operand(esp, 0));
    375     __ pop(value_reg);
    376     __ SmiTag(value_reg);
    377     __ jmp(&do_store);
    378 
    379     __ bind(&heap_number);
    380     __ CheckMap(value_reg, isolate()->factory()->heap_number_map(), miss_label,
    381                 DONT_DO_SMI_CHECK);
    382     __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
    383 
    384     __ bind(&do_store);
    385     __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
    386   }
    387 
    388   // Stub never generated for objects that require access checks.
    389   DCHECK(!transition->is_access_check_needed());
    390 
    391   // Perform map transition for the receiver if necessary.
    392   if (details.type() == FIELD &&
    393       Map::cast(transition->GetBackPointer())->unused_property_fields() == 0) {
    394     // The properties must be extended before we can store the value.
    395     // We jump to a runtime call that extends the properties array.
    396     __ pop(scratch1);  // Return address.
    397     __ push(receiver_reg);
    398     __ push(Immediate(transition));
    399     __ push(value_reg);
    400     __ push(scratch1);
    401     __ TailCallExternalReference(
    402         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
    403                           isolate()),
    404         3, 1);
    405     return;
    406   }
    407 
    408   // Update the map of the object.
    409   __ mov(scratch1, Immediate(transition));
    410   __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
    411 
    412   // Update the write barrier for the map field.
    413   __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
    414                       kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
    415 
    416   if (details.type() == CONSTANT) {
    417     DCHECK(value_reg.is(eax));
    418     __ ret(0);
    419     return;
    420   }
    421 
    422   int index = transition->instance_descriptors()->GetFieldIndex(
    423       transition->LastAdded());
    424 
    425   // Adjust for the number of properties stored in the object. Even in the
    426   // face of a transition we can use the old map here because the size of the
    427   // object and the number of in-object properties is not going to change.
    428   index -= transition->inobject_properties();
    429 
    430   SmiCheck smi_check =
    431       representation.IsTagged() ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
    432   // TODO(verwaest): Share this code as a code stub.
    433   if (index < 0) {
    434     // Set the property straight into the object.
    435     int offset = transition->instance_size() + (index * kPointerSize);
    436     if (representation.IsDouble()) {
    437       __ mov(FieldOperand(receiver_reg, offset), storage_reg);
    438     } else {
    439       __ mov(FieldOperand(receiver_reg, offset), value_reg);
    440     }
    441 
    442     if (!representation.IsSmi()) {
    443       // Update the write barrier for the array address.
    444       if (!representation.IsDouble()) {
    445         __ mov(storage_reg, value_reg);
    446       }
    447       __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
    448                           kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
    449     }
    450   } else {
    451     // Write to the properties array.
    452     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    453     // Get the properties array (optimistically).
    454     __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
    455     if (representation.IsDouble()) {
    456       __ mov(FieldOperand(scratch1, offset), storage_reg);
    457     } else {
    458       __ mov(FieldOperand(scratch1, offset), value_reg);
    459     }
    460 
    461     if (!representation.IsSmi()) {
    462       // Update the write barrier for the array address.
    463       if (!representation.IsDouble()) {
    464         __ mov(storage_reg, value_reg);
    465       }
    466       __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
    467                           kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
    468     }
    469   }
    470 
    471   // Return the value (register eax).
    472   DCHECK(value_reg.is(eax));
    473   __ ret(0);
    474 }
    475 
    476 
    477 void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
    478                                                    Register value_reg,
    479                                                    Label* miss_label) {
    480   DCHECK(lookup->representation().IsHeapObject());
    481   __ JumpIfSmi(value_reg, miss_label);
    482   HeapType::Iterator<Map> it = lookup->GetFieldType()->Classes();
    483   Label do_store;
    484   while (true) {
    485     __ CompareMap(value_reg, it.Current());
    486     it.Advance();
    487     if (it.Done()) {
    488       __ j(not_equal, miss_label);
    489       break;
    490     }
    491     __ j(equal, &do_store, Label::kNear);
    492   }
    493   __ bind(&do_store);
    494 
    495   StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
    496                       lookup->representation());
    497   GenerateTailCall(masm(), stub.GetCode());
    498 }
    499 
    500 
    501 Register PropertyHandlerCompiler::CheckPrototypes(
    502     Register object_reg, Register holder_reg, Register scratch1,
    503     Register scratch2, Handle<Name> name, Label* miss,
    504     PrototypeCheckType check) {
    505   Handle<Map> receiver_map(IC::TypeToMap(*type(), isolate()));
    506 
    507   // Make sure there's no overlap between holder and object registers.
    508   DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
    509   DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) &&
    510          !scratch2.is(scratch1));
    511 
    512   // Keep track of the current object in register reg.
    513   Register reg = object_reg;
    514   int depth = 0;
    515 
    516   Handle<JSObject> current = Handle<JSObject>::null();
    517   if (type()->IsConstant())
    518     current = Handle<JSObject>::cast(type()->AsConstant()->Value());
    519   Handle<JSObject> prototype = Handle<JSObject>::null();
    520   Handle<Map> current_map = receiver_map;
    521   Handle<Map> holder_map(holder()->map());
    522   // Traverse the prototype chain and check the maps in the prototype chain for
    523   // fast and global objects or do negative lookup for normal objects.
    524   while (!current_map.is_identical_to(holder_map)) {
    525     ++depth;
    526 
    527     // Only global objects and objects that do not require access
    528     // checks are allowed in stubs.
    529     DCHECK(current_map->IsJSGlobalProxyMap() ||
    530            !current_map->is_access_check_needed());
    531 
    532     prototype = handle(JSObject::cast(current_map->prototype()));
    533     if (current_map->is_dictionary_map() &&
    534         !current_map->IsJSGlobalObjectMap()) {
    535       DCHECK(!current_map->IsJSGlobalProxyMap());  // Proxy maps are fast.
    536       if (!name->IsUniqueName()) {
    537         DCHECK(name->IsString());
    538         name = factory()->InternalizeString(Handle<String>::cast(name));
    539       }
    540       DCHECK(current.is_null() ||
    541              current->property_dictionary()->FindEntry(name) ==
    542                  NameDictionary::kNotFound);
    543 
    544       GenerateDictionaryNegativeLookup(masm(), miss, reg, name, scratch1,
    545                                        scratch2);
    546 
    547       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    548       reg = holder_reg;  // From now on the object will be in holder_reg.
    549       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    550     } else {
    551       bool in_new_space = heap()->InNewSpace(*prototype);
    552       // Two possible reasons for loading the prototype from the map:
    553       // (1) Can't store references to new space in code.
    554       // (2) Handler is shared for all receivers with the same prototype
    555       //     map (but not necessarily the same prototype instance).
    556       bool load_prototype_from_map = in_new_space || depth == 1;
    557       if (depth != 1 || check == CHECK_ALL_MAPS) {
    558         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
    559       }
    560 
    561       // Check access rights to the global object.  This has to happen after
    562       // the map check so that we know that the object is actually a global
    563       // object.
    564       // This allows us to install generated handlers for accesses to the
    565       // global proxy (as opposed to using slow ICs). See corresponding code
    566       // in LookupForRead().
    567       if (current_map->IsJSGlobalProxyMap()) {
    568         __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
    569       } else if (current_map->IsJSGlobalObjectMap()) {
    570         GenerateCheckPropertyCell(masm(), Handle<JSGlobalObject>::cast(current),
    571                                   name, scratch2, miss);
    572       }
    573 
    574       if (load_prototype_from_map) {
    575         // Save the map in scratch1 for later.
    576         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    577       }
    578 
    579       reg = holder_reg;  // From now on the object will be in holder_reg.
    580 
    581       if (load_prototype_from_map) {
    582         __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    583       } else {
    584         __ mov(reg, prototype);
    585       }
    586     }
    587 
    588     // Go to the next object in the prototype chain.
    589     current = prototype;
    590     current_map = handle(current->map());
    591   }
    592 
    593   // Log the check depth.
    594   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
    595 
    596   if (depth != 0 || check == CHECK_ALL_MAPS) {
    597     // Check the holder map.
    598     __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
    599   }
    600 
    601   // Perform security check for access to the global object.
    602   DCHECK(current_map->IsJSGlobalProxyMap() ||
    603          !current_map->is_access_check_needed());
    604   if (current_map->IsJSGlobalProxyMap()) {
    605     __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
    606   }
    607 
    608   // Return the register containing the holder.
    609   return reg;
    610 }
    611 
    612 
    613 void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    614   if (!miss->is_unused()) {
    615     Label success;
    616     __ jmp(&success);
    617     __ bind(miss);
    618     TailCallBuiltin(masm(), MissBuiltin(kind()));
    619     __ bind(&success);
    620   }
    621 }
    622 
    623 
    624 void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
    625   if (!miss->is_unused()) {
    626     Label success;
    627     __ jmp(&success);
    628     GenerateRestoreName(miss, name);
    629     TailCallBuiltin(masm(), MissBuiltin(kind()));
    630     __ bind(&success);
    631   }
    632 }
    633 
    634 
    635 void NamedLoadHandlerCompiler::GenerateLoadCallback(
    636     Register reg, Handle<ExecutableAccessorInfo> callback) {
    637   // Insert additional parameters into the stack frame above return address.
    638   DCHECK(!scratch3().is(reg));
    639   __ pop(scratch3());  // Get return address to place it below.
    640 
    641   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
    642   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
    643   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
    644   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
    645   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
    646   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
    647   __ push(receiver());  // receiver
    648   // Push data from ExecutableAccessorInfo.
    649   if (isolate()->heap()->InNewSpace(callback->data())) {
    650     DCHECK(!scratch2().is(reg));
    651     __ mov(scratch2(), Immediate(callback));
    652     __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
    653   } else {
    654     __ push(Immediate(Handle<Object>(callback->data(), isolate())));
    655   }
    656   __ push(Immediate(isolate()->factory()->undefined_value()));  // ReturnValue
    657   // ReturnValue default value
    658   __ push(Immediate(isolate()->factory()->undefined_value()));
    659   __ push(Immediate(reinterpret_cast<int>(isolate())));
    660   __ push(reg);  // holder
    661 
    662   // Save a pointer to where we pushed the arguments. This will be
    663   // passed as the const PropertyAccessorInfo& to the C++ callback.
    664   __ push(esp);
    665 
    666   __ push(name());  // name
    667 
    668   __ push(scratch3());  // Restore return address.
    669 
    670   // Abi for CallApiGetter
    671   Register getter_address = ApiGetterDescriptor::function_address();
    672   Address function_address = v8::ToCData<Address>(callback->getter());
    673   __ mov(getter_address, Immediate(function_address));
    674 
    675   CallApiGetterStub stub(isolate());
    676   __ TailCallStub(&stub);
    677 }
    678 
    679 
    680 void NamedLoadHandlerCompiler::GenerateLoadConstant(Handle<Object> value) {
    681   // Return the constant value.
    682   __ LoadObject(eax, value);
    683   __ ret(0);
    684 }
    685 
    686 
    687 void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
    688     LookupIterator* it, Register holder_reg) {
    689   DCHECK(holder()->HasNamedInterceptor());
    690   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
    691 
    692   // Compile the interceptor call, followed by inline code to load the
    693   // property from further up the prototype chain if the call fails.
    694   // Check that the maps haven't changed.
    695   DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
    696 
    697   // Preserve the receiver register explicitly whenever it is different from the
    698   // holder and it is needed should the interceptor return without any result.
    699   // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
    700   // case might cause a miss during the prototype check.
    701   bool must_perform_prototype_check =
    702       !holder().is_identical_to(it->GetHolder<JSObject>());
    703   bool must_preserve_receiver_reg =
    704       !receiver().is(holder_reg) &&
    705       (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
    706 
    707   // Save necessary data before invoking an interceptor.
    708   // Requires a frame to make GC aware of pushed pointers.
    709   {
    710     FrameScope frame_scope(masm(), StackFrame::INTERNAL);
    711 
    712     if (must_preserve_receiver_reg) {
    713       __ push(receiver());
    714     }
    715     __ push(holder_reg);
    716     __ push(this->name());
    717 
    718     // Invoke an interceptor.  Note: map checks from receiver to
    719     // interceptor's holder has been compiled before (see a caller
    720     // of this method.)
    721     CompileCallLoadPropertyWithInterceptor(
    722         masm(), receiver(), holder_reg, this->name(), holder(),
    723         IC::kLoadPropertyWithInterceptorOnly);
    724 
    725     // Check if interceptor provided a value for property.  If it's
    726     // the case, return immediately.
    727     Label interceptor_failed;
    728     __ cmp(eax, factory()->no_interceptor_result_sentinel());
    729     __ j(equal, &interceptor_failed);
    730     frame_scope.GenerateLeaveFrame();
    731     __ ret(0);
    732 
    733     // Clobber registers when generating debug-code to provoke errors.
    734     __ bind(&interceptor_failed);
    735     if (FLAG_debug_code) {
    736       __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
    737       __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
    738       __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
    739     }
    740 
    741     __ pop(this->name());
    742     __ pop(holder_reg);
    743     if (must_preserve_receiver_reg) {
    744       __ pop(receiver());
    745     }
    746 
    747     // Leave the internal frame.
    748   }
    749 
    750   GenerateLoadPostInterceptor(it, holder_reg);
    751 }
    752 
    753 
    754 void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
    755   DCHECK(holder()->HasNamedInterceptor());
    756   DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined());
    757   // Call the runtime system to load the interceptor.
    758   __ pop(scratch2());  // save old return address
    759   PushInterceptorArguments(masm(), receiver(), holder_reg, this->name(),
    760                            holder());
    761   __ push(scratch2());  // restore old return address
    762 
    763   ExternalReference ref = ExternalReference(
    764       IC_Utility(IC::kLoadPropertyWithInterceptor), isolate());
    765   __ TailCallExternalReference(
    766       ref, NamedLoadHandlerCompiler::kInterceptorArgsLength, 1);
    767 }
    768 
    769 
    770 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    771     Handle<JSObject> object, Handle<Name> name,
    772     Handle<ExecutableAccessorInfo> callback) {
    773   Register holder_reg = Frontend(receiver(), name);
    774 
    775   __ pop(scratch1());  // remove the return address
    776   __ push(receiver());
    777   __ push(holder_reg);
    778   __ Push(callback);
    779   __ Push(name);
    780   __ push(value());
    781   __ push(scratch1());  // restore return address
    782 
    783   // Do tail-call to the runtime system.
    784   ExternalReference store_callback_property =
    785       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
    786   __ TailCallExternalReference(store_callback_property, 5, 1);
    787 
    788   // Return the generated code.
    789   return GetCode(kind(), Code::FAST, name);
    790 }
    791 
    792 
    793 Handle<Code> NamedStoreHandlerCompiler::CompileStoreInterceptor(
    794     Handle<Name> name) {
    795   __ pop(scratch1());  // remove the return address
    796   __ push(receiver());
    797   __ push(this->name());
    798   __ push(value());
    799   __ push(scratch1());  // restore return address
    800 
    801   // Do tail-call to the runtime system.
    802   ExternalReference store_ic_property = ExternalReference(
    803       IC_Utility(IC::kStorePropertyWithInterceptor), isolate());
    804   __ TailCallExternalReference(store_ic_property, 3, 1);
    805 
    806   // Return the generated code.
    807   return GetCode(kind(), Code::FAST, name);
    808 }
    809 
    810 
    811 Register NamedStoreHandlerCompiler::value() {
    812   return StoreDescriptor::ValueRegister();
    813 }
    814 
    815 
    816 Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
    817     Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
    818   Label miss;
    819 
    820   FrontendHeader(receiver(), name, &miss);
    821   // Get the value from the cell.
    822   Register result = StoreDescriptor::ValueRegister();
    823   if (masm()->serializer_enabled()) {
    824     __ mov(result, Immediate(cell));
    825     __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
    826   } else {
    827     __ mov(result, Operand::ForCell(cell));
    828   }
    829 
    830   // Check for deleted property if property can actually be deleted.
    831   if (is_configurable) {
    832     __ cmp(result, factory()->the_hole_value());
    833     __ j(equal, &miss);
    834   } else if (FLAG_debug_code) {
    835     __ cmp(result, factory()->the_hole_value());
    836     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
    837   }
    838 
    839   Counters* counters = isolate()->counters();
    840   __ IncrementCounter(counters->named_load_global_stub(), 1);
    841   // The code above already loads the result into the return register.
    842   __ ret(0);
    843 
    844   FrontendFooter(name, &miss);
    845 
    846   // Return the generated code.
    847   return GetCode(kind(), Code::NORMAL, name);
    848 }
    849 
    850 
    851 #undef __
    852 }
    853 }  // namespace v8::internal
    854 
    855 #endif  // V8_TARGET_ARCH_X87
    856