Home | History | Annotate | Download | only in ia32
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #if V8_TARGET_ARCH_IA32
     31 
     32 #include "codegen.h"
     33 #include "ic-inl.h"
     34 #include "runtime.h"
     35 #include "stub-cache.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 // ----------------------------------------------------------------------------
     41 // Static IC stub generators.
     42 //
     43 
     44 #define __ ACCESS_MASM(masm)
     45 
     46 
     47 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
     48                                             Register type,
     49                                             Label* global_object) {
     50   // Register usage:
     51   //   type: holds the receiver instance type on entry.
     52   __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
     53   __ j(equal, global_object);
     54   __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
     55   __ j(equal, global_object);
     56   __ cmp(type, JS_GLOBAL_PROXY_TYPE);
     57   __ j(equal, global_object);
     58 }
     59 
     60 
     61 // Generated code falls through if the receiver is a regular non-global
     62 // JS object with slow properties and no interceptors.
     63 static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
     64                                                 Register receiver,
     65                                                 Register r0,
     66                                                 Register r1,
     67                                                 Label* miss) {
     68   // Register usage:
     69   //   receiver: holds the receiver on entry and is unchanged.
     70   //   r0: used to hold receiver instance type.
     71   //       Holds the property dictionary on fall through.
     72   //   r1: used to hold receivers map.
     73 
     74   // Check that the receiver isn't a smi.
     75   __ JumpIfSmi(receiver, miss);
     76 
     77   // Check that the receiver is a valid JS object.
     78   __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
     79   __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
     80   __ cmp(r0, FIRST_SPEC_OBJECT_TYPE);
     81   __ j(below, miss);
     82 
     83   // If this assert fails, we have to check upper bound too.
     84   STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
     85 
     86   GenerateGlobalInstanceTypeCheck(masm, r0, miss);
     87 
     88   // Check for non-global object that requires access check.
     89   __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
     90             (1 << Map::kIsAccessCheckNeeded) |
     91             (1 << Map::kHasNamedInterceptor));
     92   __ j(not_zero, miss);
     93 
     94   __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
     95   __ CheckMap(r0, masm->isolate()->factory()->hash_table_map(), miss,
     96               DONT_DO_SMI_CHECK);
     97 }
     98 
     99 
    100 // Helper function used to load a property from a dictionary backing
    101 // storage. This function may fail to load a property even though it is
    102 // in the dictionary, so code at miss_label must always call a backup
    103 // property load that is complete. This function is safe to call if
    104 // name is not internalized, and will jump to the miss_label in that
    105 // case. The generated code assumes that the receiver has slow
    106 // properties, is not a global object and does not have interceptors.
    107 static void GenerateDictionaryLoad(MacroAssembler* masm,
    108                                    Label* miss_label,
    109                                    Register elements,
    110                                    Register name,
    111                                    Register r0,
    112                                    Register r1,
    113                                    Register result) {
    114   // Register use:
    115   //
    116   // elements - holds the property dictionary on entry and is unchanged.
    117   //
    118   // name - holds the name of the property on entry and is unchanged.
    119   //
    120   // Scratch registers:
    121   //
    122   // r0   - used for the index into the property dictionary
    123   //
    124   // r1   - used to hold the capacity of the property dictionary.
    125   //
    126   // result - holds the result on exit.
    127 
    128   Label done;
    129 
    130   // Probe the dictionary.
    131   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
    132                                                    miss_label,
    133                                                    &done,
    134                                                    elements,
    135                                                    name,
    136                                                    r0,
    137                                                    r1);
    138 
    139   // If probing finds an entry in the dictionary, r0 contains the
    140   // index into the dictionary. Check that the value is a normal
    141   // property.
    142   __ bind(&done);
    143   const int kElementsStartOffset =
    144       NameDictionary::kHeaderSize +
    145       NameDictionary::kElementsStartIndex * kPointerSize;
    146   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    147   __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
    148           Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
    149   __ j(not_zero, miss_label);
    150 
    151   // Get the value at the masked, scaled index.
    152   const int kValueOffset = kElementsStartOffset + kPointerSize;
    153   __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
    154 }
    155 
    156 
    157 // Helper function used to store a property to a dictionary backing
    158 // storage. This function may fail to store a property eventhough it
    159 // is in the dictionary, so code at miss_label must always call a
    160 // backup property store that is complete. This function is safe to
    161 // call if name is not internalized, and will jump to the miss_label in
    162 // that case. The generated code assumes that the receiver has slow
    163 // properties, is not a global object and does not have interceptors.
    164 static void GenerateDictionaryStore(MacroAssembler* masm,
    165                                     Label* miss_label,
    166                                     Register elements,
    167                                     Register name,
    168                                     Register value,
    169                                     Register r0,
    170                                     Register r1) {
    171   // Register use:
    172   //
    173   // elements - holds the property dictionary on entry and is clobbered.
    174   //
    175   // name - holds the name of the property on entry and is unchanged.
    176   //
    177   // value - holds the value to store and is unchanged.
    178   //
    179   // r0 - used for index into the property dictionary and is clobbered.
    180   //
    181   // r1 - used to hold the capacity of the property dictionary and is clobbered.
    182   Label done;
    183 
    184 
    185   // Probe the dictionary.
    186   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
    187                                                    miss_label,
    188                                                    &done,
    189                                                    elements,
    190                                                    name,
    191                                                    r0,
    192                                                    r1);
    193 
    194   // If probing finds an entry in the dictionary, r0 contains the
    195   // index into the dictionary. Check that the value is a normal
    196   // property that is not read only.
    197   __ bind(&done);
    198   const int kElementsStartOffset =
    199       NameDictionary::kHeaderSize +
    200       NameDictionary::kElementsStartIndex * kPointerSize;
    201   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    202   const int kTypeAndReadOnlyMask =
    203       (PropertyDetails::TypeField::kMask |
    204        PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
    205   __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
    206           Immediate(kTypeAndReadOnlyMask));
    207   __ j(not_zero, miss_label);
    208 
    209   // Store the value at the masked, scaled index.
    210   const int kValueOffset = kElementsStartOffset + kPointerSize;
    211   __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
    212   __ mov(Operand(r0, 0), value);
    213 
    214   // Update write barrier. Make sure not to clobber the value.
    215   __ mov(r1, value);
    216   __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
    217 }
    218 
    219 
    220 // Checks the receiver for special cases (value type, slow case bits).
    221 // Falls through for regular JS object.
    222 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    223                                            Register receiver,
    224                                            Register map,
    225                                            int interceptor_bit,
    226                                            Label* slow) {
    227   // Register use:
    228   //   receiver - holds the receiver and is unchanged.
    229   // Scratch registers:
    230   //   map - used to hold the map of the receiver.
    231 
    232   // Check that the object isn't a smi.
    233   __ JumpIfSmi(receiver, slow);
    234 
    235   // Get the map of the receiver.
    236   __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
    237 
    238   // Check bit field.
    239   __ test_b(FieldOperand(map, Map::kBitFieldOffset),
    240             (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
    241   __ j(not_zero, slow);
    242   // Check that the object is some kind of JS object EXCEPT JS Value type.
    243   // In the case that the object is a value-wrapper object,
    244   // we enter the runtime system to make sure that indexing
    245   // into string objects works as intended.
    246   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    247 
    248   __ CmpInstanceType(map, JS_OBJECT_TYPE);
    249   __ j(below, slow);
    250 }
    251 
    252 
    253 // Loads an indexed element from a fast case array.
    254 // If not_fast_array is NULL, doesn't perform the elements map check.
    255 static void GenerateFastArrayLoad(MacroAssembler* masm,
    256                                   Register receiver,
    257                                   Register key,
    258                                   Register scratch,
    259                                   Register result,
    260                                   Label* not_fast_array,
    261                                   Label* out_of_range) {
    262   // Register use:
    263   //   receiver - holds the receiver and is unchanged.
    264   //   key - holds the key and is unchanged (must be a smi).
    265   // Scratch registers:
    266   //   scratch - used to hold elements of the receiver and the loaded value.
    267   //   result - holds the result on exit if the load succeeds and
    268   //            we fall through.
    269 
    270   __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
    271   if (not_fast_array != NULL) {
    272     // Check that the object is in fast mode and writable.
    273     __ CheckMap(scratch,
    274                 masm->isolate()->factory()->fixed_array_map(),
    275                 not_fast_array,
    276                 DONT_DO_SMI_CHECK);
    277   } else {
    278     __ AssertFastElements(scratch);
    279   }
    280   // Check that the key (index) is within bounds.
    281   __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
    282   __ j(above_equal, out_of_range);
    283   // Fast case: Do the load.
    284   STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
    285   __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
    286   __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value()));
    287   // In case the loaded value is the_hole we have to consult GetProperty
    288   // to ensure the prototype chain is searched.
    289   __ j(equal, out_of_range);
    290   if (!result.is(scratch)) {
    291     __ mov(result, scratch);
    292   }
    293 }
    294 
    295 
    296 // Checks whether a key is an array index string or a unique name.
    297 // Falls through if the key is a unique name.
    298 static void GenerateKeyNameCheck(MacroAssembler* masm,
    299                                  Register key,
    300                                  Register map,
    301                                  Register hash,
    302                                  Label* index_string,
    303                                  Label* not_unique) {
    304   // Register use:
    305   //   key - holds the key and is unchanged. Assumed to be non-smi.
    306   // Scratch registers:
    307   //   map - used to hold the map of the key.
    308   //   hash - used to hold the hash of the key.
    309   Label unique;
    310   __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
    311   __ j(above, not_unique);
    312   STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
    313   __ j(equal, &unique);
    314 
    315   // Is the string an array index, with cached numeric value?
    316   __ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
    317   __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
    318   __ j(zero, index_string);
    319 
    320   // Is the string internalized? We already know it's a string so a single
    321   // bit test is enough.
    322   STATIC_ASSERT(kNotInternalizedTag != 0);
    323   __ test_b(FieldOperand(map, Map::kInstanceTypeOffset),
    324             kIsNotInternalizedMask);
    325   __ j(not_zero, not_unique);
    326 
    327   __ bind(&unique);
    328 }
    329 
    330 
    331 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
    332                                              Register object,
    333                                              Register key,
    334                                              Register scratch1,
    335                                              Register scratch2,
    336                                              Label* unmapped_case,
    337                                              Label* slow_case) {
    338   Heap* heap = masm->isolate()->heap();
    339   Factory* factory = masm->isolate()->factory();
    340 
    341   // Check that the receiver is a JSObject. Because of the elements
    342   // map check later, we do not need to check for interceptors or
    343   // whether it requires access checks.
    344   __ JumpIfSmi(object, slow_case);
    345   // Check that the object is some kind of JSObject.
    346   __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
    347   __ j(below, slow_case);
    348 
    349   // Check that the key is a positive smi.
    350   __ test(key, Immediate(0x80000001));
    351   __ j(not_zero, slow_case);
    352 
    353   // Load the elements into scratch1 and check its map.
    354   Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
    355   __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
    356   __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
    357 
    358   // Check if element is in the range of mapped arguments. If not, jump
    359   // to the unmapped lookup with the parameter map in scratch1.
    360   __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
    361   __ sub(scratch2, Immediate(Smi::FromInt(2)));
    362   __ cmp(key, scratch2);
    363   __ j(above_equal, unmapped_case);
    364 
    365   // Load element index and check whether it is the hole.
    366   const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
    367   __ mov(scratch2, FieldOperand(scratch1,
    368                                 key,
    369                                 times_half_pointer_size,
    370                                 kHeaderSize));
    371   __ cmp(scratch2, factory->the_hole_value());
    372   __ j(equal, unmapped_case);
    373 
    374   // Load value from context and return it. We can reuse scratch1 because
    375   // we do not jump to the unmapped lookup (which requires the parameter
    376   // map in scratch1).
    377   const int kContextOffset = FixedArray::kHeaderSize;
    378   __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
    379   return FieldOperand(scratch1,
    380                       scratch2,
    381                       times_half_pointer_size,
    382                       Context::kHeaderSize);
    383 }
    384 
    385 
    386 static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
    387                                                Register key,
    388                                                Register parameter_map,
    389                                                Register scratch,
    390                                                Label* slow_case) {
    391   // Element is in arguments backing store, which is referenced by the
    392   // second element of the parameter_map.
    393   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
    394   Register backing_store = parameter_map;
    395   __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
    396   Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
    397   __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
    398   __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
    399   __ cmp(key, scratch);
    400   __ j(greater_equal, slow_case);
    401   return FieldOperand(backing_store,
    402                       key,
    403                       times_half_pointer_size,
    404                       FixedArray::kHeaderSize);
    405 }
    406 
    407 
    408 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
    409   // ----------- S t a t e -------------
    410   //  -- ecx    : key
    411   //  -- edx    : receiver
    412   //  -- esp[0] : return address
    413   // -----------------------------------
    414   Label slow, check_name, index_smi, index_name, property_array_property;
    415   Label probe_dictionary, check_number_dictionary;
    416 
    417   // Check that the key is a smi.
    418   __ JumpIfNotSmi(ecx, &check_name);
    419   __ bind(&index_smi);
    420   // Now the key is known to be a smi. This place is also jumped to from
    421   // where a numeric string is converted to a smi.
    422 
    423   GenerateKeyedLoadReceiverCheck(
    424       masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
    425 
    426   // Check the receiver's map to see if it has fast elements.
    427   __ CheckFastElements(eax, &check_number_dictionary);
    428 
    429   GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
    430   Isolate* isolate = masm->isolate();
    431   Counters* counters = isolate->counters();
    432   __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
    433   __ ret(0);
    434 
    435   __ bind(&check_number_dictionary);
    436   __ mov(ebx, ecx);
    437   __ SmiUntag(ebx);
    438   __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
    439 
    440   // Check whether the elements is a number dictionary.
    441   // edx: receiver
    442   // ebx: untagged index
    443   // ecx: key
    444   // eax: elements
    445   __ CheckMap(eax,
    446               isolate->factory()->hash_table_map(),
    447               &slow,
    448               DONT_DO_SMI_CHECK);
    449   Label slow_pop_receiver;
    450   // Push receiver on the stack to free up a register for the dictionary
    451   // probing.
    452   __ push(edx);
    453   __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
    454   // Pop receiver before returning.
    455   __ pop(edx);
    456   __ ret(0);
    457 
    458   __ bind(&slow_pop_receiver);
    459   // Pop the receiver from the stack and jump to runtime.
    460   __ pop(edx);
    461 
    462   __ bind(&slow);
    463   // Slow case: jump to runtime.
    464   // edx: receiver
    465   // ecx: key
    466   __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
    467   GenerateRuntimeGetProperty(masm);
    468 
    469   __ bind(&check_name);
    470   GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow);
    471 
    472   GenerateKeyedLoadReceiverCheck(
    473       masm, edx, eax, Map::kHasNamedInterceptor, &slow);
    474 
    475   // If the receiver is a fast-case object, check the keyed lookup
    476   // cache. Otherwise probe the dictionary.
    477   __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
    478   __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
    479          Immediate(isolate->factory()->hash_table_map()));
    480   __ j(equal, &probe_dictionary);
    481 
    482   // The receiver's map is still in eax, compute the keyed lookup cache hash
    483   // based on 32 bits of the map pointer and the string hash.
    484   if (FLAG_debug_code) {
    485     __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
    486     __ Check(equal, kMapIsNoLongerInEax);
    487   }
    488   __ mov(ebx, eax);  // Keep the map around for later.
    489   __ shr(eax, KeyedLookupCache::kMapHashShift);
    490   __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
    491   __ shr(edi, String::kHashShift);
    492   __ xor_(eax, edi);
    493   __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
    494 
    495   // Load the key (consisting of map and internalized string) from the cache and
    496   // check for match.
    497   Label load_in_object_property;
    498   static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
    499   Label hit_on_nth_entry[kEntriesPerBucket];
    500   ExternalReference cache_keys =
    501       ExternalReference::keyed_lookup_cache_keys(masm->isolate());
    502 
    503   for (int i = 0; i < kEntriesPerBucket - 1; i++) {
    504     Label try_next_entry;
    505     __ mov(edi, eax);
    506     __ shl(edi, kPointerSizeLog2 + 1);
    507     if (i != 0) {
    508       __ add(edi, Immediate(kPointerSize * i * 2));
    509     }
    510     __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
    511     __ j(not_equal, &try_next_entry);
    512     __ add(edi, Immediate(kPointerSize));
    513     __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
    514     __ j(equal, &hit_on_nth_entry[i]);
    515     __ bind(&try_next_entry);
    516   }
    517 
    518   __ lea(edi, Operand(eax, 1));
    519   __ shl(edi, kPointerSizeLog2 + 1);
    520   __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
    521   __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
    522   __ j(not_equal, &slow);
    523   __ add(edi, Immediate(kPointerSize));
    524   __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
    525   __ j(not_equal, &slow);
    526 
    527   // Get field offset.
    528   // edx     : receiver
    529   // ebx     : receiver's map
    530   // ecx     : key
    531   // eax     : lookup cache index
    532   ExternalReference cache_field_offsets =
    533       ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
    534 
    535   // Hit on nth entry.
    536   for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
    537     __ bind(&hit_on_nth_entry[i]);
    538     if (i != 0) {
    539       __ add(eax, Immediate(i));
    540     }
    541     __ mov(edi,
    542            Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
    543     __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
    544     __ sub(edi, eax);
    545     __ j(above_equal, &property_array_property);
    546     if (i != 0) {
    547       __ jmp(&load_in_object_property);
    548     }
    549   }
    550 
    551   // Load in-object property.
    552   __ bind(&load_in_object_property);
    553   __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
    554   __ add(eax, edi);
    555   __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
    556   __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
    557   __ ret(0);
    558 
    559   // Load property array property.
    560   __ bind(&property_array_property);
    561   __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
    562   __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
    563                            FixedArray::kHeaderSize));
    564   __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
    565   __ ret(0);
    566 
    567   // Do a quick inline probe of the receiver's dictionary, if it
    568   // exists.
    569   __ bind(&probe_dictionary);
    570 
    571   __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
    572   __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
    573   GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
    574 
    575   GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
    576   __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
    577   __ ret(0);
    578 
    579   __ bind(&index_name);
    580   __ IndexFromHash(ebx, ecx);
    581   // Now jump to the place where smi keys are handled.
    582   __ jmp(&index_smi);
    583 }
    584 
    585 
    586 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
    587   // ----------- S t a t e -------------
    588   //  -- ecx    : key (index)
    589   //  -- edx    : receiver
    590   //  -- esp[0] : return address
    591   // -----------------------------------
    592   Label miss;
    593 
    594   Register receiver = edx;
    595   Register index = ecx;
    596   Register scratch = ebx;
    597   Register result = eax;
    598 
    599   StringCharAtGenerator char_at_generator(receiver,
    600                                           index,
    601                                           scratch,
    602                                           result,
    603                                           &miss,  // When not a string.
    604                                           &miss,  // When not a number.
    605                                           &miss,  // When index out of range.
    606                                           STRING_INDEX_IS_ARRAY_INDEX);
    607   char_at_generator.GenerateFast(masm);
    608   __ ret(0);
    609 
    610   StubRuntimeCallHelper call_helper;
    611   char_at_generator.GenerateSlow(masm, call_helper);
    612 
    613   __ bind(&miss);
    614   GenerateMiss(masm, MISS);
    615 }
    616 
    617 
    618 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
    619   // ----------- S t a t e -------------
    620   //  -- ecx    : key
    621   //  -- edx    : receiver
    622   //  -- esp[0] : return address
    623   // -----------------------------------
    624   Label slow;
    625 
    626   // Check that the receiver isn't a smi.
    627   __ JumpIfSmi(edx, &slow);
    628 
    629   // Check that the key is an array index, that is Uint32.
    630   __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
    631   __ j(not_zero, &slow);
    632 
    633   // Get the map of the receiver.
    634   __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
    635 
    636   // Check that it has indexed interceptor and access checks
    637   // are not enabled for this object.
    638   __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
    639   __ and_(eax, Immediate(kSlowCaseBitFieldMask));
    640   __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
    641   __ j(not_zero, &slow);
    642 
    643   // Everything is fine, call runtime.
    644   __ pop(eax);
    645   __ push(edx);  // receiver
    646   __ push(ecx);  // key
    647   __ push(eax);  // return address
    648 
    649   // Perform tail call to the entry.
    650   ExternalReference ref =
    651       ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
    652                         masm->isolate());
    653   __ TailCallExternalReference(ref, 2, 1);
    654 
    655   __ bind(&slow);
    656   GenerateMiss(masm, MISS);
    657 }
    658 
    659 
    660 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
    661   // ----------- S t a t e -------------
    662   //  -- ecx    : key
    663   //  -- edx    : receiver
    664   //  -- esp[0] : return address
    665   // -----------------------------------
    666   Label slow, notin;
    667   Factory* factory = masm->isolate()->factory();
    668   Operand mapped_location =
    669       GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
    670   __ mov(eax, mapped_location);
    671   __ Ret();
    672   __ bind(&notin);
    673   // The unmapped lookup expects that the parameter map is in ebx.
    674   Operand unmapped_location =
    675       GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
    676   __ cmp(unmapped_location, factory->the_hole_value());
    677   __ j(equal, &slow);
    678   __ mov(eax, unmapped_location);
    679   __ Ret();
    680   __ bind(&slow);
    681   GenerateMiss(masm, MISS);
    682 }
    683 
    684 
    685 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
    686   // ----------- S t a t e -------------
    687   //  -- eax    : value
    688   //  -- ecx    : key
    689   //  -- edx    : receiver
    690   //  -- esp[0] : return address
    691   // -----------------------------------
    692   Label slow, notin;
    693   Operand mapped_location =
    694       GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
    695   __ mov(mapped_location, eax);
    696   __ lea(ecx, mapped_location);
    697   __ mov(edx, eax);
    698   __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
    699   __ Ret();
    700   __ bind(&notin);
    701   // The unmapped lookup expects that the parameter map is in ebx.
    702   Operand unmapped_location =
    703       GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
    704   __ mov(unmapped_location, eax);
    705   __ lea(edi, unmapped_location);
    706   __ mov(edx, eax);
    707   __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
    708   __ Ret();
    709   __ bind(&slow);
    710   GenerateMiss(masm, MISS);
    711 }
    712 
    713 
    714 static void KeyedStoreGenerateGenericHelper(
    715     MacroAssembler* masm,
    716     Label* fast_object,
    717     Label* fast_double,
    718     Label* slow,
    719     KeyedStoreCheckMap check_map,
    720     KeyedStoreIncrementLength increment_length) {
    721   Label transition_smi_elements;
    722   Label finish_object_store, non_double_value, transition_double_elements;
    723   Label fast_double_without_map_check;
    724   // eax: value
    725   // ecx: key (a smi)
    726   // edx: receiver
    727   // ebx: FixedArray receiver->elements
    728   // edi: receiver map
    729   // Fast case: Do the store, could either Object or double.
    730   __ bind(fast_object);
    731   if (check_map == kCheckMap) {
    732     __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
    733     __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
    734     __ j(not_equal, fast_double);
    735   }
    736   // Smi stores don't require further checks.
    737   Label non_smi_value;
    738   __ JumpIfNotSmi(eax, &non_smi_value);
    739   if (increment_length == kIncrementLength) {
    740     // Add 1 to receiver->length.
    741     __ add(FieldOperand(edx, JSArray::kLengthOffset),
    742            Immediate(Smi::FromInt(1)));
    743   }
    744   // It's irrelevant whether array is smi-only or not when writing a smi.
    745   __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
    746   __ ret(0);
    747 
    748   __ bind(&non_smi_value);
    749   // Escape to elements kind transition case.
    750   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
    751   __ CheckFastObjectElements(edi, &transition_smi_elements);
    752 
    753   // Fast elements array, store the value to the elements backing store.
    754   __ bind(&finish_object_store);
    755   if (increment_length == kIncrementLength) {
    756     // Add 1 to receiver->length.
    757     __ add(FieldOperand(edx, JSArray::kLengthOffset),
    758            Immediate(Smi::FromInt(1)));
    759   }
    760   __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
    761   // Update write barrier for the elements array address.
    762   __ mov(edx, eax);  // Preserve the value which is returned.
    763   __ RecordWriteArray(
    764       ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
    765   __ ret(0);
    766 
    767   __ bind(fast_double);
    768   if (check_map == kCheckMap) {
    769     // Check for fast double array case. If this fails, call through to the
    770     // runtime.
    771     __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
    772     __ j(not_equal, slow);
    773     // If the value is a number, store it as a double in the FastDoubleElements
    774     // array.
    775   }
    776   __ bind(&fast_double_without_map_check);
    777   __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
    778                                  &transition_double_elements, false);
    779   if (increment_length == kIncrementLength) {
    780     // Add 1 to receiver->length.
    781     __ add(FieldOperand(edx, JSArray::kLengthOffset),
    782            Immediate(Smi::FromInt(1)));
    783   }
    784   __ ret(0);
    785 
    786   __ bind(&transition_smi_elements);
    787   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
    788 
    789   // Transition the array appropriately depending on the value type.
    790   __ CheckMap(eax,
    791               masm->isolate()->factory()->heap_number_map(),
    792               &non_double_value,
    793               DONT_DO_SMI_CHECK);
    794 
    795   // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
    796   // and complete the store.
    797   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
    798                                          FAST_DOUBLE_ELEMENTS,
    799                                          ebx,
    800                                          edi,
    801                                          slow);
    802   AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
    803                                                     FAST_DOUBLE_ELEMENTS);
    804   ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
    805   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    806   __ jmp(&fast_double_without_map_check);
    807 
    808   __ bind(&non_double_value);
    809   // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
    810   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
    811                                          FAST_ELEMENTS,
    812                                          ebx,
    813                                          edi,
    814                                          slow);
    815   mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
    816   ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
    817                                                                    slow);
    818   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    819   __ jmp(&finish_object_store);
    820 
    821   __ bind(&transition_double_elements);
    822   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
    823   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
    824   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
    825   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
    826   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
    827                                          FAST_ELEMENTS,
    828                                          ebx,
    829                                          edi,
    830                                          slow);
    831   mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
    832   ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
    833   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    834   __ jmp(&finish_object_store);
    835 }
    836 
    837 
    838 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
    839                                    StrictModeFlag strict_mode) {
    840   // ----------- S t a t e -------------
    841   //  -- eax    : value
    842   //  -- ecx    : key
    843   //  -- edx    : receiver
    844   //  -- esp[0] : return address
    845   // -----------------------------------
    846   Label slow, fast_object, fast_object_grow;
    847   Label fast_double, fast_double_grow;
    848   Label array, extra, check_if_double_array;
    849 
    850   // Check that the object isn't a smi.
    851   __ JumpIfSmi(edx, &slow);
    852   // Get the map from the receiver.
    853   __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
    854   // Check that the receiver does not require access checks.  We need
    855   // to do this because this generic stub does not perform map checks.
    856   __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
    857             1 << Map::kIsAccessCheckNeeded);
    858   __ j(not_zero, &slow);
    859   // Check that the key is a smi.
    860   __ JumpIfNotSmi(ecx, &slow);
    861   __ CmpInstanceType(edi, JS_ARRAY_TYPE);
    862   __ j(equal, &array);
    863   // Check that the object is some kind of JSObject.
    864   __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
    865   __ j(below, &slow);
    866 
    867   // Object case: Check key against length in the elements array.
    868   // eax: value
    869   // edx: JSObject
    870   // ecx: key (a smi)
    871   // edi: receiver map
    872   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    873   // Check array bounds. Both the key and the length of FixedArray are smis.
    874   __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
    875   __ j(below, &fast_object);
    876 
    877   // Slow case: call runtime.
    878   __ bind(&slow);
    879   GenerateRuntimeSetProperty(masm, strict_mode);
    880 
    881   // Extra capacity case: Check if there is extra capacity to
    882   // perform the store and update the length. Used for adding one
    883   // element to the array by writing to array[array.length].
    884   __ bind(&extra);
    885   // eax: value
    886   // edx: receiver, a JSArray
    887   // ecx: key, a smi.
    888   // ebx: receiver->elements, a FixedArray
    889   // edi: receiver map
    890   // flags: compare (ecx, edx.length())
    891   // do not leave holes in the array:
    892   __ j(not_equal, &slow);
    893   __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
    894   __ j(above_equal, &slow);
    895   __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
    896   __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
    897   __ j(not_equal, &check_if_double_array);
    898   __ jmp(&fast_object_grow);
    899 
    900   __ bind(&check_if_double_array);
    901   __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
    902   __ j(not_equal, &slow);
    903   __ jmp(&fast_double_grow);
    904 
    905   // Array case: Get the length and the elements array from the JS
    906   // array. Check that the array is in fast mode (and writable); if it
    907   // is the length is always a smi.
    908   __ bind(&array);
    909   // eax: value
    910   // edx: receiver, a JSArray
    911   // ecx: key, a smi.
    912   // edi: receiver map
    913   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    914 
    915   // Check the key against the length in the array and fall through to the
    916   // common store code.
    917   __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
    918   __ j(above_equal, &extra);
    919 
    920   KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
    921                                   &slow, kCheckMap, kDontIncrementLength);
    922   KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
    923                                   &slow, kDontCheckMap, kIncrementLength);
    924 }
    925 
    926 
    927 // The generated code does not accept smi keys.
    928 // The generated code falls through if both probes miss.
    929 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
    930                                                int argc,
    931                                                Code::Kind kind,
    932                                                Code::ExtraICState extra_state) {
    933   // ----------- S t a t e -------------
    934   //  -- ecx                 : name
    935   //  -- edx                 : receiver
    936   // -----------------------------------
    937   Label number, non_number, non_string, boolean, probe, miss;
    938 
    939   // Probe the stub cache.
    940   Code::Flags flags = Code::ComputeFlags(kind,
    941                                          MONOMORPHIC,
    942                                          extra_state,
    943                                          Code::NORMAL,
    944                                          argc);
    945   Isolate* isolate = masm->isolate();
    946   isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
    947 
    948   // If the stub cache probing failed, the receiver might be a value.
    949   // For value objects, we use the map of the prototype objects for
    950   // the corresponding JSValue for the cache and that is what we need
    951   // to probe.
    952   //
    953   // Check for number.
    954   __ JumpIfSmi(edx, &number);
    955   __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
    956   __ j(not_equal, &non_number);
    957   __ bind(&number);
    958   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    959       masm, Context::NUMBER_FUNCTION_INDEX, edx);
    960   __ jmp(&probe);
    961 
    962   // Check for string.
    963   __ bind(&non_number);
    964   __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
    965   __ j(above_equal, &non_string);
    966   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    967       masm, Context::STRING_FUNCTION_INDEX, edx);
    968   __ jmp(&probe);
    969 
    970   // Check for boolean.
    971   __ bind(&non_string);
    972   __ cmp(edx, isolate->factory()->true_value());
    973   __ j(equal, &boolean);
    974   __ cmp(edx, isolate->factory()->false_value());
    975   __ j(not_equal, &miss);
    976   __ bind(&boolean);
    977   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    978       masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
    979 
    980   // Probe the stub cache for the value object.
    981   __ bind(&probe);
    982   isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
    983   __ bind(&miss);
    984 }
    985 
    986 
    987 static void GenerateFunctionTailCall(MacroAssembler* masm,
    988                                      int argc,
    989                                      Label* miss) {
    990   // ----------- S t a t e -------------
    991   //  -- ecx                 : name
    992   //  -- edi                 : function
    993   //  -- esp[0]              : return address
    994   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
    995   //  -- ...
    996   //  -- esp[(argc + 1) * 4] : receiver
    997   // -----------------------------------
    998 
    999   // Check that the result is not a smi.
   1000   __ JumpIfSmi(edi, miss);
   1001 
   1002   // Check that the value is a JavaScript function, fetching its map into eax.
   1003   __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
   1004   __ j(not_equal, miss);
   1005 
   1006   // Invoke the function.
   1007   ParameterCount actual(argc);
   1008   __ InvokeFunction(edi, actual, JUMP_FUNCTION,
   1009                     NullCallWrapper(), CALL_AS_METHOD);
   1010 }
   1011 
   1012 
   1013 // The generated code falls through if the call should be handled by runtime.
   1014 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
   1015   // ----------- S t a t e -------------
   1016   //  -- ecx                 : name
   1017   //  -- esp[0]              : return address
   1018   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1019   //  -- ...
   1020   //  -- esp[(argc + 1) * 4] : receiver
   1021   // -----------------------------------
   1022   Label miss;
   1023 
   1024   // Get the receiver of the function from the stack; 1 ~ return address.
   1025   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1026 
   1027   GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
   1028 
   1029   // eax: elements
   1030   // Search the dictionary placing the result in edi.
   1031   GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
   1032   GenerateFunctionTailCall(masm, argc, &miss);
   1033 
   1034   __ bind(&miss);
   1035 }
   1036 
   1037 
   1038 void CallICBase::GenerateMiss(MacroAssembler* masm,
   1039                               int argc,
   1040                               IC::UtilityId id,
   1041                               Code::ExtraICState extra_state) {
   1042   // ----------- S t a t e -------------
   1043   //  -- ecx                 : name
   1044   //  -- esp[0]              : return address
   1045   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1046   //  -- ...
   1047   //  -- esp[(argc + 1) * 4] : receiver
   1048   // -----------------------------------
   1049 
   1050   Counters* counters = masm->isolate()->counters();
   1051   if (id == IC::kCallIC_Miss) {
   1052     __ IncrementCounter(counters->call_miss(), 1);
   1053   } else {
   1054     __ IncrementCounter(counters->keyed_call_miss(), 1);
   1055   }
   1056 
   1057   // Get the receiver of the function from the stack; 1 ~ return address.
   1058   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1059 
   1060   {
   1061     FrameScope scope(masm, StackFrame::INTERNAL);
   1062 
   1063     // Push the receiver and the name of the function.
   1064     __ push(edx);
   1065     __ push(ecx);
   1066 
   1067     // Call the entry.
   1068     CEntryStub stub(1);
   1069     __ mov(eax, Immediate(2));
   1070     __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
   1071     __ CallStub(&stub);
   1072 
   1073     // Move result to edi and exit the internal frame.
   1074     __ mov(edi, eax);
   1075   }
   1076 
   1077   // Check if the receiver is a global object of some sort.
   1078   // This can happen only for regular CallIC but not KeyedCallIC.
   1079   if (id == IC::kCallIC_Miss) {
   1080     Label invoke, global;
   1081     __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
   1082     __ JumpIfSmi(edx, &invoke, Label::kNear);
   1083     __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
   1084     __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
   1085     __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
   1086     __ j(equal, &global, Label::kNear);
   1087     __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
   1088     __ j(not_equal, &invoke, Label::kNear);
   1089 
   1090     // Patch the receiver on the stack.
   1091     __ bind(&global);
   1092     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   1093     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   1094     __ bind(&invoke);
   1095   }
   1096 
   1097   // Invoke the function.
   1098   CallKind call_kind = CallICBase::Contextual::decode(extra_state)
   1099       ? CALL_AS_FUNCTION
   1100       : CALL_AS_METHOD;
   1101   ParameterCount actual(argc);
   1102   __ InvokeFunction(edi,
   1103                     actual,
   1104                     JUMP_FUNCTION,
   1105                     NullCallWrapper(),
   1106                     call_kind);
   1107 }
   1108 
   1109 
   1110 void CallIC::GenerateMegamorphic(MacroAssembler* masm,
   1111                                  int argc,
   1112                                  Code::ExtraICState extra_state) {
   1113   // ----------- S t a t e -------------
   1114   //  -- ecx                 : name
   1115   //  -- esp[0]              : return address
   1116   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1117   //  -- ...
   1118   //  -- esp[(argc + 1) * 4] : receiver
   1119   // -----------------------------------
   1120 
   1121   // Get the receiver of the function from the stack; 1 ~ return address.
   1122   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1123   CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
   1124                                             extra_state);
   1125 
   1126   GenerateMiss(masm, argc, extra_state);
   1127 }
   1128 
   1129 
   1130 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   1131   // ----------- S t a t e -------------
   1132   //  -- ecx                 : name
   1133   //  -- esp[0]              : return address
   1134   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1135   //  -- ...
   1136   //  -- esp[(argc + 1) * 4] : receiver
   1137   // -----------------------------------
   1138 
   1139   // Get the receiver of the function from the stack; 1 ~ return address.
   1140   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1141 
   1142   Label do_call, slow_call, slow_load, slow_reload_receiver;
   1143   Label check_number_dictionary, check_name, lookup_monomorphic_cache;
   1144   Label index_smi, index_name;
   1145 
   1146   // Check that the key is a smi.
   1147   __ JumpIfNotSmi(ecx, &check_name);
   1148 
   1149   __ bind(&index_smi);
   1150   // Now the key is known to be a smi. This place is also jumped to from
   1151   // where a numeric string is converted to a smi.
   1152 
   1153   GenerateKeyedLoadReceiverCheck(
   1154       masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
   1155 
   1156   GenerateFastArrayLoad(
   1157       masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
   1158   Isolate* isolate = masm->isolate();
   1159   Counters* counters = isolate->counters();
   1160   __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
   1161 
   1162   __ bind(&do_call);
   1163   // receiver in edx is not used after this point.
   1164   // ecx: key
   1165   // edi: function
   1166   GenerateFunctionTailCall(masm, argc, &slow_call);
   1167 
   1168   __ bind(&check_number_dictionary);
   1169   // eax: elements
   1170   // ecx: smi key
   1171   // Check whether the elements is a number dictionary.
   1172   __ CheckMap(eax,
   1173               isolate->factory()->hash_table_map(),
   1174               &slow_load,
   1175               DONT_DO_SMI_CHECK);
   1176   __ mov(ebx, ecx);
   1177   __ SmiUntag(ebx);
   1178   // ebx: untagged index
   1179   // Receiver in edx will be clobbered, need to reload it on miss.
   1180   __ LoadFromNumberDictionary(
   1181       &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
   1182   __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
   1183   __ jmp(&do_call);
   1184 
   1185   __ bind(&slow_reload_receiver);
   1186   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1187 
   1188   __ bind(&slow_load);
   1189   // This branch is taken when calling KeyedCallIC_Miss is neither required
   1190   // nor beneficial.
   1191   __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
   1192 
   1193   {
   1194     FrameScope scope(masm, StackFrame::INTERNAL);
   1195     __ push(ecx);  // save the key
   1196     __ push(edx);  // pass the receiver
   1197     __ push(ecx);  // pass the key
   1198     __ CallRuntime(Runtime::kKeyedGetProperty, 2);
   1199     __ pop(ecx);  // restore the key
   1200     // Leave the internal frame.
   1201   }
   1202 
   1203   __ mov(edi, eax);
   1204   __ jmp(&do_call);
   1205 
   1206   __ bind(&check_name);
   1207   GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call);
   1208 
   1209   // The key is known to be a unique name.
   1210   // If the receiver is a regular JS object with slow properties then do
   1211   // a quick inline probe of the receiver's dictionary.
   1212   // Otherwise do the monomorphic cache probe.
   1213   GenerateKeyedLoadReceiverCheck(
   1214       masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
   1215 
   1216   __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
   1217   __ CheckMap(ebx,
   1218               isolate->factory()->hash_table_map(),
   1219               &lookup_monomorphic_cache,
   1220               DONT_DO_SMI_CHECK);
   1221 
   1222   GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
   1223   __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
   1224   __ jmp(&do_call);
   1225 
   1226   __ bind(&lookup_monomorphic_cache);
   1227   __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
   1228   CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
   1229                                             Code::kNoExtraICState);
   1230   // Fall through on miss.
   1231 
   1232   __ bind(&slow_call);
   1233   // This branch is taken if:
   1234   // - the receiver requires boxing or access check,
   1235   // - the key is neither smi nor a unique name,
   1236   // - the value loaded is not a function,
   1237   // - there is hope that the runtime will create a monomorphic call stub
   1238   //   that will get fetched next time.
   1239   __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
   1240   GenerateMiss(masm, argc);
   1241 
   1242   __ bind(&index_name);
   1243   __ IndexFromHash(ebx, ecx);
   1244   // Now jump to the place where smi keys are handled.
   1245   __ jmp(&index_smi);
   1246 }
   1247 
   1248 
   1249 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
   1250                                              int argc) {
   1251   // ----------- S t a t e -------------
   1252   //  -- ecx                 : name
   1253   //  -- esp[0]              : return address
   1254   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1255   //  -- ...
   1256   //  -- esp[(argc + 1) * 4] : receiver
   1257   // -----------------------------------
   1258   Label slow, notin;
   1259   Factory* factory = masm->isolate()->factory();
   1260   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1261   Operand mapped_location =
   1262       GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
   1263   __ mov(edi, mapped_location);
   1264   GenerateFunctionTailCall(masm, argc, &slow);
   1265   __ bind(&notin);
   1266   // The unmapped lookup expects that the parameter map is in ebx.
   1267   Operand unmapped_location =
   1268       GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
   1269   __ cmp(unmapped_location, factory->the_hole_value());
   1270   __ j(equal, &slow);
   1271   __ mov(edi, unmapped_location);
   1272   GenerateFunctionTailCall(masm, argc, &slow);
   1273   __ bind(&slow);
   1274   GenerateMiss(masm, argc);
   1275 }
   1276 
   1277 
   1278 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   1279   // ----------- S t a t e -------------
   1280   //  -- ecx                 : name
   1281   //  -- esp[0]              : return address
   1282   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1283   //  -- ...
   1284   //  -- esp[(argc + 1) * 4] : receiver
   1285   // -----------------------------------
   1286 
   1287   // Check if the name is really a name.
   1288   Label miss;
   1289   __ JumpIfSmi(ecx, &miss);
   1290   Condition cond = masm->IsObjectNameType(ecx, eax, eax);
   1291   __ j(NegateCondition(cond), &miss);
   1292   CallICBase::GenerateNormal(masm, argc);
   1293   __ bind(&miss);
   1294   GenerateMiss(masm, argc);
   1295 }
   1296 
   1297 
   1298 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   1299   // ----------- S t a t e -------------
   1300   //  -- ecx    : name
   1301   //  -- edx    : receiver
   1302   //  -- esp[0] : return address
   1303   // -----------------------------------
   1304 
   1305   // Probe the stub cache.
   1306   Code::Flags flags = Code::ComputeFlags(
   1307       Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
   1308       Code::NORMAL, Code::LOAD_IC);
   1309   Isolate::Current()->stub_cache()->GenerateProbe(
   1310       masm, flags, edx, ecx, ebx, eax);
   1311 
   1312   // Cache miss: Jump to runtime.
   1313   GenerateMiss(masm);
   1314 }
   1315 
   1316 
   1317 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   1318   // ----------- S t a t e -------------
   1319   //  -- ecx    : name
   1320   //  -- edx    : receiver
   1321   //  -- esp[0] : return address
   1322   // -----------------------------------
   1323   Label miss;
   1324 
   1325   GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
   1326 
   1327   // eax: elements
   1328   // Search the dictionary placing the result in eax.
   1329   GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
   1330   __ ret(0);
   1331 
   1332   // Cache miss: Jump to runtime.
   1333   __ bind(&miss);
   1334   GenerateMiss(masm);
   1335 }
   1336 
   1337 
   1338 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   1339   // ----------- S t a t e -------------
   1340   //  -- ecx    : name
   1341   //  -- edx    : receiver
   1342   //  -- esp[0] : return address
   1343   // -----------------------------------
   1344 
   1345   __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
   1346 
   1347   __ pop(ebx);
   1348   __ push(edx);  // receiver
   1349   __ push(ecx);  // name
   1350   __ push(ebx);  // return address
   1351 
   1352   // Perform tail call to the entry.
   1353   ExternalReference ref =
   1354       ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
   1355   __ TailCallExternalReference(ref, 2, 1);
   1356 }
   1357 
   1358 
   1359 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   1360   // ----------- S t a t e -------------
   1361   //  -- ecx    : key
   1362   //  -- edx    : receiver
   1363   //  -- esp[0] : return address
   1364   // -----------------------------------
   1365 
   1366   __ pop(ebx);
   1367   __ push(edx);  // receiver
   1368   __ push(ecx);  // name
   1369   __ push(ebx);  // return address
   1370 
   1371   // Perform tail call to the entry.
   1372   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
   1373 }
   1374 
   1375 
   1376 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
   1377   // ----------- S t a t e -------------
   1378   //  -- ecx    : key
   1379   //  -- edx    : receiver
   1380   //  -- esp[0] : return address
   1381   // -----------------------------------
   1382 
   1383   __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
   1384 
   1385   __ pop(ebx);
   1386   __ push(edx);  // receiver
   1387   __ push(ecx);  // name
   1388   __ push(ebx);  // return address
   1389 
   1390   // Perform tail call to the entry.
   1391   ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
   1392       ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
   1393                           masm->isolate())
   1394       : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
   1395   __ TailCallExternalReference(ref, 2, 1);
   1396 }
   1397 
   1398 
   1399 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   1400   // ----------- S t a t e -------------
   1401   //  -- ecx    : key
   1402   //  -- edx    : receiver
   1403   //  -- esp[0] : return address
   1404   // -----------------------------------
   1405 
   1406   __ pop(ebx);
   1407   __ push(edx);  // receiver
   1408   __ push(ecx);  // name
   1409   __ push(ebx);  // return address
   1410 
   1411   // Perform tail call to the entry.
   1412   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
   1413 }
   1414 
   1415 
   1416 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
   1417                                   StrictModeFlag strict_mode) {
   1418   // ----------- S t a t e -------------
   1419   //  -- eax    : value
   1420   //  -- ecx    : name
   1421   //  -- edx    : receiver
   1422   //  -- esp[0] : return address
   1423   // -----------------------------------
   1424 
   1425   Code::Flags flags = Code::ComputeFlags(
   1426       Code::STUB, MONOMORPHIC, strict_mode,
   1427       Code::NORMAL, Code::STORE_IC);
   1428   Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
   1429                                                   no_reg);
   1430 
   1431   // Cache miss: Jump to runtime.
   1432   GenerateMiss(masm);
   1433 }
   1434 
   1435 
   1436 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1437   // ----------- S t a t e -------------
   1438   //  -- eax    : value
   1439   //  -- ecx    : name
   1440   //  -- edx    : receiver
   1441   //  -- esp[0] : return address
   1442   // -----------------------------------
   1443 
   1444   __ pop(ebx);
   1445   __ push(edx);
   1446   __ push(ecx);
   1447   __ push(eax);
   1448   __ push(ebx);
   1449 
   1450   // Perform tail call to the entry.
   1451   ExternalReference ref =
   1452       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
   1453   __ TailCallExternalReference(ref, 3, 1);
   1454 }
   1455 
   1456 
   1457 void StoreIC::GenerateNormal(MacroAssembler* masm) {
   1458   // ----------- S t a t e -------------
   1459   //  -- eax    : value
   1460   //  -- ecx    : name
   1461   //  -- edx    : receiver
   1462   //  -- esp[0] : return address
   1463   // -----------------------------------
   1464 
   1465   Label miss, restore_miss;
   1466 
   1467   GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
   1468 
   1469   // A lot of registers are needed for storing to slow case
   1470   // objects. Push and restore receiver but rely on
   1471   // GenerateDictionaryStore preserving the value and name.
   1472   __ push(edx);
   1473   GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
   1474   __ Drop(1);
   1475   Counters* counters = masm->isolate()->counters();
   1476   __ IncrementCounter(counters->store_normal_hit(), 1);
   1477   __ ret(0);
   1478 
   1479   __ bind(&restore_miss);
   1480   __ pop(edx);
   1481 
   1482   __ bind(&miss);
   1483   __ IncrementCounter(counters->store_normal_miss(), 1);
   1484   GenerateMiss(masm);
   1485 }
   1486 
   1487 
   1488 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1489                                          StrictModeFlag strict_mode) {
   1490   // ----------- S t a t e -------------
   1491   //  -- eax    : value
   1492   //  -- ecx    : name
   1493   //  -- edx    : receiver
   1494   //  -- esp[0] : return address
   1495   // -----------------------------------
   1496   __ pop(ebx);
   1497   __ push(edx);
   1498   __ push(ecx);
   1499   __ push(eax);
   1500   __ push(Immediate(Smi::FromInt(NONE)));  // PropertyAttributes
   1501   __ push(Immediate(Smi::FromInt(strict_mode)));
   1502   __ push(ebx);  // return address
   1503 
   1504   // Do tail-call to runtime routine.
   1505   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1506 }
   1507 
   1508 
   1509 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1510                                               StrictModeFlag strict_mode) {
   1511   // ----------- S t a t e -------------
   1512   //  -- eax    : value
   1513   //  -- ecx    : key
   1514   //  -- edx    : receiver
   1515   //  -- esp[0] : return address
   1516   // -----------------------------------
   1517 
   1518   __ pop(ebx);
   1519   __ push(edx);
   1520   __ push(ecx);
   1521   __ push(eax);
   1522   __ push(Immediate(Smi::FromInt(NONE)));         // PropertyAttributes
   1523   __ push(Immediate(Smi::FromInt(strict_mode)));  // Strict mode.
   1524   __ push(ebx);   // return address
   1525 
   1526   // Do tail-call to runtime routine.
   1527   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1528 }
   1529 
   1530 
   1531 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
   1532   // ----------- S t a t e -------------
   1533   //  -- eax    : value
   1534   //  -- ecx    : key
   1535   //  -- edx    : receiver
   1536   //  -- esp[0] : return address
   1537   // -----------------------------------
   1538 
   1539   __ pop(ebx);
   1540   __ push(edx);
   1541   __ push(ecx);
   1542   __ push(eax);
   1543   __ push(ebx);
   1544 
   1545   // Do tail-call to runtime routine.
   1546   ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
   1547       ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
   1548                           masm->isolate())
   1549       : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
   1550   __ TailCallExternalReference(ref, 3, 1);
   1551 }
   1552 
   1553 
   1554 void StoreIC::GenerateSlow(MacroAssembler* masm) {
   1555   // ----------- S t a t e -------------
   1556   //  -- eax    : value
   1557   //  -- ecx    : key
   1558   //  -- edx    : receiver
   1559   //  -- esp[0] : return address
   1560   // -----------------------------------
   1561 
   1562   __ pop(ebx);
   1563   __ push(edx);
   1564   __ push(ecx);
   1565   __ push(eax);
   1566   __ push(ebx);   // return address
   1567 
   1568   // Do tail-call to runtime routine.
   1569   ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
   1570   __ TailCallExternalReference(ref, 3, 1);
   1571 }
   1572 
   1573 
   1574 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
   1575   // ----------- S t a t e -------------
   1576   //  -- eax    : value
   1577   //  -- ecx    : key
   1578   //  -- edx    : receiver
   1579   //  -- esp[0] : return address
   1580   // -----------------------------------
   1581 
   1582   __ pop(ebx);
   1583   __ push(edx);
   1584   __ push(ecx);
   1585   __ push(eax);
   1586   __ push(ebx);   // return address
   1587 
   1588   // Do tail-call to runtime routine.
   1589   ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
   1590   __ TailCallExternalReference(ref, 3, 1);
   1591 }
   1592 
   1593 
   1594 #undef __
   1595 
   1596 
   1597 Condition CompareIC::ComputeCondition(Token::Value op) {
   1598   switch (op) {
   1599     case Token::EQ_STRICT:
   1600     case Token::EQ:
   1601       return equal;
   1602     case Token::LT:
   1603       return less;
   1604     case Token::GT:
   1605       return greater;
   1606     case Token::LTE:
   1607       return less_equal;
   1608     case Token::GTE:
   1609       return greater_equal;
   1610     default:
   1611       UNREACHABLE();
   1612       return no_condition;
   1613   }
   1614 }
   1615 
   1616 
   1617 bool CompareIC::HasInlinedSmiCode(Address address) {
   1618   // The address of the instruction following the call.
   1619   Address test_instruction_address =
   1620       address + Assembler::kCallTargetAddressOffset;
   1621 
   1622   // If the instruction following the call is not a test al, nothing
   1623   // was inlined.
   1624   return *test_instruction_address == Assembler::kTestAlByte;
   1625 }
   1626 
   1627 
   1628 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
   1629   // The address of the instruction following the call.
   1630   Address test_instruction_address =
   1631       address + Assembler::kCallTargetAddressOffset;
   1632 
   1633   // If the instruction following the call is not a test al, nothing
   1634   // was inlined.
   1635   if (*test_instruction_address != Assembler::kTestAlByte) {
   1636     ASSERT(*test_instruction_address == Assembler::kNopByte);
   1637     return;
   1638   }
   1639 
   1640   Address delta_address = test_instruction_address + 1;
   1641   // The delta to the start of the map check instruction and the
   1642   // condition code uses at the patched jump.
   1643   int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
   1644   if (FLAG_trace_ic) {
   1645     PrintF("[  patching ic at %p, test=%p, delta=%d\n",
   1646            address, test_instruction_address, delta);
   1647   }
   1648 
   1649   // Patch with a short conditional jump. Enabling means switching from a short
   1650   // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
   1651   // reverse operation of that.
   1652   Address jmp_address = test_instruction_address - delta;
   1653   ASSERT((check == ENABLE_INLINED_SMI_CHECK)
   1654          ? (*jmp_address == Assembler::kJncShortOpcode ||
   1655             *jmp_address == Assembler::kJcShortOpcode)
   1656          : (*jmp_address == Assembler::kJnzShortOpcode ||
   1657             *jmp_address == Assembler::kJzShortOpcode));
   1658   Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
   1659       ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
   1660       : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
   1661   *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
   1662 }
   1663 
   1664 
   1665 } }  // namespace v8::internal
   1666 
   1667 #endif  // V8_TARGET_ARCH_IA32
   1668