Home | History | Annotate | Download | only in ia32
      1 // Copyright 2006-2008 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 #include "codegen-inl.h"
     31 #include "ic-inl.h"
     32 #include "runtime.h"
     33 #include "stub-cache.h"
     34 #include "utils.h"
     35 
     36 namespace v8 {
     37 namespace internal {
     38 
     39 // ----------------------------------------------------------------------------
     40 // Static IC stub generators.
     41 //
     42 
     43 #define __ ACCESS_MASM(masm)
     44 
     45 
     46 // Helper function used to load a property from a dictionary backing storage.
     47 // This function may return false negatives, so miss_label
     48 // must always call a backup property load that is complete.
     49 // This function is safe to call if the receiver has fast properties,
     50 // or if name is not a symbol, and will jump to the miss_label in that case.
     51 static void GenerateDictionaryLoad(MacroAssembler* masm,
     52                                    Label* miss_label,
     53                                    Register receiver,
     54                                    Register name,
     55                                    Register r0,
     56                                    Register r1,
     57                                    Register r2,
     58                                    DictionaryCheck check_dictionary) {
     59   // Register use:
     60   //
     61   // name - holds the name of the property and is unchanged.
     62   // receiver - holds the receiver and is unchanged.
     63   // Scratch registers:
     64   // r0   - used to hold the property dictionary.
     65   //
     66   // r1   - used for the index into the property dictionary
     67   //      - holds the result on exit.
     68   //
     69   // r2   - used to hold the capacity of the property dictionary.
     70 
     71   Label done;
     72 
     73   // Check for the absence of an interceptor.
     74   // Load the map into r0.
     75   __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
     76   // Test the has_named_interceptor bit in the map.
     77   __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
     78           Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
     79 
     80   // Jump to miss if the interceptor bit is set.
     81   __ j(not_zero, miss_label, not_taken);
     82 
     83   // Bail out if we have a JS global proxy object.
     84   __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
     85   __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
     86   __ j(equal, miss_label, not_taken);
     87 
     88   // Possible work-around for http://crbug.com/16276.
     89   __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
     90   __ j(equal, miss_label, not_taken);
     91   __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
     92   __ j(equal, miss_label, not_taken);
     93 
     94   // Load properties array.
     95   __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
     96 
     97   // Check that the properties array is a dictionary.
     98   if (check_dictionary == CHECK_DICTIONARY) {
     99     __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
    100            Immediate(Factory::hash_table_map()));
    101     __ j(not_equal, miss_label);
    102   }
    103 
    104   // Compute the capacity mask.
    105   const int kCapacityOffset =
    106       StringDictionary::kHeaderSize +
    107       StringDictionary::kCapacityIndex * kPointerSize;
    108   __ mov(r2, FieldOperand(r0, kCapacityOffset));
    109   __ shr(r2, kSmiTagSize);  // convert smi to int
    110   __ dec(r2);
    111 
    112   // Generate an unrolled loop that performs a few probes before
    113   // giving up. Measurements done on Gmail indicate that 2 probes
    114   // cover ~93% of loads from dictionaries.
    115   static const int kProbes = 4;
    116   const int kElementsStartOffset =
    117       StringDictionary::kHeaderSize +
    118       StringDictionary::kElementsStartIndex * kPointerSize;
    119   for (int i = 0; i < kProbes; i++) {
    120     // Compute the masked index: (hash + i + i * i) & mask.
    121     __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
    122     __ shr(r1, String::kHashShift);
    123     if (i > 0) {
    124       __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
    125     }
    126     __ and_(r1, Operand(r2));
    127 
    128     // Scale the index by multiplying by the entry size.
    129     ASSERT(StringDictionary::kEntrySize == 3);
    130     __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
    131 
    132     // Check if the key is identical to the name.
    133     __ cmp(name,
    134            Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
    135     if (i != kProbes - 1) {
    136       __ j(equal, &done, taken);
    137     } else {
    138       __ j(not_equal, miss_label, not_taken);
    139     }
    140   }
    141 
    142   // Check that the value is a normal property.
    143   __ bind(&done);
    144   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    145   __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
    146           Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
    147   __ j(not_zero, miss_label, not_taken);
    148 
    149   // Get the value at the masked, scaled index.
    150   const int kValueOffset = kElementsStartOffset + kPointerSize;
    151   __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
    152 }
    153 
    154 
    155 // The offset from the inlined patch site to the start of the
    156 // inlined load instruction.  It is 7 bytes (test eax, imm) plus
    157 // 6 bytes (jne slow_label).
    158 const int LoadIC::kOffsetToLoadInstruction = 13;
    159 
    160 
    161 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
    162   // ----------- S t a t e -------------
    163   //  -- eax    : receiver
    164   //  -- ecx    : name
    165   //  -- esp[0] : return address
    166   // -----------------------------------
    167   Label miss;
    168 
    169   StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
    170   __ bind(&miss);
    171   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    172 }
    173 
    174 
    175 void LoadIC::GenerateStringLength(MacroAssembler* masm) {
    176   // ----------- S t a t e -------------
    177   //  -- eax    : receiver
    178   //  -- ecx    : name
    179   //  -- esp[0] : return address
    180   // -----------------------------------
    181   Label miss;
    182 
    183   StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
    184   __ bind(&miss);
    185   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    186 }
    187 
    188 
    189 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
    190   // ----------- S t a t e -------------
    191   //  -- eax    : receiver
    192   //  -- ecx    : name
    193   //  -- esp[0] : return address
    194   // -----------------------------------
    195   Label miss;
    196 
    197   StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
    198   __ bind(&miss);
    199   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    200 }
    201 
    202 
    203 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
    204   // ----------- S t a t e -------------
    205   //  -- eax    : key
    206   //  -- edx    : receiver
    207   //  -- esp[0] : return address
    208   // -----------------------------------
    209   Label slow, check_string, index_int, index_string;
    210   Label check_pixel_array, probe_dictionary;
    211 
    212   // Check that the object isn't a smi.
    213   __ test(edx, Immediate(kSmiTagMask));
    214   __ j(zero, &slow, not_taken);
    215 
    216   // Get the map of the receiver.
    217   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    218 
    219   // Check bit field.
    220   __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
    221   __ test(ebx, Immediate(kSlowCaseBitFieldMask));
    222   __ j(not_zero, &slow, not_taken);
    223   // Check that the object is some kind of JS object EXCEPT JS Value type.
    224   // In the case that the object is a value-wrapper object,
    225   // we enter the runtime system to make sure that indexing
    226   // into string objects work as intended.
    227   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    228   __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
    229   __ j(below, &slow, not_taken);
    230   // Check that the key is a smi.
    231   __ test(eax, Immediate(kSmiTagMask));
    232   __ j(not_zero, &check_string, not_taken);
    233   __ mov(ebx, eax);
    234   __ SmiUntag(ebx);
    235   // Get the elements array of the object.
    236   __ bind(&index_int);
    237   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
    238   // Check that the object is in fast mode (not dictionary).
    239   __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true);
    240   // Check that the key (index) is within bounds.
    241   __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
    242   __ j(above_equal, &slow);
    243   // Fast case: Do the load.
    244   __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize));
    245   __ cmp(Operand(ecx), Immediate(Factory::the_hole_value()));
    246   // In case the loaded value is the_hole we have to consult GetProperty
    247   // to ensure the prototype chain is searched.
    248   __ j(equal, &slow);
    249   __ mov(eax, ecx);
    250   __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
    251   __ ret(0);
    252 
    253   __ bind(&check_pixel_array);
    254   // Check whether the elements is a pixel array.
    255   // edx: receiver
    256   // ebx: untagged index
    257   // eax: key
    258   // ecx: elements
    259   __ CheckMap(ecx, Factory::pixel_array_map(), &slow, true);
    260   __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
    261   __ j(above_equal, &slow);
    262   __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
    263   __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
    264   __ SmiTag(eax);
    265   __ ret(0);
    266 
    267   __ bind(&slow);
    268   // Slow case: jump to runtime.
    269   // edx: receiver
    270   // eax: key
    271   __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
    272   GenerateRuntimeGetProperty(masm);
    273 
    274   __ bind(&check_string);
    275   // The key is not a smi.
    276   // Is it a string?
    277   // edx: receiver
    278   // eax: key
    279   __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
    280   __ j(above_equal, &slow);
    281   // Is the string an array index, with cached numeric value?
    282   __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
    283   __ test(ebx, Immediate(String::kIsArrayIndexMask));
    284   __ j(not_zero, &index_string, not_taken);
    285 
    286   // Is the string a symbol?
    287   __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset));
    288   ASSERT(kSymbolTag != 0);
    289   __ test(ebx, Immediate(kIsSymbolMask));
    290   __ j(zero, &slow, not_taken);
    291 
    292   // If the receiver is a fast-case object, check the keyed lookup
    293   // cache. Otherwise probe the dictionary.
    294   __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
    295   __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
    296          Immediate(Factory::hash_table_map()));
    297   __ j(equal, &probe_dictionary);
    298 
    299   // Load the map of the receiver, compute the keyed lookup cache hash
    300   // based on 32 bits of the map pointer and the string hash.
    301   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
    302   __ mov(ecx, ebx);
    303   __ shr(ecx, KeyedLookupCache::kMapHashShift);
    304   __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
    305   __ shr(edi, String::kHashShift);
    306   __ xor_(ecx, Operand(edi));
    307   __ and_(ecx, KeyedLookupCache::kCapacityMask);
    308 
    309   // Load the key (consisting of map and symbol) from the cache and
    310   // check for match.
    311   ExternalReference cache_keys
    312       = ExternalReference::keyed_lookup_cache_keys();
    313   __ mov(edi, ecx);
    314   __ shl(edi, kPointerSizeLog2 + 1);
    315   __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
    316   __ j(not_equal, &slow);
    317   __ add(Operand(edi), Immediate(kPointerSize));
    318   __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
    319   __ j(not_equal, &slow);
    320 
    321   // Get field offset and check that it is an in-object property.
    322   // edx     : receiver
    323   // ebx     : receiver's map
    324   // eax     : key
    325   // ecx     : lookup cache index
    326   ExternalReference cache_field_offsets
    327       = ExternalReference::keyed_lookup_cache_field_offsets();
    328   __ mov(edi,
    329          Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
    330   __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
    331   __ cmp(edi, Operand(ecx));
    332   __ j(above_equal, &slow);
    333 
    334   // Load in-object property.
    335   __ sub(edi, Operand(ecx));
    336   __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
    337   __ add(ecx, Operand(edi));
    338   __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
    339   __ ret(0);
    340 
    341   // Do a quick inline probe of the receiver's dictionary, if it
    342   // exists.
    343   __ bind(&probe_dictionary);
    344   GenerateDictionaryLoad(masm,
    345                          &slow,
    346                          edx,
    347                          eax,
    348                          ebx,
    349                          ecx,
    350                          edi,
    351                          DICTIONARY_CHECK_DONE);
    352   __ mov(eax, Operand(ecx));
    353   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
    354   __ ret(0);
    355 
    356   // If the hash field contains an array index pick it out. The assert checks
    357   // that the constants for the maximum number of digits for an array index
    358   // cached in the hash field and the number of bits reserved for it does not
    359   // conflict.
    360   ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
    361          (1 << String::kArrayIndexValueBits));
    362   __ bind(&index_string);
    363   __ and_(ebx, String::kArrayIndexHashMask);
    364   __ shr(ebx, String::kHashShift);
    365   __ jmp(&index_int);
    366 }
    367 
    368 
    369 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
    370   // ----------- S t a t e -------------
    371   //  -- eax    : key
    372   //  -- edx    : receiver
    373   //  -- esp[0] : return address
    374   // -----------------------------------
    375   Label miss, index_ok;
    376 
    377   // Pop return address.
    378   // Performing the load early is better in the common case.
    379   __ pop(ebx);
    380 
    381   __ test(edx, Immediate(kSmiTagMask));
    382   __ j(zero, &miss);
    383   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    384   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
    385   __ test(ecx, Immediate(kIsNotStringMask));
    386   __ j(not_zero, &miss);
    387 
    388   // Check if key is a smi or a heap number.
    389   __ test(eax, Immediate(kSmiTagMask));
    390   __ j(zero, &index_ok);
    391   __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
    392   __ cmp(ecx, Factory::heap_number_map());
    393   __ j(not_equal, &miss);
    394 
    395   __ bind(&index_ok);
    396   // Push receiver and key on the stack, and make a tail call.
    397   __ push(edx);  // receiver
    398   __ push(eax);  // key
    399   __ push(ebx);  // return address
    400   __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
    401 
    402   __ bind(&miss);
    403   __ push(ebx);
    404   GenerateMiss(masm);
    405 }
    406 
    407 
    408 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
    409                                         ExternalArrayType array_type) {
    410   // ----------- S t a t e -------------
    411   //  -- eax    : key
    412   //  -- edx    : receiver
    413   //  -- esp[0] : return address
    414   // -----------------------------------
    415   Label slow, failed_allocation;
    416 
    417   // Check that the object isn't a smi.
    418   __ test(edx, Immediate(kSmiTagMask));
    419   __ j(zero, &slow, not_taken);
    420 
    421   // Check that the key is a smi.
    422   __ test(eax, Immediate(kSmiTagMask));
    423   __ j(not_zero, &slow, not_taken);
    424 
    425   // Get the map of the receiver.
    426   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    427   // Check that the receiver does not require access checks.  We need
    428   // to check this explicitly since this generic stub does not perform
    429   // map checks.
    430   __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
    431   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
    432   __ j(not_zero, &slow, not_taken);
    433 
    434   __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
    435   __ j(not_equal, &slow, not_taken);
    436 
    437   // Check that the elements array is the appropriate type of
    438   // ExternalArray.
    439   __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
    440   Handle<Map> map(Heap::MapForExternalArrayType(array_type));
    441   __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
    442          Immediate(map));
    443   __ j(not_equal, &slow, not_taken);
    444 
    445   // eax: key, known to be a smi.
    446   // edx: receiver, known to be a JSObject.
    447   // ebx: elements object, known to be an external array.
    448   // Check that the index is in range.
    449   __ mov(ecx, eax);
    450   __ SmiUntag(ecx);  // Untag the index.
    451   __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
    452   // Unsigned comparison catches both negative and too-large values.
    453   __ j(above_equal, &slow);
    454 
    455   __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
    456   // ebx: base pointer of external storage
    457   switch (array_type) {
    458     case kExternalByteArray:
    459       __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
    460       break;
    461     case kExternalUnsignedByteArray:
    462       __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
    463       break;
    464     case kExternalShortArray:
    465       __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
    466       break;
    467     case kExternalUnsignedShortArray:
    468       __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
    469       break;
    470     case kExternalIntArray:
    471     case kExternalUnsignedIntArray:
    472       __ mov(ecx, Operand(ebx, ecx, times_4, 0));
    473       break;
    474     case kExternalFloatArray:
    475       __ fld_s(Operand(ebx, ecx, times_4, 0));
    476       break;
    477     default:
    478       UNREACHABLE();
    479       break;
    480   }
    481 
    482   // For integer array types:
    483   // ecx: value
    484   // For floating-point array type:
    485   // FP(0): value
    486 
    487   if (array_type == kExternalIntArray ||
    488       array_type == kExternalUnsignedIntArray) {
    489     // For the Int and UnsignedInt array types, we need to see whether
    490     // the value can be represented in a Smi. If not, we need to convert
    491     // it to a HeapNumber.
    492     Label box_int;
    493     if (array_type == kExternalIntArray) {
    494       __ cmp(ecx, 0xC0000000);
    495       __ j(sign, &box_int);
    496     } else {
    497       ASSERT_EQ(array_type, kExternalUnsignedIntArray);
    498       // The test is different for unsigned int values. Since we need
    499       // the value to be in the range of a positive smi, we can't
    500       // handle either of the top two bits being set in the value.
    501       __ test(ecx, Immediate(0xC0000000));
    502       __ j(not_zero, &box_int);
    503     }
    504 
    505     __ mov(eax, ecx);
    506     __ SmiTag(eax);
    507     __ ret(0);
    508 
    509     __ bind(&box_int);
    510 
    511     // Allocate a HeapNumber for the int and perform int-to-double
    512     // conversion.
    513     if (array_type == kExternalIntArray) {
    514       __ push(ecx);
    515       __ fild_s(Operand(esp, 0));
    516       __ pop(ecx);
    517     } else {
    518       ASSERT(array_type == kExternalUnsignedIntArray);
    519       // Need to zero-extend the value.
    520       // There's no fild variant for unsigned values, so zero-extend
    521       // to a 64-bit int manually.
    522       __ push(Immediate(0));
    523       __ push(ecx);
    524       __ fild_d(Operand(esp, 0));
    525       __ pop(ecx);
    526       __ pop(ecx);
    527     }
    528     // FP(0): value
    529     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
    530     // Set the value.
    531     __ mov(eax, ecx);
    532     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
    533     __ ret(0);
    534   } else if (array_type == kExternalFloatArray) {
    535     // For the floating-point array type, we need to always allocate a
    536     // HeapNumber.
    537     __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
    538     // Set the value.
    539     __ mov(eax, ecx);
    540     __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
    541     __ ret(0);
    542   } else {
    543     __ mov(eax, ecx);
    544     __ SmiTag(eax);
    545     __ ret(0);
    546   }
    547 
    548   // If we fail allocation of the HeapNumber, we still have a value on
    549   // top of the FPU stack. Remove it.
    550   __ bind(&failed_allocation);
    551   __ ffree();
    552   __ fincstp();
    553   // Fall through to slow case.
    554 
    555   // Slow case: Load key and receiver from stack and jump to runtime.
    556   __ bind(&slow);
    557   __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
    558   GenerateRuntimeGetProperty(masm);
    559 }
    560 
    561 
    562 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
    563   // ----------- S t a t e -------------
    564   //  -- eax    : key
    565   //  -- edx    : receiver
    566   //  -- esp[0] : return address
    567   // -----------------------------------
    568   Label slow;
    569 
    570   // Check that the receiver isn't a smi.
    571   __ test(edx, Immediate(kSmiTagMask));
    572   __ j(zero, &slow, not_taken);
    573 
    574   // Check that the key is a smi.
    575   __ test(eax, Immediate(kSmiTagMask));
    576   __ j(not_zero, &slow, not_taken);
    577 
    578   // Get the map of the receiver.
    579   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    580 
    581   // Check that it has indexed interceptor and access checks
    582   // are not enabled for this object.
    583   __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
    584   __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
    585   __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
    586   __ j(not_zero, &slow, not_taken);
    587 
    588   // Everything is fine, call runtime.
    589   __ pop(ecx);
    590   __ push(edx);  // receiver
    591   __ push(eax);  // key
    592   __ push(ecx);  // return address
    593 
    594   // Perform tail call to the entry.
    595   __ TailCallRuntime(ExternalReference(
    596         IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
    597 
    598   __ bind(&slow);
    599   GenerateMiss(masm);
    600 }
    601 
    602 
    603 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
    604   // ----------- S t a t e -------------
    605   //  -- eax    : value
    606   //  -- esp[0] : return address
    607   //  -- esp[4] : key
    608   //  -- esp[8] : receiver
    609   // -----------------------------------
    610   Label slow, fast, array, extra, check_pixel_array;
    611 
    612   // Get the receiver from the stack.
    613   __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
    614   // Check that the object isn't a smi.
    615   __ test(edx, Immediate(kSmiTagMask));
    616   __ j(zero, &slow, not_taken);
    617   // Get the map from the receiver.
    618   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    619   // Check that the receiver does not require access checks.  We need
    620   // to do this because this generic stub does not perform map checks.
    621   __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
    622   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
    623   __ j(not_zero, &slow, not_taken);
    624   // Get the key from the stack.
    625   __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
    626   // Check that the key is a smi.
    627   __ test(ebx, Immediate(kSmiTagMask));
    628   __ j(not_zero, &slow, not_taken);
    629   // Get the instance type from the map of the receiver.
    630   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
    631   // Check if the object is a JS array or not.
    632   __ cmp(ecx, JS_ARRAY_TYPE);
    633   __ j(equal, &array);
    634   // Check that the object is some kind of JS object.
    635   __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
    636   __ j(less, &slow, not_taken);
    637 
    638   // Object case: Check key against length in the elements array.
    639   // eax: value
    640   // edx: JSObject
    641   // ebx: index (as a smi)
    642   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
    643   // Check that the object is in fast mode (not dictionary).
    644   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
    645          Immediate(Factory::fixed_array_map()));
    646   __ j(not_equal, &check_pixel_array, not_taken);
    647   // Untag the key (for checking against untagged length in the fixed array).
    648   __ mov(edx, Operand(ebx));
    649   __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
    650   __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
    651   // eax: value
    652   // ecx: FixedArray
    653   // ebx: index (as a smi)
    654   __ j(below, &fast, taken);
    655 
    656   // Slow case: call runtime.
    657   __ bind(&slow);
    658   GenerateRuntimeSetProperty(masm);
    659 
    660   // Check whether the elements is a pixel array.
    661   // eax: value
    662   // ecx: elements array
    663   // ebx: index (as a smi)
    664   __ bind(&check_pixel_array);
    665   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
    666          Immediate(Factory::pixel_array_map()));
    667   __ j(not_equal, &slow);
    668   // Check that the value is a smi. If a conversion is needed call into the
    669   // runtime to convert and clamp.
    670   __ test(eax, Immediate(kSmiTagMask));
    671   __ j(not_zero, &slow);
    672   __ sar(ebx, kSmiTagSize);  // Untag the index.
    673   __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
    674   __ j(above_equal, &slow);
    675   __ mov(edx, eax);  // Save the value.
    676   __ sar(eax, kSmiTagSize);  // Untag the value.
    677   {  // Clamp the value to [0..255].
    678     Label done;
    679     __ test(eax, Immediate(0xFFFFFF00));
    680     __ j(zero, &done);
    681     __ setcc(negative, eax);  // 1 if negative, 0 if positive.
    682     __ dec_b(eax);  // 0 if negative, 255 if positive.
    683     __ bind(&done);
    684   }
    685   __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
    686   __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
    687   __ mov(eax, edx);  // Return the original value.
    688   __ ret(0);
    689 
    690   // Extra capacity case: Check if there is extra capacity to
    691   // perform the store and update the length. Used for adding one
    692   // element to the array by writing to array[array.length].
    693   __ bind(&extra);
    694   // eax: value
    695   // edx: JSArray
    696   // ecx: FixedArray
    697   // ebx: index (as a smi)
    698   // flags: compare (ebx, edx.length())
    699   __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
    700   __ sar(ebx, kSmiTagSize);  // untag
    701   __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
    702   __ j(above_equal, &slow, not_taken);
    703   // Restore tag and increment.
    704   __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
    705   __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
    706   __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
    707   __ jmp(&fast);
    708 
    709   // Array case: Get the length and the elements array from the JS
    710   // array. Check that the array is in fast mode; if it is the
    711   // length is always a smi.
    712   __ bind(&array);
    713   // eax: value
    714   // edx: JSArray
    715   // ebx: index (as a smi)
    716   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
    717   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
    718          Immediate(Factory::fixed_array_map()));
    719   __ j(not_equal, &check_pixel_array);
    720 
    721   // Check the key against the length in the array, compute the
    722   // address to store into and fall through to fast case.
    723   __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
    724   __ j(above_equal, &extra, not_taken);
    725 
    726   // Fast case: Do the store.
    727   __ bind(&fast);
    728   // eax: value
    729   // ecx: FixedArray
    730   // ebx: index (as a smi)
    731   __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
    732          eax);
    733   // Update write barrier for the elements array address.
    734   __ mov(edx, Operand(eax));
    735   __ RecordWrite(ecx, 0, edx, ebx);
    736   __ ret(0);
    737 }
    738 
    739 
    740 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
    741                                          ExternalArrayType array_type) {
    742   // ----------- S t a t e -------------
    743   //  -- eax    : value
    744   //  -- esp[0] : return address
    745   //  -- esp[4] : key
    746   //  -- esp[8] : receiver
    747   // -----------------------------------
    748   Label slow, check_heap_number;
    749 
    750   // Get the receiver from the stack.
    751   __ mov(edx, Operand(esp, 2 * kPointerSize));
    752   // Check that the object isn't a smi.
    753   __ test(edx, Immediate(kSmiTagMask));
    754   __ j(zero, &slow);
    755   // Get the map from the receiver.
    756   __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
    757   // Check that the receiver does not require access checks.  We need
    758   // to do this because this generic stub does not perform map checks.
    759   __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
    760   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
    761   __ j(not_zero, &slow);
    762   // Get the key from the stack.
    763   __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
    764   // Check that the key is a smi.
    765   __ test(ebx, Immediate(kSmiTagMask));
    766   __ j(not_zero, &slow);
    767   // Get the instance type from the map of the receiver.
    768   __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
    769   // Check that the object is a JS object.
    770   __ cmp(ecx, JS_OBJECT_TYPE);
    771   __ j(not_equal, &slow);
    772 
    773   // Check that the elements array is the appropriate type of
    774   // ExternalArray.
    775   // eax: value
    776   // edx: JSObject
    777   // ebx: index (as a smi)
    778   __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
    779   Handle<Map> map(Heap::MapForExternalArrayType(array_type));
    780   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
    781          Immediate(map));
    782   __ j(not_equal, &slow);
    783 
    784   // Check that the index is in range.
    785   __ sar(ebx, kSmiTagSize);  // Untag the index.
    786   __ cmp(ebx, FieldOperand(ecx, ExternalArray::kLengthOffset));
    787   // Unsigned comparison catches both negative and too-large values.
    788   __ j(above_equal, &slow);
    789 
    790   // Handle both smis and HeapNumbers in the fast path. Go to the
    791   // runtime for all other kinds of values.
    792   // eax: value
    793   // ecx: elements array
    794   // ebx: untagged index
    795   __ test(eax, Immediate(kSmiTagMask));
    796   __ j(not_equal, &check_heap_number);
    797   // smi case
    798   __ mov(edx, eax);  // Save the value.
    799   __ sar(eax, kSmiTagSize);  // Untag the value.
    800   __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
    801   // ecx: base pointer of external storage
    802   switch (array_type) {
    803     case kExternalByteArray:
    804     case kExternalUnsignedByteArray:
    805       __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
    806       break;
    807     case kExternalShortArray:
    808     case kExternalUnsignedShortArray:
    809       __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
    810       break;
    811     case kExternalIntArray:
    812     case kExternalUnsignedIntArray:
    813       __ mov(Operand(ecx, ebx, times_4, 0), eax);
    814       break;
    815     case kExternalFloatArray:
    816       // Need to perform int-to-float conversion.
    817       __ push(eax);
    818       __ fild_s(Operand(esp, 0));
    819       __ pop(eax);
    820       __ fstp_s(Operand(ecx, ebx, times_4, 0));
    821       break;
    822     default:
    823       UNREACHABLE();
    824       break;
    825   }
    826   __ mov(eax, edx);  // Return the original value.
    827   __ ret(0);
    828 
    829   __ bind(&check_heap_number);
    830   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
    831          Immediate(Factory::heap_number_map()));
    832   __ j(not_equal, &slow);
    833 
    834   // The WebGL specification leaves the behavior of storing NaN and
    835   // +/-Infinity into integer arrays basically undefined. For more
    836   // reproducible behavior, convert these to zero.
    837   __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
    838   __ mov(edx, eax);  // Save the value.
    839   __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
    840   // ebx: untagged index
    841   // ecx: base pointer of external storage
    842   // top of FPU stack: value
    843   if (array_type == kExternalFloatArray) {
    844     __ fstp_s(Operand(ecx, ebx, times_4, 0));
    845     __ mov(eax, edx);  // Return the original value.
    846     __ ret(0);
    847   } else {
    848     // Need to perform float-to-int conversion.
    849     // Test the top of the FP stack for NaN.
    850     Label is_nan;
    851     __ fucomi(0);
    852     __ j(parity_even, &is_nan);
    853 
    854     if (array_type != kExternalUnsignedIntArray) {
    855       __ push(eax);  // Make room on stack
    856       __ fistp_s(Operand(esp, 0));
    857       __ pop(eax);
    858     } else {
    859       // fistp stores values as signed integers.
    860       // To represent the entire range, we need to store as a 64-bit
    861       // int and discard the high 32 bits.
    862       __ push(eax);  // Make room on stack
    863       __ push(eax);  // Make room on stack
    864       __ fistp_d(Operand(esp, 0));
    865       __ pop(eax);
    866       __ mov(Operand(esp, 0), eax);
    867       __ pop(eax);
    868     }
    869     // eax: untagged integer value
    870     switch (array_type) {
    871       case kExternalByteArray:
    872       case kExternalUnsignedByteArray:
    873         __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
    874         break;
    875       case kExternalShortArray:
    876       case kExternalUnsignedShortArray:
    877         __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
    878         break;
    879       case kExternalIntArray:
    880       case kExternalUnsignedIntArray: {
    881         // We also need to explicitly check for +/-Infinity. These are
    882         // converted to MIN_INT, but we need to be careful not to
    883         // confuse with legal uses of MIN_INT.
    884         Label not_infinity;
    885         // This test would apparently detect both NaN and Infinity,
    886         // but we've already checked for NaN using the FPU hardware
    887         // above.
    888         __ mov_w(edi, FieldOperand(edx, HeapNumber::kValueOffset + 6));
    889         __ and_(edi, 0x7FF0);
    890         __ cmp(edi, 0x7FF0);
    891         __ j(not_equal, &not_infinity);
    892         __ mov(eax, 0);
    893         __ bind(&not_infinity);
    894         __ mov(Operand(ecx, ebx, times_4, 0), eax);
    895         break;
    896       }
    897       default:
    898         UNREACHABLE();
    899         break;
    900     }
    901     __ mov(eax, edx);  // Return the original value.
    902     __ ret(0);
    903 
    904     __ bind(&is_nan);
    905     __ ffree();
    906     __ fincstp();
    907     switch (array_type) {
    908       case kExternalByteArray:
    909       case kExternalUnsignedByteArray:
    910         __ mov_b(Operand(ecx, ebx, times_1, 0), 0);
    911         break;
    912       case kExternalShortArray:
    913       case kExternalUnsignedShortArray:
    914         __ mov(eax, 0);
    915         __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
    916         break;
    917       case kExternalIntArray:
    918       case kExternalUnsignedIntArray:
    919         __ mov(Operand(ecx, ebx, times_4, 0), Immediate(0));
    920         break;
    921       default:
    922         UNREACHABLE();
    923         break;
    924     }
    925     __ mov(eax, edx);  // Return the original value.
    926     __ ret(0);
    927   }
    928 
    929   // Slow case: call runtime.
    930   __ bind(&slow);
    931   GenerateRuntimeSetProperty(masm);
    932 }
    933 
    934 
    935 // Defined in ic.cc.
    936 Object* CallIC_Miss(Arguments args);
    937 
    938 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
    939   // ----------- S t a t e -------------
    940   //  -- ecx                 : name
    941   //  -- esp[0]              : return address
    942   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
    943   //  -- ...
    944   //  -- esp[(argc + 1) * 4] : receiver
    945   // -----------------------------------
    946   Label number, non_number, non_string, boolean, probe, miss;
    947 
    948   // Get the receiver of the function from the stack; 1 ~ return address.
    949   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
    950 
    951   // Probe the stub cache.
    952   Code::Flags flags =
    953       Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
    954   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
    955 
    956   // If the stub cache probing failed, the receiver might be a value.
    957   // For value objects, we use the map of the prototype objects for
    958   // the corresponding JSValue for the cache and that is what we need
    959   // to probe.
    960   //
    961   // Check for number.
    962   __ test(edx, Immediate(kSmiTagMask));
    963   __ j(zero, &number, not_taken);
    964   __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
    965   __ j(not_equal, &non_number, taken);
    966   __ bind(&number);
    967   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    968       masm, Context::NUMBER_FUNCTION_INDEX, edx);
    969   __ jmp(&probe);
    970 
    971   // Check for string.
    972   __ bind(&non_number);
    973   __ cmp(ebx, FIRST_NONSTRING_TYPE);
    974   __ j(above_equal, &non_string, taken);
    975   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    976       masm, Context::STRING_FUNCTION_INDEX, edx);
    977   __ jmp(&probe);
    978 
    979   // Check for boolean.
    980   __ bind(&non_string);
    981   __ cmp(edx, Factory::true_value());
    982   __ j(equal, &boolean, not_taken);
    983   __ cmp(edx, Factory::false_value());
    984   __ j(not_equal, &miss, taken);
    985   __ bind(&boolean);
    986   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    987       masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
    988 
    989   // Probe the stub cache for the value object.
    990   __ bind(&probe);
    991   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
    992 
    993   // Cache miss: Jump to runtime.
    994   __ bind(&miss);
    995   GenerateMiss(masm, argc);
    996 }
    997 
    998 
    999 static void GenerateNormalHelper(MacroAssembler* masm,
   1000                                  int argc,
   1001                                  bool is_global_object,
   1002                                  Label* miss) {
   1003   // ----------- S t a t e -------------
   1004   //  -- ecx                 : name
   1005   //  -- edx                 : receiver
   1006   //  -- esp[0]              : return address
   1007   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1008   //  -- ...
   1009   //  -- esp[(argc + 1) * 4] : receiver
   1010   // -----------------------------------
   1011 
   1012   // Search dictionary - put result in register edi.
   1013   __ mov(edi, edx);
   1014   GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
   1015 
   1016   // Check that the result is not a smi.
   1017   __ test(edi, Immediate(kSmiTagMask));
   1018   __ j(zero, miss, not_taken);
   1019 
   1020   // Check that the value is a JavaScript function, fetching its map into eax.
   1021   __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
   1022   __ j(not_equal, miss, not_taken);
   1023 
   1024   // Patch the receiver on stack with the global proxy if necessary.
   1025   if (is_global_object) {
   1026     __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   1027     __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   1028   }
   1029 
   1030   // Invoke the function.
   1031   ParameterCount actual(argc);
   1032   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
   1033 }
   1034 
   1035 
   1036 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   1037   // ----------- S t a t e -------------
   1038   //  -- ecx                 : name
   1039   //  -- esp[0]              : return address
   1040   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1041   //  -- ...
   1042   //  -- esp[(argc + 1) * 4] : receiver
   1043   // -----------------------------------
   1044   Label miss, global_object, non_global_object;
   1045 
   1046   // Get the receiver of the function from the stack; 1 ~ return address.
   1047   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1048 
   1049   // Check that the receiver isn't a smi.
   1050   __ test(edx, Immediate(kSmiTagMask));
   1051   __ j(zero, &miss, not_taken);
   1052 
   1053   // Check that the receiver is a valid JS object.
   1054   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
   1055   __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
   1056   __ cmp(eax, FIRST_JS_OBJECT_TYPE);
   1057   __ j(below, &miss, not_taken);
   1058 
   1059   // If this assert fails, we have to check upper bound too.
   1060   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
   1061 
   1062   // Check for access to global object.
   1063   __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
   1064   __ j(equal, &global_object);
   1065   __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
   1066   __ j(not_equal, &non_global_object);
   1067 
   1068   // Accessing global object: Load and invoke.
   1069   __ bind(&global_object);
   1070   // Check that the global object does not require access checks.
   1071   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
   1072   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   1073   __ j(not_equal, &miss, not_taken);
   1074   GenerateNormalHelper(masm, argc, true, &miss);
   1075 
   1076   // Accessing non-global object: Check for access to global proxy.
   1077   Label global_proxy, invoke;
   1078   __ bind(&non_global_object);
   1079   __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
   1080   __ j(equal, &global_proxy, not_taken);
   1081   // Check that the non-global, non-global-proxy object does not
   1082   // require access checks.
   1083   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
   1084   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   1085   __ j(not_equal, &miss, not_taken);
   1086   __ bind(&invoke);
   1087   GenerateNormalHelper(masm, argc, false, &miss);
   1088 
   1089   // Global object proxy access: Check access rights.
   1090   __ bind(&global_proxy);
   1091   __ CheckAccessGlobalProxy(edx, eax, &miss);
   1092   __ jmp(&invoke);
   1093 
   1094   // Cache miss: Jump to runtime.
   1095   __ bind(&miss);
   1096   GenerateMiss(masm, argc);
   1097 }
   1098 
   1099 
   1100 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
   1101   // ----------- S t a t e -------------
   1102   //  -- ecx                 : name
   1103   //  -- esp[0]              : return address
   1104   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   1105   //  -- ...
   1106   //  -- esp[(argc + 1) * 4] : receiver
   1107   // -----------------------------------
   1108 
   1109   // Get the receiver of the function from the stack; 1 ~ return address.
   1110   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
   1111 
   1112   // Enter an internal frame.
   1113   __ EnterInternalFrame();
   1114 
   1115   // Push the receiver and the name of the function.
   1116   __ push(edx);
   1117   __ push(ecx);
   1118 
   1119   // Call the entry.
   1120   CEntryStub stub(1);
   1121   __ mov(eax, Immediate(2));
   1122   __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss))));
   1123   __ CallStub(&stub);
   1124 
   1125   // Move result to edi and exit the internal frame.
   1126   __ mov(edi, eax);
   1127   __ LeaveInternalFrame();
   1128 
   1129   // Check if the receiver is a global object of some sort.
   1130   Label invoke, global;
   1131   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
   1132   __ test(edx, Immediate(kSmiTagMask));
   1133   __ j(zero, &invoke, not_taken);
   1134   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
   1135   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
   1136   __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
   1137   __ j(equal, &global);
   1138   __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
   1139   __ j(not_equal, &invoke);
   1140 
   1141   // Patch the receiver on the stack.
   1142   __ bind(&global);
   1143   __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
   1144   __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
   1145 
   1146   // Invoke the function.
   1147   ParameterCount actual(argc);
   1148   __ bind(&invoke);
   1149   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
   1150 }
   1151 
   1152 
   1153 // Defined in ic.cc.
   1154 Object* LoadIC_Miss(Arguments args);
   1155 
   1156 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   1157   // ----------- S t a t e -------------
   1158   //  -- eax    : receiver
   1159   //  -- ecx    : name
   1160   //  -- esp[0] : return address
   1161   // -----------------------------------
   1162 
   1163   // Probe the stub cache.
   1164   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
   1165                                          NOT_IN_LOOP,
   1166                                          MONOMORPHIC);
   1167   StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
   1168 
   1169   // Cache miss: Jump to runtime.
   1170   GenerateMiss(masm);
   1171 }
   1172 
   1173 
   1174 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   1175   // ----------- S t a t e -------------
   1176   //  -- eax    : receiver
   1177   //  -- ecx    : name
   1178   //  -- esp[0] : return address
   1179   // -----------------------------------
   1180   Label miss, probe, global;
   1181 
   1182   // Check that the receiver isn't a smi.
   1183   __ test(eax, Immediate(kSmiTagMask));
   1184   __ j(zero, &miss, not_taken);
   1185 
   1186   // Check that the receiver is a valid JS object.
   1187   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
   1188   __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
   1189   __ cmp(edx, FIRST_JS_OBJECT_TYPE);
   1190   __ j(less, &miss, not_taken);
   1191 
   1192   // If this assert fails, we have to check upper bound too.
   1193   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
   1194 
   1195   // Check for access to global object (unlikely).
   1196   __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
   1197   __ j(equal, &global, not_taken);
   1198 
   1199   // Check for non-global object that requires access check.
   1200   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
   1201   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   1202   __ j(not_zero, &miss, not_taken);
   1203 
   1204   // Search the dictionary placing the result in eax.
   1205   __ bind(&probe);
   1206   GenerateDictionaryLoad(masm,
   1207                          &miss,
   1208                          eax,
   1209                          ecx,
   1210                          edx,
   1211                          edi,
   1212                          ebx,
   1213                          CHECK_DICTIONARY);
   1214   __ mov(eax, edi);
   1215   __ ret(0);
   1216 
   1217   // Global object access: Check access rights.
   1218   __ bind(&global);
   1219   __ CheckAccessGlobalProxy(eax, edx, &miss);
   1220   __ jmp(&probe);
   1221 
   1222   // Cache miss: Restore receiver from stack and jump to runtime.
   1223   __ bind(&miss);
   1224   GenerateMiss(masm);
   1225 }
   1226 
   1227 
   1228 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   1229   // ----------- S t a t e -------------
   1230   //  -- eax    : receiver
   1231   //  -- ecx    : name
   1232   //  -- esp[0] : return address
   1233   // -----------------------------------
   1234 
   1235   __ pop(ebx);
   1236   __ push(eax);  // receiver
   1237   __ push(ecx);  // name
   1238   __ push(ebx);  // return address
   1239 
   1240   // Perform tail call to the entry.
   1241   __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1);
   1242 }
   1243 
   1244 
   1245 // One byte opcode for test eax,0xXXXXXXXX.
   1246 static const byte kTestEaxByte = 0xA9;
   1247 
   1248 
   1249 void LoadIC::ClearInlinedVersion(Address address) {
   1250   // Reset the map check of the inlined inobject property load (if
   1251   // present) to guarantee failure by holding an invalid map (the null
   1252   // value).  The offset can be patched to anything.
   1253   PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
   1254 }
   1255 
   1256 
   1257 void KeyedLoadIC::ClearInlinedVersion(Address address) {
   1258   // Insert null as the map to check for to make sure the map check fails
   1259   // sending control flow to the IC instead of the inlined version.
   1260   PatchInlinedLoad(address, Heap::null_value());
   1261 }
   1262 
   1263 
   1264 void KeyedStoreIC::ClearInlinedVersion(Address address) {
   1265   // Insert null as the elements map to check for.  This will make
   1266   // sure that the elements fast-case map check fails so that control
   1267   // flows to the IC instead of the inlined version.
   1268   PatchInlinedStore(address, Heap::null_value());
   1269 }
   1270 
   1271 
   1272 void KeyedStoreIC::RestoreInlinedVersion(Address address) {
   1273   // Restore the fast-case elements map check so that the inlined
   1274   // version can be used again.
   1275   PatchInlinedStore(address, Heap::fixed_array_map());
   1276 }
   1277 
   1278 
   1279 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
   1280   // The address of the instruction following the call.
   1281   Address test_instruction_address =
   1282       address + Assembler::kCallTargetAddressOffset;
   1283   // If the instruction following the call is not a test eax, nothing
   1284   // was inlined.
   1285   if (*test_instruction_address != kTestEaxByte) return false;
   1286 
   1287   Address delta_address = test_instruction_address + 1;
   1288   // The delta to the start of the map check instruction.
   1289   int delta = *reinterpret_cast<int*>(delta_address);
   1290 
   1291   // The map address is the last 4 bytes of the 7-byte
   1292   // operand-immediate compare instruction, so we add 3 to get the
   1293   // offset to the last 4 bytes.
   1294   Address map_address = test_instruction_address + delta + 3;
   1295   *(reinterpret_cast<Object**>(map_address)) = map;
   1296 
   1297   // The offset is in the last 4 bytes of a six byte
   1298   // memory-to-register move instruction, so we add 2 to get the
   1299   // offset to the last 4 bytes.
   1300   Address offset_address =
   1301       test_instruction_address + delta + kOffsetToLoadInstruction + 2;
   1302   *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
   1303   return true;
   1304 }
   1305 
   1306 
   1307 static bool PatchInlinedMapCheck(Address address, Object* map) {
   1308   Address test_instruction_address =
   1309       address + Assembler::kCallTargetAddressOffset;
   1310   // The keyed load has a fast inlined case if the IC call instruction
   1311   // is immediately followed by a test instruction.
   1312   if (*test_instruction_address != kTestEaxByte) return false;
   1313 
   1314   // Fetch the offset from the test instruction to the map cmp
   1315   // instruction.  This offset is stored in the last 4 bytes of the 5
   1316   // byte test instruction.
   1317   Address delta_address = test_instruction_address + 1;
   1318   int delta = *reinterpret_cast<int*>(delta_address);
   1319   // Compute the map address.  The map address is in the last 4 bytes
   1320   // of the 7-byte operand-immediate compare instruction, so we add 3
   1321   // to the offset to get the map address.
   1322   Address map_address = test_instruction_address + delta + 3;
   1323   // Patch the map check.
   1324   *(reinterpret_cast<Object**>(map_address)) = map;
   1325   return true;
   1326 }
   1327 
   1328 
   1329 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
   1330   return PatchInlinedMapCheck(address, map);
   1331 }
   1332 
   1333 
   1334 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
   1335   return PatchInlinedMapCheck(address, map);
   1336 }
   1337 
   1338 
   1339 // Defined in ic.cc.
   1340 Object* KeyedLoadIC_Miss(Arguments args);
   1341 
   1342 
   1343 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   1344   // ----------- S t a t e -------------
   1345   //  -- eax    : key
   1346   //  -- edx    : receiver
   1347   //  -- esp[0] : return address
   1348   // -----------------------------------
   1349 
   1350   __ pop(ebx);
   1351   __ push(edx);  // receiver
   1352   __ push(eax);  // name
   1353   __ push(ebx);  // return address
   1354 
   1355   // Perform tail call to the entry.
   1356   __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1);
   1357 }
   1358 
   1359 
   1360 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   1361   // ----------- S t a t e -------------
   1362   //  -- eax    : key
   1363   //  -- edx    : receiver
   1364   //  -- esp[0] : return address
   1365   // -----------------------------------
   1366 
   1367   __ pop(ebx);
   1368   __ push(edx);  // receiver
   1369   __ push(eax);  // name
   1370   __ push(ebx);  // return address
   1371 
   1372   // Perform tail call to the entry.
   1373   __ TailCallRuntime(ExternalReference(Runtime::kKeyedGetProperty), 2, 1);
   1374 }
   1375 
   1376 
   1377 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
   1378   // ----------- S t a t e -------------
   1379   //  -- eax    : value
   1380   //  -- ecx    : name
   1381   //  -- edx    : receiver
   1382   //  -- esp[0] : return address
   1383   // -----------------------------------
   1384 
   1385   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
   1386                                          NOT_IN_LOOP,
   1387                                          MONOMORPHIC);
   1388   StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
   1389 
   1390   // Cache miss: Jump to runtime.
   1391   GenerateMiss(masm);
   1392 }
   1393 
   1394 
   1395 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1396   // ----------- S t a t e -------------
   1397   //  -- eax    : value
   1398   //  -- ecx    : name
   1399   //  -- edx    : receiver
   1400   //  -- esp[0] : return address
   1401   // -----------------------------------
   1402 
   1403   __ pop(ebx);
   1404   __ push(edx);
   1405   __ push(ecx);
   1406   __ push(eax);
   1407   __ push(ebx);
   1408 
   1409   // Perform tail call to the entry.
   1410   __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1);
   1411 }
   1412 
   1413 
   1414 // Defined in ic.cc.
   1415 Object* KeyedStoreIC_Miss(Arguments args);
   1416 
   1417 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
   1418   // ----------- S t a t e -------------
   1419   //  -- eax    : value
   1420   //  -- esp[0] : return address
   1421   //  -- esp[4] : key
   1422   //  -- esp[8] : receiver
   1423   // -----------------------------------
   1424 
   1425   __ pop(ecx);
   1426   __ push(Operand(esp, 1 * kPointerSize));
   1427   __ push(Operand(esp, 1 * kPointerSize));
   1428   __ push(eax);
   1429   __ push(ecx);
   1430 
   1431   // Do tail-call to runtime routine.
   1432   __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
   1433 }
   1434 
   1435 
   1436 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   1437   // ----------- S t a t e -------------
   1438   //  -- eax    : value
   1439   //  -- esp[0] : return address
   1440   //  -- esp[4] : key
   1441   //  -- esp[8] : receiver
   1442   // -----------------------------------
   1443 
   1444   __ pop(ecx);
   1445   __ push(Operand(esp, 1 * kPointerSize));
   1446   __ push(Operand(esp, 1 * kPointerSize));
   1447   __ push(eax);
   1448   __ push(ecx);
   1449 
   1450   // Do tail-call to runtime routine.
   1451   __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1);
   1452 }
   1453 
   1454 #undef __
   1455 
   1456 
   1457 } }  // namespace v8::internal
   1458