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-inl.h"
     10 #include "src/codegen.h"
     11 #include "src/stub-cache.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 #define __ ACCESS_MASM(masm)
     17 
     18 
     19 static void ProbeTable(Isolate* isolate,
     20                        MacroAssembler* masm,
     21                        Code::Flags flags,
     22                        StubCache::Table table,
     23                        Register name,
     24                        Register receiver,
     25                        // Number of the cache entry pointer-size scaled.
     26                        Register offset,
     27                        Register extra) {
     28   ExternalReference key_offset(isolate->stub_cache()->key_reference(table));
     29   ExternalReference value_offset(isolate->stub_cache()->value_reference(table));
     30   ExternalReference map_offset(isolate->stub_cache()->map_reference(table));
     31 
     32   Label miss;
     33 
     34   // Multiply by 3 because there are 3 fields per entry (name, code, map).
     35   __ lea(offset, Operand(offset, offset, times_2, 0));
     36 
     37   if (extra.is_valid()) {
     38     // Get the code entry from the cache.
     39     __ mov(extra, Operand::StaticArray(offset, times_1, value_offset));
     40 
     41     // Check that the key in the entry matches the name.
     42     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
     43     __ j(not_equal, &miss);
     44 
     45     // Check the map matches.
     46     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
     47     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
     48     __ j(not_equal, &miss);
     49 
     50     // Check that the flags match what we're looking for.
     51     __ mov(offset, FieldOperand(extra, Code::kFlagsOffset));
     52     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
     53     __ cmp(offset, flags);
     54     __ j(not_equal, &miss);
     55 
     56 #ifdef DEBUG
     57     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
     58       __ jmp(&miss);
     59     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
     60       __ jmp(&miss);
     61     }
     62 #endif
     63 
     64     // Jump to the first instruction in the code stub.
     65     __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag));
     66     __ jmp(extra);
     67 
     68     __ bind(&miss);
     69   } else {
     70     // Save the offset on the stack.
     71     __ push(offset);
     72 
     73     // Check that the key in the entry matches the name.
     74     __ cmp(name, Operand::StaticArray(offset, times_1, key_offset));
     75     __ j(not_equal, &miss);
     76 
     77     // Check the map matches.
     78     __ mov(offset, Operand::StaticArray(offset, times_1, map_offset));
     79     __ cmp(offset, FieldOperand(receiver, HeapObject::kMapOffset));
     80     __ j(not_equal, &miss);
     81 
     82     // Restore offset register.
     83     __ mov(offset, Operand(esp, 0));
     84 
     85     // Get the code entry from the cache.
     86     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
     87 
     88     // Check that the flags match what we're looking for.
     89     __ mov(offset, FieldOperand(offset, Code::kFlagsOffset));
     90     __ and_(offset, ~Code::kFlagsNotUsedInLookup);
     91     __ cmp(offset, flags);
     92     __ j(not_equal, &miss);
     93 
     94 #ifdef DEBUG
     95     if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
     96       __ jmp(&miss);
     97     } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
     98       __ jmp(&miss);
     99     }
    100 #endif
    101 
    102     // Restore offset and re-load code entry from cache.
    103     __ pop(offset);
    104     __ mov(offset, Operand::StaticArray(offset, times_1, value_offset));
    105 
    106     // Jump to the first instruction in the code stub.
    107     __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag));
    108     __ jmp(offset);
    109 
    110     // Pop at miss.
    111     __ bind(&miss);
    112     __ pop(offset);
    113   }
    114 }
    115 
    116 
    117 void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
    118                                                     Label* miss_label,
    119                                                     Register receiver,
    120                                                     Handle<Name> name,
    121                                                     Register scratch0,
    122                                                     Register scratch1) {
    123   ASSERT(name->IsUniqueName());
    124   ASSERT(!receiver.is(scratch0));
    125   Counters* counters = masm->isolate()->counters();
    126   __ IncrementCounter(counters->negative_lookups(), 1);
    127   __ IncrementCounter(counters->negative_lookups_miss(), 1);
    128 
    129   __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
    130 
    131   const int kInterceptorOrAccessCheckNeededMask =
    132       (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
    133 
    134   // Bail out if the receiver has a named interceptor or requires access checks.
    135   __ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
    136             kInterceptorOrAccessCheckNeededMask);
    137   __ j(not_zero, miss_label);
    138 
    139   // Check that receiver is a JSObject.
    140   __ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
    141   __ j(below, miss_label);
    142 
    143   // Load properties array.
    144   Register properties = scratch0;
    145   __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
    146 
    147   // Check that the properties array is a dictionary.
    148   __ cmp(FieldOperand(properties, HeapObject::kMapOffset),
    149          Immediate(masm->isolate()->factory()->hash_table_map()));
    150   __ j(not_equal, miss_label);
    151 
    152   Label done;
    153   NameDictionaryLookupStub::GenerateNegativeLookup(masm,
    154                                                    miss_label,
    155                                                    &done,
    156                                                    properties,
    157                                                    name,
    158                                                    scratch1);
    159   __ bind(&done);
    160   __ DecrementCounter(counters->negative_lookups_miss(), 1);
    161 }
    162 
    163 
    164 void StubCache::GenerateProbe(MacroAssembler* masm,
    165                               Code::Flags flags,
    166                               Register receiver,
    167                               Register name,
    168                               Register scratch,
    169                               Register extra,
    170                               Register extra2,
    171                               Register extra3) {
    172   Label miss;
    173 
    174   // Assert that code is valid.  The multiplying code relies on the entry size
    175   // being 12.
    176   ASSERT(sizeof(Entry) == 12);
    177 
    178   // Assert the flags do not name a specific type.
    179   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
    180 
    181   // Assert that there are no register conflicts.
    182   ASSERT(!scratch.is(receiver));
    183   ASSERT(!scratch.is(name));
    184   ASSERT(!extra.is(receiver));
    185   ASSERT(!extra.is(name));
    186   ASSERT(!extra.is(scratch));
    187 
    188   // Assert scratch and extra registers are valid, and extra2/3 are unused.
    189   ASSERT(!scratch.is(no_reg));
    190   ASSERT(extra2.is(no_reg));
    191   ASSERT(extra3.is(no_reg));
    192 
    193   Register offset = scratch;
    194   scratch = no_reg;
    195 
    196   Counters* counters = masm->isolate()->counters();
    197   __ IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
    198 
    199   // Check that the receiver isn't a smi.
    200   __ JumpIfSmi(receiver, &miss);
    201 
    202   // Get the map of the receiver and compute the hash.
    203   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
    204   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
    205   __ xor_(offset, flags);
    206   // We mask out the last two bits because they are not part of the hash and
    207   // they are always 01 for maps.  Also in the two 'and' instructions below.
    208   __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
    209   // ProbeTable expects the offset to be pointer scaled, which it is, because
    210   // the heap object tag size is 2 and the pointer size log 2 is also 2.
    211   ASSERT(kHeapObjectTagSize == kPointerSizeLog2);
    212 
    213   // Probe the primary table.
    214   ProbeTable(isolate(), masm, flags, kPrimary, name, receiver, offset, extra);
    215 
    216   // Primary miss: Compute hash for secondary probe.
    217   __ mov(offset, FieldOperand(name, Name::kHashFieldOffset));
    218   __ add(offset, FieldOperand(receiver, HeapObject::kMapOffset));
    219   __ xor_(offset, flags);
    220   __ and_(offset, (kPrimaryTableSize - 1) << kHeapObjectTagSize);
    221   __ sub(offset, name);
    222   __ add(offset, Immediate(flags));
    223   __ and_(offset, (kSecondaryTableSize - 1) << kHeapObjectTagSize);
    224 
    225   // Probe the secondary table.
    226   ProbeTable(
    227       isolate(), masm, flags, kSecondary, name, receiver, offset, extra);
    228 
    229   // Cache miss: Fall-through and let caller handle the miss by
    230   // entering the runtime system.
    231   __ bind(&miss);
    232   __ IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
    233 }
    234 
    235 
    236 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
    237                                                        int index,
    238                                                        Register prototype) {
    239   __ LoadGlobalFunction(index, prototype);
    240   __ LoadGlobalFunctionInitialMap(prototype, prototype);
    241   // Load the prototype from the initial map.
    242   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
    243 }
    244 
    245 
    246 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype(
    247     MacroAssembler* masm,
    248     int index,
    249     Register prototype,
    250     Label* miss) {
    251   // Get the global function with the given index.
    252   Handle<JSFunction> function(
    253       JSFunction::cast(masm->isolate()->native_context()->get(index)));
    254   // Check we're still in the same context.
    255   Register scratch = prototype;
    256   const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX);
    257   __ mov(scratch, Operand(esi, offset));
    258   __ mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
    259   __ cmp(Operand(scratch, Context::SlotOffset(index)), function);
    260   __ j(not_equal, miss);
    261 
    262   // Load its initial map. The global functions all have initial maps.
    263   __ Move(prototype, Immediate(Handle<Map>(function->initial_map())));
    264   // Load the prototype from the initial map.
    265   __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
    266 }
    267 
    268 
    269 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm,
    270                                            Register receiver,
    271                                            Register scratch,
    272                                            Label* miss_label) {
    273   // Check that the receiver isn't a smi.
    274   __ JumpIfSmi(receiver, miss_label);
    275 
    276   // Check that the object is a JS array.
    277   __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
    278   __ j(not_equal, miss_label);
    279 
    280   // Load length directly from the JS array.
    281   __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset));
    282   __ ret(0);
    283 }
    284 
    285 
    286 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
    287                                                  Register receiver,
    288                                                  Register scratch1,
    289                                                  Register scratch2,
    290                                                  Label* miss_label) {
    291   __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
    292   __ mov(eax, scratch1);
    293   __ ret(0);
    294 }
    295 
    296 
    297 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
    298                                             Register dst,
    299                                             Register src,
    300                                             bool inobject,
    301                                             int index,
    302                                             Representation representation) {
    303   ASSERT(!representation.IsDouble());
    304   int offset = index * kPointerSize;
    305   if (!inobject) {
    306     // Calculate the offset into the properties array.
    307     offset = offset + FixedArray::kHeaderSize;
    308     __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
    309     src = dst;
    310   }
    311   __ mov(dst, FieldOperand(src, offset));
    312 }
    313 
    314 
    315 static void PushInterceptorArguments(MacroAssembler* masm,
    316                                      Register receiver,
    317                                      Register holder,
    318                                      Register name,
    319                                      Handle<JSObject> holder_obj) {
    320   STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
    321   STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
    322   STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
    323   STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
    324   STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
    325   __ push(name);
    326   Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
    327   ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
    328   Register scratch = name;
    329   __ mov(scratch, Immediate(interceptor));
    330   __ push(scratch);
    331   __ push(receiver);
    332   __ push(holder);
    333 }
    334 
    335 
    336 static void CompileCallLoadPropertyWithInterceptor(
    337     MacroAssembler* masm,
    338     Register receiver,
    339     Register holder,
    340     Register name,
    341     Handle<JSObject> holder_obj,
    342     IC::UtilityId id) {
    343   PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
    344   __ CallExternalReference(
    345       ExternalReference(IC_Utility(id), masm->isolate()),
    346       StubCache::kInterceptorArgsLength);
    347 }
    348 
    349 
    350 // Generate call to api function.
    351 // This function uses push() to generate smaller, faster code than
    352 // the version above. It is an optimization that should will be removed
    353 // when api call ICs are generated in hydrogen.
    354 void StubCompiler::GenerateFastApiCall(MacroAssembler* masm,
    355                                        const CallOptimization& optimization,
    356                                        Handle<Map> receiver_map,
    357                                        Register receiver,
    358                                        Register scratch_in,
    359                                        bool is_store,
    360                                        int argc,
    361                                        Register* values) {
    362   // Copy return value.
    363   __ pop(scratch_in);
    364   // receiver
    365   __ push(receiver);
    366   // Write the arguments to stack frame.
    367   for (int i = 0; i < argc; i++) {
    368     Register arg = values[argc-1-i];
    369     ASSERT(!receiver.is(arg));
    370     ASSERT(!scratch_in.is(arg));
    371     __ push(arg);
    372   }
    373   __ push(scratch_in);
    374   // Stack now matches JSFunction abi.
    375   ASSERT(optimization.is_simple_api_call());
    376 
    377   // Abi for CallApiFunctionStub.
    378   Register callee = eax;
    379   Register call_data = ebx;
    380   Register holder = ecx;
    381   Register api_function_address = edx;
    382   Register scratch = edi;  // scratch_in is no longer valid.
    383 
    384   // Put holder in place.
    385   CallOptimization::HolderLookup holder_lookup;
    386   Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
    387       receiver_map,
    388       &holder_lookup);
    389   switch (holder_lookup) {
    390     case CallOptimization::kHolderIsReceiver:
    391       __ Move(holder, receiver);
    392       break;
    393     case CallOptimization::kHolderFound:
    394       __ LoadHeapObject(holder, api_holder);
    395      break;
    396     case CallOptimization::kHolderNotFound:
    397       UNREACHABLE();
    398       break;
    399   }
    400 
    401   Isolate* isolate = masm->isolate();
    402   Handle<JSFunction> function = optimization.constant_function();
    403   Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
    404   Handle<Object> call_data_obj(api_call_info->data(), isolate);
    405 
    406   // Put callee in place.
    407   __ LoadHeapObject(callee, function);
    408 
    409   bool call_data_undefined = false;
    410   // Put call_data in place.
    411   if (isolate->heap()->InNewSpace(*call_data_obj)) {
    412     __ mov(scratch, api_call_info);
    413     __ mov(call_data, FieldOperand(scratch, CallHandlerInfo::kDataOffset));
    414   } else if (call_data_obj->IsUndefined()) {
    415     call_data_undefined = true;
    416     __ mov(call_data, Immediate(isolate->factory()->undefined_value()));
    417   } else {
    418     __ mov(call_data, call_data_obj);
    419   }
    420 
    421   // Put api_function_address in place.
    422   Address function_address = v8::ToCData<Address>(api_call_info->callback());
    423   __ mov(api_function_address, Immediate(function_address));
    424 
    425   // Jump to stub.
    426   CallApiFunctionStub stub(isolate, is_store, call_data_undefined, argc);
    427   __ TailCallStub(&stub);
    428 }
    429 
    430 
    431 void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
    432                                             Label* label,
    433                                             Handle<Name> name) {
    434   if (!label->is_unused()) {
    435     __ bind(label);
    436     __ mov(this->name(), Immediate(name));
    437   }
    438 }
    439 
    440 
    441 // Generate code to check that a global property cell is empty. Create
    442 // the property cell at compilation time if no cell exists for the
    443 // property.
    444 void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
    445                                              Handle<JSGlobalObject> global,
    446                                              Handle<Name> name,
    447                                              Register scratch,
    448                                              Label* miss) {
    449   Handle<PropertyCell> cell =
    450       JSGlobalObject::EnsurePropertyCell(global, name);
    451   ASSERT(cell->value()->IsTheHole());
    452   Handle<Oddball> the_hole = masm->isolate()->factory()->the_hole_value();
    453   if (masm->serializer_enabled()) {
    454     __ mov(scratch, Immediate(cell));
    455     __ cmp(FieldOperand(scratch, PropertyCell::kValueOffset),
    456            Immediate(the_hole));
    457   } else {
    458     __ cmp(Operand::ForCell(cell), Immediate(the_hole));
    459   }
    460   __ j(not_equal, miss);
    461 }
    462 
    463 
    464 void StoreStubCompiler::GenerateNegativeHolderLookup(
    465     MacroAssembler* masm,
    466     Handle<JSObject> holder,
    467     Register holder_reg,
    468     Handle<Name> name,
    469     Label* miss) {
    470   if (holder->IsJSGlobalObject()) {
    471     GenerateCheckPropertyCell(
    472         masm, Handle<JSGlobalObject>::cast(holder), name, scratch1(), miss);
    473   } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
    474     GenerateDictionaryNegativeLookup(
    475         masm, miss, holder_reg, name, scratch1(), scratch2());
    476   }
    477 }
    478 
    479 
    480 // Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
    481 // store is successful.
    482 void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
    483                                                 Handle<JSObject> object,
    484                                                 LookupResult* lookup,
    485                                                 Handle<Map> transition,
    486                                                 Handle<Name> name,
    487                                                 Register receiver_reg,
    488                                                 Register storage_reg,
    489                                                 Register value_reg,
    490                                                 Register scratch1,
    491                                                 Register scratch2,
    492                                                 Register unused,
    493                                                 Label* miss_label,
    494                                                 Label* slow) {
    495   int descriptor = transition->LastAdded();
    496   DescriptorArray* descriptors = transition->instance_descriptors();
    497   PropertyDetails details = descriptors->GetDetails(descriptor);
    498   Representation representation = details.representation();
    499   ASSERT(!representation.IsNone());
    500 
    501   if (details.type() == CONSTANT) {
    502     Handle<Object> constant(descriptors->GetValue(descriptor), masm->isolate());
    503     __ CmpObject(value_reg, constant);
    504     __ j(not_equal, miss_label);
    505   } else if (representation.IsSmi()) {
    506       __ JumpIfNotSmi(value_reg, miss_label);
    507   } else if (representation.IsHeapObject()) {
    508     __ JumpIfSmi(value_reg, miss_label);
    509     HeapType* field_type = descriptors->GetFieldType(descriptor);
    510     HeapType::Iterator<Map> it = field_type->Classes();
    511     if (!it.Done()) {
    512       Label do_store;
    513       while (true) {
    514         __ CompareMap(value_reg, it.Current());
    515         it.Advance();
    516         if (it.Done()) {
    517           __ j(not_equal, miss_label);
    518           break;
    519         }
    520         __ j(equal, &do_store, Label::kNear);
    521       }
    522       __ bind(&do_store);
    523     }
    524   } else if (representation.IsDouble()) {
    525     Label do_store, heap_number;
    526     __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
    527 
    528     __ JumpIfNotSmi(value_reg, &heap_number);
    529     __ SmiUntag(value_reg);
    530     __ push(value_reg);
    531     __ fild_s(Operand(esp, 0));
    532     __ pop(value_reg);
    533     __ SmiTag(value_reg);
    534     __ jmp(&do_store);
    535 
    536     __ bind(&heap_number);
    537     __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
    538                 miss_label, DONT_DO_SMI_CHECK);
    539     __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
    540 
    541     __ bind(&do_store);
    542     __ fstp_d(FieldOperand(storage_reg, HeapNumber::kValueOffset));
    543   }
    544 
    545   // Stub never generated for non-global objects that require access
    546   // checks.
    547   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
    548 
    549   // Perform map transition for the receiver if necessary.
    550   if (details.type() == FIELD &&
    551       object->map()->unused_property_fields() == 0) {
    552     // The properties must be extended before we can store the value.
    553     // We jump to a runtime call that extends the properties array.
    554     __ pop(scratch1);  // Return address.
    555     __ push(receiver_reg);
    556     __ push(Immediate(transition));
    557     __ push(value_reg);
    558     __ push(scratch1);
    559     __ TailCallExternalReference(
    560         ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage),
    561                           masm->isolate()),
    562         3,
    563         1);
    564     return;
    565   }
    566 
    567   // Update the map of the object.
    568   __ mov(scratch1, Immediate(transition));
    569   __ mov(FieldOperand(receiver_reg, HeapObject::kMapOffset), scratch1);
    570 
    571   // Update the write barrier for the map field.
    572   __ RecordWriteField(receiver_reg,
    573                       HeapObject::kMapOffset,
    574                       scratch1,
    575                       scratch2,
    576                       OMIT_REMEMBERED_SET,
    577                       OMIT_SMI_CHECK);
    578 
    579   if (details.type() == CONSTANT) {
    580     ASSERT(value_reg.is(eax));
    581     __ ret(0);
    582     return;
    583   }
    584 
    585   int index = transition->instance_descriptors()->GetFieldIndex(
    586       transition->LastAdded());
    587 
    588   // Adjust for the number of properties stored in the object. Even in the
    589   // face of a transition we can use the old map here because the size of the
    590   // object and the number of in-object properties is not going to change.
    591   index -= object->map()->inobject_properties();
    592 
    593   SmiCheck smi_check = representation.IsTagged()
    594       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
    595   // TODO(verwaest): Share this code as a code stub.
    596   if (index < 0) {
    597     // Set the property straight into the object.
    598     int offset = object->map()->instance_size() + (index * kPointerSize);
    599     if (representation.IsDouble()) {
    600       __ mov(FieldOperand(receiver_reg, offset), storage_reg);
    601     } else {
    602       __ mov(FieldOperand(receiver_reg, offset), value_reg);
    603     }
    604 
    605     if (!representation.IsSmi()) {
    606       // Update the write barrier for the array address.
    607       if (!representation.IsDouble()) {
    608         __ mov(storage_reg, value_reg);
    609       }
    610       __ RecordWriteField(receiver_reg,
    611                           offset,
    612                           storage_reg,
    613                           scratch1,
    614                           EMIT_REMEMBERED_SET,
    615                           smi_check);
    616     }
    617   } else {
    618     // Write to the properties array.
    619     int offset = index * kPointerSize + FixedArray::kHeaderSize;
    620     // Get the properties array (optimistically).
    621     __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
    622     if (representation.IsDouble()) {
    623       __ mov(FieldOperand(scratch1, offset), storage_reg);
    624     } else {
    625       __ mov(FieldOperand(scratch1, offset), value_reg);
    626     }
    627 
    628     if (!representation.IsSmi()) {
    629       // Update the write barrier for the array address.
    630       if (!representation.IsDouble()) {
    631         __ mov(storage_reg, value_reg);
    632       }
    633       __ RecordWriteField(scratch1,
    634                           offset,
    635                           storage_reg,
    636                           receiver_reg,
    637                           EMIT_REMEMBERED_SET,
    638                           smi_check);
    639     }
    640   }
    641 
    642   // Return the value (register eax).
    643   ASSERT(value_reg.is(eax));
    644   __ ret(0);
    645 }
    646 
    647 
    648 // Both name_reg and receiver_reg are preserved on jumps to miss_label,
    649 // but may be destroyed if store is successful.
    650 void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
    651                                            Handle<JSObject> object,
    652                                            LookupResult* lookup,
    653                                            Register receiver_reg,
    654                                            Register name_reg,
    655                                            Register value_reg,
    656                                            Register scratch1,
    657                                            Register scratch2,
    658                                            Label* miss_label) {
    659   // Stub never generated for non-global objects that require access
    660   // checks.
    661   ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
    662 
    663   FieldIndex index = lookup->GetFieldIndex();
    664 
    665   Representation representation = lookup->representation();
    666   ASSERT(!representation.IsNone());
    667   if (representation.IsSmi()) {
    668     __ JumpIfNotSmi(value_reg, miss_label);
    669   } else if (representation.IsHeapObject()) {
    670     __ JumpIfSmi(value_reg, miss_label);
    671     HeapType* field_type = lookup->GetFieldType();
    672     HeapType::Iterator<Map> it = field_type->Classes();
    673     if (!it.Done()) {
    674       Label do_store;
    675       while (true) {
    676         __ CompareMap(value_reg, it.Current());
    677         it.Advance();
    678         if (it.Done()) {
    679           __ j(not_equal, miss_label);
    680           break;
    681         }
    682         __ j(equal, &do_store, Label::kNear);
    683       }
    684       __ bind(&do_store);
    685     }
    686   } else if (representation.IsDouble()) {
    687     // Load the double storage.
    688     if (index.is_inobject()) {
    689       __ mov(scratch1, FieldOperand(receiver_reg, index.offset()));
    690     } else {
    691       __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
    692       __ mov(scratch1, FieldOperand(scratch1, index.offset()));
    693     }
    694 
    695     // Store the value into the storage.
    696     Label do_store, heap_number;
    697     __ JumpIfNotSmi(value_reg, &heap_number);
    698     __ SmiUntag(value_reg);
    699     __ push(value_reg);
    700     __ fild_s(Operand(esp, 0));
    701     __ pop(value_reg);
    702     __ SmiTag(value_reg);
    703     __ jmp(&do_store);
    704     __ bind(&heap_number);
    705     __ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
    706                 miss_label, DONT_DO_SMI_CHECK);
    707     __ fld_d(FieldOperand(value_reg, HeapNumber::kValueOffset));
    708     __ bind(&do_store);
    709     __ fstp_d(FieldOperand(scratch1, HeapNumber::kValueOffset));
    710     // Return the value (register eax).
    711     ASSERT(value_reg.is(eax));
    712     __ ret(0);
    713     return;
    714   }
    715 
    716   ASSERT(!representation.IsDouble());
    717   // TODO(verwaest): Share this code as a code stub.
    718   SmiCheck smi_check = representation.IsTagged()
    719       ? INLINE_SMI_CHECK : OMIT_SMI_CHECK;
    720   if (index.is_inobject()) {
    721     // Set the property straight into the object.
    722     __ mov(FieldOperand(receiver_reg, index.offset()), value_reg);
    723 
    724     if (!representation.IsSmi()) {
    725       // Update the write barrier for the array address.
    726       // Pass the value being stored in the now unused name_reg.
    727       __ mov(name_reg, value_reg);
    728       __ RecordWriteField(receiver_reg,
    729                           index.offset(),
    730                           name_reg,
    731                           scratch1,
    732                           EMIT_REMEMBERED_SET,
    733                           smi_check);
    734     }
    735   } else {
    736     // Write to the properties array.
    737     // Get the properties array (optimistically).
    738     __ mov(scratch1, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
    739     __ mov(FieldOperand(scratch1, index.offset()), value_reg);
    740 
    741     if (!representation.IsSmi()) {
    742       // Update the write barrier for the array address.
    743       // Pass the value being stored in the now unused name_reg.
    744       __ mov(name_reg, value_reg);
    745       __ RecordWriteField(scratch1,
    746                           index.offset(),
    747                           name_reg,
    748                           receiver_reg,
    749                           EMIT_REMEMBERED_SET,
    750                           smi_check);
    751     }
    752   }
    753 
    754   // Return the value (register eax).
    755   ASSERT(value_reg.is(eax));
    756   __ ret(0);
    757 }
    758 
    759 
    760 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
    761   __ jmp(code, RelocInfo::CODE_TARGET);
    762 }
    763 
    764 
    765 #undef __
    766 #define __ ACCESS_MASM(masm())
    767 
    768 
    769 Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
    770                                        Register object_reg,
    771                                        Handle<JSObject> holder,
    772                                        Register holder_reg,
    773                                        Register scratch1,
    774                                        Register scratch2,
    775                                        Handle<Name> name,
    776                                        Label* miss,
    777                                        PrototypeCheckType check) {
    778   Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
    779 
    780   // Make sure there's no overlap between holder and object registers.
    781   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
    782   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
    783          && !scratch2.is(scratch1));
    784 
    785   // Keep track of the current object in register reg.
    786   Register reg = object_reg;
    787   int depth = 0;
    788 
    789   Handle<JSObject> current = Handle<JSObject>::null();
    790   if (type->IsConstant()) current =
    791       Handle<JSObject>::cast(type->AsConstant()->Value());
    792   Handle<JSObject> prototype = Handle<JSObject>::null();
    793   Handle<Map> current_map = receiver_map;
    794   Handle<Map> holder_map(holder->map());
    795   // Traverse the prototype chain and check the maps in the prototype chain for
    796   // fast and global objects or do negative lookup for normal objects.
    797   while (!current_map.is_identical_to(holder_map)) {
    798     ++depth;
    799 
    800     // Only global objects and objects that do not require access
    801     // checks are allowed in stubs.
    802     ASSERT(current_map->IsJSGlobalProxyMap() ||
    803            !current_map->is_access_check_needed());
    804 
    805     prototype = handle(JSObject::cast(current_map->prototype()));
    806     if (current_map->is_dictionary_map() &&
    807         !current_map->IsJSGlobalObjectMap() &&
    808         !current_map->IsJSGlobalProxyMap()) {
    809       if (!name->IsUniqueName()) {
    810         ASSERT(name->IsString());
    811         name = factory()->InternalizeString(Handle<String>::cast(name));
    812       }
    813       ASSERT(current.is_null() ||
    814              current->property_dictionary()->FindEntry(name) ==
    815              NameDictionary::kNotFound);
    816 
    817       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
    818                                        scratch1, scratch2);
    819 
    820       __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    821       reg = holder_reg;  // From now on the object will be in holder_reg.
    822       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    823     } else {
    824       bool in_new_space = heap()->InNewSpace(*prototype);
    825       if (depth != 1 || check == CHECK_ALL_MAPS) {
    826         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
    827       }
    828 
    829       // Check access rights to the global object.  This has to happen after
    830       // the map check so that we know that the object is actually a global
    831       // object.
    832       if (current_map->IsJSGlobalProxyMap()) {
    833         __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
    834       } else if (current_map->IsJSGlobalObjectMap()) {
    835         GenerateCheckPropertyCell(
    836             masm(), Handle<JSGlobalObject>::cast(current), name,
    837             scratch2, miss);
    838       }
    839 
    840       if (in_new_space) {
    841         // Save the map in scratch1 for later.
    842         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
    843       }
    844 
    845       reg = holder_reg;  // From now on the object will be in holder_reg.
    846 
    847       if (in_new_space) {
    848         // The prototype is in new space; we cannot store a reference to it
    849         // in the code.  Load it from the map.
    850         __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
    851       } else {
    852         // The prototype is in old space; load it directly.
    853         __ mov(reg, prototype);
    854       }
    855     }
    856 
    857     // Go to the next object in the prototype chain.
    858     current = prototype;
    859     current_map = handle(current->map());
    860   }
    861 
    862   // Log the check depth.
    863   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
    864 
    865   if (depth != 0 || check == CHECK_ALL_MAPS) {
    866     // Check the holder map.
    867     __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
    868   }
    869 
    870   // Perform security check for access to the global object.
    871   ASSERT(current_map->IsJSGlobalProxyMap() ||
    872          !current_map->is_access_check_needed());
    873   if (current_map->IsJSGlobalProxyMap()) {
    874     __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
    875   }
    876 
    877   // Return the register containing the holder.
    878   return reg;
    879 }
    880 
    881 
    882 void LoadStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
    883   if (!miss->is_unused()) {
    884     Label success;
    885     __ jmp(&success);
    886     __ bind(miss);
    887     TailCallBuiltin(masm(), MissBuiltin(kind()));
    888     __ bind(&success);
    889   }
    890 }
    891 
    892 
    893 void StoreStubCompiler::HandlerFrontendFooter(Handle<Name> name, Label* miss) {
    894   if (!miss->is_unused()) {
    895     Label success;
    896     __ jmp(&success);
    897     GenerateRestoreName(masm(), miss, name);
    898     TailCallBuiltin(masm(), MissBuiltin(kind()));
    899     __ bind(&success);
    900   }
    901 }
    902 
    903 
    904 Register LoadStubCompiler::CallbackHandlerFrontend(
    905     Handle<HeapType> type,
    906     Register object_reg,
    907     Handle<JSObject> holder,
    908     Handle<Name> name,
    909     Handle<Object> callback) {
    910   Label miss;
    911 
    912   Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
    913 
    914   if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
    915     ASSERT(!reg.is(scratch2()));
    916     ASSERT(!reg.is(scratch3()));
    917     Register dictionary = scratch1();
    918     bool must_preserve_dictionary_reg = reg.is(dictionary);
    919 
    920     // Load the properties dictionary.
    921     if (must_preserve_dictionary_reg) {
    922       __ push(dictionary);
    923     }
    924     __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset));
    925 
    926     // Probe the dictionary.
    927     Label probe_done, pop_and_miss;
    928     NameDictionaryLookupStub::GeneratePositiveLookup(masm(),
    929                                                      &pop_and_miss,
    930                                                      &probe_done,
    931                                                      dictionary,
    932                                                      this->name(),
    933                                                      scratch2(),
    934                                                      scratch3());
    935     __ bind(&pop_and_miss);
    936     if (must_preserve_dictionary_reg) {
    937       __ pop(dictionary);
    938     }
    939     __ jmp(&miss);
    940     __ bind(&probe_done);
    941 
    942     // If probing finds an entry in the dictionary, scratch2 contains the
    943     // index into the dictionary. Check that the value is the callback.
    944     Register index = scratch2();
    945     const int kElementsStartOffset =
    946         NameDictionary::kHeaderSize +
    947         NameDictionary::kElementsStartIndex * kPointerSize;
    948     const int kValueOffset = kElementsStartOffset + kPointerSize;
    949     __ mov(scratch3(),
    950            Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag));
    951     if (must_preserve_dictionary_reg) {
    952       __ pop(dictionary);
    953     }
    954     __ cmp(scratch3(), callback);
    955     __ j(not_equal, &miss);
    956   }
    957 
    958   HandlerFrontendFooter(name, &miss);
    959   return reg;
    960 }
    961 
    962 
    963 void LoadStubCompiler::GenerateLoadField(Register reg,
    964                                          Handle<JSObject> holder,
    965                                          FieldIndex field,
    966                                          Representation representation) {
    967   if (!reg.is(receiver())) __ mov(receiver(), reg);
    968   if (kind() == Code::LOAD_IC) {
    969     LoadFieldStub stub(isolate(), field);
    970     GenerateTailCall(masm(), stub.GetCode());
    971   } else {
    972     KeyedLoadFieldStub stub(isolate(), field);
    973     GenerateTailCall(masm(), stub.GetCode());
    974   }
    975 }
    976 
    977 
    978 void LoadStubCompiler::GenerateLoadCallback(
    979     Register reg,
    980     Handle<ExecutableAccessorInfo> callback) {
    981   // Insert additional parameters into the stack frame above return address.
    982   ASSERT(!scratch3().is(reg));
    983   __ pop(scratch3());  // Get return address to place it below.
    984 
    985   STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0);
    986   STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1);
    987   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2);
    988   STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3);
    989   STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4);
    990   STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5);
    991   __ push(receiver());  // receiver
    992   // Push data from ExecutableAccessorInfo.
    993   if (isolate()->heap()->InNewSpace(callback->data())) {
    994     ASSERT(!scratch2().is(reg));
    995     __ mov(scratch2(), Immediate(callback));
    996     __ push(FieldOperand(scratch2(), ExecutableAccessorInfo::kDataOffset));
    997   } else {
    998     __ push(Immediate(Handle<Object>(callback->data(), isolate())));
    999   }
   1000   __ push(Immediate(isolate()->factory()->undefined_value()));  // ReturnValue
   1001   // ReturnValue default value
   1002   __ push(Immediate(isolate()->factory()->undefined_value()));
   1003   __ push(Immediate(reinterpret_cast<int>(isolate())));
   1004   __ push(reg);  // holder
   1005 
   1006   // Save a pointer to where we pushed the arguments. This will be
   1007   // passed as the const PropertyAccessorInfo& to the C++ callback.
   1008   __ push(esp);
   1009 
   1010   __ push(name());  // name
   1011 
   1012   __ push(scratch3());  // Restore return address.
   1013 
   1014   // Abi for CallApiGetter
   1015   Register getter_address = edx;
   1016   Address function_address = v8::ToCData<Address>(callback->getter());
   1017   __ mov(getter_address, Immediate(function_address));
   1018 
   1019   CallApiGetterStub stub(isolate());
   1020   __ TailCallStub(&stub);
   1021 }
   1022 
   1023 
   1024 void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) {
   1025   // Return the constant value.
   1026   __ LoadObject(eax, value);
   1027   __ ret(0);
   1028 }
   1029 
   1030 
   1031 void LoadStubCompiler::GenerateLoadInterceptor(
   1032     Register holder_reg,
   1033     Handle<Object> object,
   1034     Handle<JSObject> interceptor_holder,
   1035     LookupResult* lookup,
   1036     Handle<Name> name) {
   1037   ASSERT(interceptor_holder->HasNamedInterceptor());
   1038   ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined());
   1039 
   1040   // So far the most popular follow ups for interceptor loads are FIELD
   1041   // and CALLBACKS, so inline only them, other cases may be added
   1042   // later.
   1043   bool compile_followup_inline = false;
   1044   if (lookup->IsFound() && lookup->IsCacheable()) {
   1045     if (lookup->IsField()) {
   1046       compile_followup_inline = true;
   1047     } else if (lookup->type() == CALLBACKS &&
   1048                lookup->GetCallbackObject()->IsExecutableAccessorInfo()) {
   1049       ExecutableAccessorInfo* callback =
   1050           ExecutableAccessorInfo::cast(lookup->GetCallbackObject());
   1051       compile_followup_inline = callback->getter() != NULL &&
   1052           callback->IsCompatibleReceiver(*object);
   1053     }
   1054   }
   1055 
   1056   if (compile_followup_inline) {
   1057     // Compile the interceptor call, followed by inline code to load the
   1058     // property from further up the prototype chain if the call fails.
   1059     // Check that the maps haven't changed.
   1060     ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
   1061 
   1062     // Preserve the receiver register explicitly whenever it is different from
   1063     // the holder and it is needed should the interceptor return without any
   1064     // result. The CALLBACKS case needs the receiver to be passed into C++ code,
   1065     // the FIELD case might cause a miss during the prototype check.
   1066     bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder();
   1067     bool must_preserve_receiver_reg = !receiver().is(holder_reg) &&
   1068         (lookup->type() == CALLBACKS || must_perfrom_prototype_check);
   1069 
   1070     // Save necessary data before invoking an interceptor.
   1071     // Requires a frame to make GC aware of pushed pointers.
   1072     {
   1073       FrameScope frame_scope(masm(), StackFrame::INTERNAL);
   1074 
   1075       if (must_preserve_receiver_reg) {
   1076         __ push(receiver());
   1077       }
   1078       __ push(holder_reg);
   1079       __ push(this->name());
   1080 
   1081       // Invoke an interceptor.  Note: map checks from receiver to
   1082       // interceptor's holder has been compiled before (see a caller
   1083       // of this method.)
   1084       CompileCallLoadPropertyWithInterceptor(
   1085           masm(), receiver(), holder_reg, this->name(), interceptor_holder,
   1086           IC::kLoadPropertyWithInterceptorOnly);
   1087 
   1088       // Check if interceptor provided a value for property.  If it's
   1089       // the case, return immediately.
   1090       Label interceptor_failed;
   1091       __ cmp(eax, factory()->no_interceptor_result_sentinel());
   1092       __ j(equal, &interceptor_failed);
   1093       frame_scope.GenerateLeaveFrame();
   1094       __ ret(0);
   1095 
   1096       // Clobber registers when generating debug-code to provoke errors.
   1097       __ bind(&interceptor_failed);
   1098       if (FLAG_debug_code) {
   1099         __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue)));
   1100         __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue)));
   1101         __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue)));
   1102       }
   1103 
   1104       __ pop(this->name());
   1105       __ pop(holder_reg);
   1106       if (must_preserve_receiver_reg) {
   1107         __ pop(receiver());
   1108       }
   1109 
   1110       // Leave the internal frame.
   1111     }
   1112 
   1113     GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup);
   1114   } else {  // !compile_followup_inline
   1115     // Call the runtime system to load the interceptor.
   1116     // Check that the maps haven't changed.
   1117     __ pop(scratch2());  // save old return address
   1118     PushInterceptorArguments(masm(), receiver(), holder_reg,
   1119                              this->name(), interceptor_holder);
   1120     __ push(scratch2());  // restore old return address
   1121 
   1122     ExternalReference ref =
   1123         ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptor),
   1124                           isolate());
   1125     __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
   1126   }
   1127 }
   1128 
   1129 
   1130 Handle<Code> StoreStubCompiler::CompileStoreCallback(
   1131     Handle<JSObject> object,
   1132     Handle<JSObject> holder,
   1133     Handle<Name> name,
   1134     Handle<ExecutableAccessorInfo> callback) {
   1135   Register holder_reg = HandlerFrontend(
   1136       IC::CurrentTypeOf(object, isolate()), receiver(), holder, name);
   1137 
   1138   __ pop(scratch1());  // remove the return address
   1139   __ push(receiver());
   1140   __ push(holder_reg);
   1141   __ Push(callback);
   1142   __ Push(name);
   1143   __ push(value());
   1144   __ push(scratch1());  // restore return address
   1145 
   1146   // Do tail-call to the runtime system.
   1147   ExternalReference store_callback_property =
   1148       ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
   1149   __ TailCallExternalReference(store_callback_property, 5, 1);
   1150 
   1151   // Return the generated code.
   1152   return GetCode(kind(), Code::FAST, name);
   1153 }
   1154 
   1155 
   1156 #undef __
   1157 #define __ ACCESS_MASM(masm)
   1158 
   1159 
   1160 void StoreStubCompiler::GenerateStoreViaSetter(
   1161     MacroAssembler* masm,
   1162     Handle<HeapType> type,
   1163     Register receiver,
   1164     Handle<JSFunction> setter) {
   1165   // ----------- S t a t e -------------
   1166   //  -- esp[0] : return address
   1167   // -----------------------------------
   1168   {
   1169     FrameScope scope(masm, StackFrame::INTERNAL);
   1170 
   1171     // Save value register, so we can restore it later.
   1172     __ push(value());
   1173 
   1174     if (!setter.is_null()) {
   1175       // Call the JavaScript setter with receiver and value on the stack.
   1176       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
   1177         // Swap in the global receiver.
   1178         __ mov(receiver,
   1179                FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
   1180       }
   1181       __ push(receiver);
   1182       __ push(value());
   1183       ParameterCount actual(1);
   1184       ParameterCount expected(setter);
   1185       __ InvokeFunction(setter, expected, actual,
   1186                         CALL_FUNCTION, NullCallWrapper());
   1187     } else {
   1188       // If we generate a global code snippet for deoptimization only, remember
   1189       // the place to continue after deoptimization.
   1190       masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset());
   1191     }
   1192 
   1193     // We have to return the passed value, not the return value of the setter.
   1194     __ pop(eax);
   1195 
   1196     // Restore context register.
   1197     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   1198   }
   1199   __ ret(0);
   1200 }
   1201 
   1202 
   1203 #undef __
   1204 #define __ ACCESS_MASM(masm())
   1205 
   1206 
   1207 Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
   1208     Handle<JSObject> object,
   1209     Handle<Name> name) {
   1210   __ pop(scratch1());  // remove the return address
   1211   __ push(receiver());
   1212   __ push(this->name());
   1213   __ push(value());
   1214   __ push(scratch1());  // restore return address
   1215 
   1216   // Do tail-call to the runtime system.
   1217   ExternalReference store_ic_property =
   1218       ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
   1219   __ TailCallExternalReference(store_ic_property, 3, 1);
   1220 
   1221   // Return the generated code.
   1222   return GetCode(kind(), Code::FAST, name);
   1223 }
   1224 
   1225 
   1226 void StoreStubCompiler::GenerateStoreArrayLength() {
   1227   // Prepare tail call to StoreIC_ArrayLength.
   1228   __ pop(scratch1());  // remove the return address
   1229   __ push(receiver());
   1230   __ push(value());
   1231   __ push(scratch1());  // restore return address
   1232 
   1233   ExternalReference ref =
   1234       ExternalReference(IC_Utility(IC::kStoreIC_ArrayLength),
   1235                         masm()->isolate());
   1236   __ TailCallExternalReference(ref, 2, 1);
   1237 }
   1238 
   1239 
   1240 Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
   1241     MapHandleList* receiver_maps,
   1242     CodeHandleList* handler_stubs,
   1243     MapHandleList* transitioned_maps) {
   1244   Label miss;
   1245   __ JumpIfSmi(receiver(), &miss, Label::kNear);
   1246   __ mov(scratch1(), FieldOperand(receiver(), HeapObject::kMapOffset));
   1247   for (int i = 0; i < receiver_maps->length(); ++i) {
   1248     __ cmp(scratch1(), receiver_maps->at(i));
   1249     if (transitioned_maps->at(i).is_null()) {
   1250       __ j(equal, handler_stubs->at(i));
   1251     } else {
   1252       Label next_map;
   1253       __ j(not_equal, &next_map, Label::kNear);
   1254       __ mov(transition_map(), Immediate(transitioned_maps->at(i)));
   1255       __ jmp(handler_stubs->at(i), RelocInfo::CODE_TARGET);
   1256       __ bind(&next_map);
   1257     }
   1258   }
   1259   __ bind(&miss);
   1260   TailCallBuiltin(masm(), MissBuiltin(kind()));
   1261 
   1262   // Return the generated code.
   1263   return GetICCode(
   1264       kind(), Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
   1265 }
   1266 
   1267 
   1268 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type,
   1269                                                       Handle<JSObject> last,
   1270                                                       Handle<Name> name) {
   1271   NonexistentHandlerFrontend(type, last, name);
   1272 
   1273   // Return undefined if maps of the full prototype chain are still the
   1274   // same and no global property with this name contains a value.
   1275   __ mov(eax, isolate()->factory()->undefined_value());
   1276   __ ret(0);
   1277 
   1278   // Return the generated code.
   1279   return GetCode(kind(), Code::FAST, name);
   1280 }
   1281 
   1282 
   1283 Register* LoadStubCompiler::registers() {
   1284   // receiver, name, scratch1, scratch2, scratch3, scratch4.
   1285   static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
   1286   return registers;
   1287 }
   1288 
   1289 
   1290 Register* KeyedLoadStubCompiler::registers() {
   1291   // receiver, name, scratch1, scratch2, scratch3, scratch4.
   1292   static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg };
   1293   return registers;
   1294 }
   1295 
   1296 
   1297 Register StoreStubCompiler::value() {
   1298   return eax;
   1299 }
   1300 
   1301 
   1302 Register* StoreStubCompiler::registers() {
   1303   // receiver, name, scratch1, scratch2, scratch3.
   1304   static Register registers[] = { edx, ecx, ebx, edi, no_reg };
   1305   return registers;
   1306 }
   1307 
   1308 
   1309 Register* KeyedStoreStubCompiler::registers() {
   1310   // receiver, name, scratch1, scratch2, scratch3.
   1311   static Register registers[] = { edx, ecx, ebx, edi, no_reg };
   1312   return registers;
   1313 }
   1314 
   1315 
   1316 #undef __
   1317 #define __ ACCESS_MASM(masm)
   1318 
   1319 
   1320 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
   1321                                              Handle<HeapType> type,
   1322                                              Register receiver,
   1323                                              Handle<JSFunction> getter) {
   1324   {
   1325     FrameScope scope(masm, StackFrame::INTERNAL);
   1326 
   1327     if (!getter.is_null()) {
   1328       // Call the JavaScript getter with the receiver on the stack.
   1329       if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) {
   1330         // Swap in the global receiver.
   1331         __ mov(receiver,
   1332                 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
   1333       }
   1334       __ push(receiver);
   1335       ParameterCount actual(0);
   1336       ParameterCount expected(getter);
   1337       __ InvokeFunction(getter, expected, actual,
   1338                         CALL_FUNCTION, NullCallWrapper());
   1339     } else {
   1340       // If we generate a global code snippet for deoptimization only, remember
   1341       // the place to continue after deoptimization.
   1342       masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
   1343     }
   1344 
   1345     // Restore context register.
   1346     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
   1347   }
   1348   __ ret(0);
   1349 }
   1350 
   1351 
   1352 #undef __
   1353 #define __ ACCESS_MASM(masm())
   1354 
   1355 
   1356 Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   1357     Handle<HeapType> type,
   1358     Handle<GlobalObject> global,
   1359     Handle<PropertyCell> cell,
   1360     Handle<Name> name,
   1361     bool is_dont_delete) {
   1362   Label miss;
   1363 
   1364   HandlerFrontendHeader(type, receiver(), global, name, &miss);
   1365   // Get the value from the cell.
   1366   if (masm()->serializer_enabled()) {
   1367     __ mov(eax, Immediate(cell));
   1368     __ mov(eax, FieldOperand(eax, PropertyCell::kValueOffset));
   1369   } else {
   1370     __ mov(eax, Operand::ForCell(cell));
   1371   }
   1372 
   1373   // Check for deleted property if property can actually be deleted.
   1374   if (!is_dont_delete) {
   1375     __ cmp(eax, factory()->the_hole_value());
   1376     __ j(equal, &miss);
   1377   } else if (FLAG_debug_code) {
   1378     __ cmp(eax, factory()->the_hole_value());
   1379     __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
   1380   }
   1381 
   1382   Counters* counters = isolate()->counters();
   1383   __ IncrementCounter(counters->named_load_global_stub(), 1);
   1384   // The code above already loads the result into the return register.
   1385   __ ret(0);
   1386 
   1387   HandlerFrontendFooter(name, &miss);
   1388 
   1389   // Return the generated code.
   1390   return GetCode(kind(), Code::NORMAL, name);
   1391 }
   1392 
   1393 
   1394 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
   1395     TypeHandleList* types,
   1396     CodeHandleList* handlers,
   1397     Handle<Name> name,
   1398     Code::StubType type,
   1399     IcCheckType check) {
   1400   Label miss;
   1401 
   1402   if (check == PROPERTY &&
   1403       (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) {
   1404     __ cmp(this->name(), Immediate(name));
   1405     __ j(not_equal, &miss);
   1406   }
   1407 
   1408   Label number_case;
   1409   Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
   1410   __ JumpIfSmi(receiver(), smi_target);
   1411 
   1412   Register map_reg = scratch1();
   1413   __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   1414   int receiver_count = types->length();
   1415   int number_of_handled_maps = 0;
   1416   for (int current = 0; current < receiver_count; ++current) {
   1417     Handle<HeapType> type = types->at(current);
   1418     Handle<Map> map = IC::TypeToMap(*type, isolate());
   1419     if (!map->is_deprecated()) {
   1420       number_of_handled_maps++;
   1421       __ cmp(map_reg, map);
   1422       if (type->Is(HeapType::Number())) {
   1423         ASSERT(!number_case.is_unused());
   1424         __ bind(&number_case);
   1425       }
   1426       __ j(equal, handlers->at(current));
   1427     }
   1428   }
   1429   ASSERT(number_of_handled_maps != 0);
   1430 
   1431   __ bind(&miss);
   1432   TailCallBuiltin(masm(), MissBuiltin(kind()));
   1433 
   1434   // Return the generated code.
   1435   InlineCacheState state =
   1436       number_of_handled_maps > 1 ? POLYMORPHIC : MONOMORPHIC;
   1437   return GetICCode(kind(), type, name, state);
   1438 }
   1439 
   1440 
   1441 #undef __
   1442 #define __ ACCESS_MASM(masm)
   1443 
   1444 
   1445 void KeyedLoadStubCompiler::GenerateLoadDictionaryElement(
   1446     MacroAssembler* masm) {
   1447   // ----------- S t a t e -------------
   1448   //  -- ecx    : key
   1449   //  -- edx    : receiver
   1450   //  -- esp[0] : return address
   1451   // -----------------------------------
   1452   Label slow, miss;
   1453 
   1454   // This stub is meant to be tail-jumped to, the receiver must already
   1455   // have been verified by the caller to not be a smi.
   1456   __ JumpIfNotSmi(ecx, &miss);
   1457   __ mov(ebx, ecx);
   1458   __ SmiUntag(ebx);
   1459   __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
   1460 
   1461   // Push receiver on the stack to free up a register for the dictionary
   1462   // probing.
   1463   __ push(edx);
   1464   __ LoadFromNumberDictionary(&slow, eax, ecx, ebx, edx, edi, eax);
   1465   // Pop receiver before returning.
   1466   __ pop(edx);
   1467   __ ret(0);
   1468 
   1469   __ bind(&slow);
   1470   __ pop(edx);
   1471 
   1472   // ----------- S t a t e -------------
   1473   //  -- ecx    : key
   1474   //  -- edx    : receiver
   1475   //  -- esp[0] : return address
   1476   // -----------------------------------
   1477   TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Slow);
   1478 
   1479   __ bind(&miss);
   1480   // ----------- S t a t e -------------
   1481   //  -- ecx    : key
   1482   //  -- edx    : receiver
   1483   //  -- esp[0] : return address
   1484   // -----------------------------------
   1485   TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss);
   1486 }
   1487 
   1488 
   1489 #undef __
   1490 
   1491 } }  // namespace v8::internal
   1492 
   1493 #endif  // V8_TARGET_ARCH_X87
   1494