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