Home | History | Annotate | Download | only in x64
      1 // Copyright 2011 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 defined(V8_TARGET_ARCH_X64)
     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   __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
     53   __ j(equal, global_object);
     54   __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
     55   __ j(equal, global_object);
     56   __ cmpb(type, Immediate(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 GenerateStringDictionaryReceiverCheck(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   __ JumpIfSmi(receiver, miss);
     75 
     76   // Check that the receiver is a valid JS object.
     77   __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
     78   __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
     79   __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE));
     80   __ j(below, miss);
     81 
     82   // If this assert fails, we have to check upper bound too.
     83   ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
     84 
     85   GenerateGlobalInstanceTypeCheck(masm, r0, miss);
     86 
     87   // Check for non-global object that requires access check.
     88   __ testb(FieldOperand(r1, Map::kBitFieldOffset),
     89            Immediate((1 << Map::kIsAccessCheckNeeded) |
     90                      (1 << Map::kHasNamedInterceptor)));
     91   __ j(not_zero, miss);
     92 
     93   __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
     94   __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
     95                  Heap::kHashTableMapRootIndex);
     96   __ j(not_equal, miss);
     97 }
     98 
     99 
    100 // Probe the string dictionary in the |elements| register. Jump to the
    101 // |done| label if a property with the given name is found leaving the
    102 // index into the dictionary in |r1|. Jump to the |miss| label
    103 // otherwise.
    104 static void GenerateStringDictionaryProbes(MacroAssembler* masm,
    105                                            Label* miss,
    106                                            Label* done,
    107                                            Register elements,
    108                                            Register name,
    109                                            Register r0,
    110                                            Register r1) {
    111   // Assert that name contains a string.
    112   if (FLAG_debug_code) __ AbortIfNotString(name);
    113 
    114   // Compute the capacity mask.
    115   const int kCapacityOffset =
    116       StringDictionary::kHeaderSize +
    117       StringDictionary::kCapacityIndex * kPointerSize;
    118   __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
    119   __ decl(r0);
    120 
    121   // Generate an unrolled loop that performs a few probes before
    122   // giving up. Measurements done on Gmail indicate that 2 probes
    123   // cover ~93% of loads from dictionaries.
    124   static const int kProbes = 4;
    125   const int kElementsStartOffset =
    126       StringDictionary::kHeaderSize +
    127       StringDictionary::kElementsStartIndex * kPointerSize;
    128   for (int i = 0; i < kProbes; i++) {
    129     // Compute the masked index: (hash + i + i * i) & mask.
    130     __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
    131     __ shrl(r1, Immediate(String::kHashShift));
    132     if (i > 0) {
    133       __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
    134     }
    135     __ and_(r1, r0);
    136 
    137     // Scale the index by multiplying by the entry size.
    138     ASSERT(StringDictionary::kEntrySize == 3);
    139     __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
    140 
    141     // Check if the key is identical to the name.
    142     __ cmpq(name, Operand(elements, r1, times_pointer_size,
    143                           kElementsStartOffset - kHeapObjectTag));
    144     if (i != kProbes - 1) {
    145       __ j(equal, done);
    146     } else {
    147       __ j(not_equal, miss);
    148     }
    149   }
    150 }
    151 
    152 
    153 // Helper function used to load a property from a dictionary backing storage.
    154 // This function may return false negatives, so miss_label
    155 // must always call a backup property load that is complete.
    156 // This function is safe to call if name is not a symbol, and will jump to
    157 // the miss_label in that case.
    158 // The generated code assumes that the receiver has slow properties,
    159 // is not a global object and does not have interceptors.
    160 static void GenerateDictionaryLoad(MacroAssembler* masm,
    161                                    Label* miss_label,
    162                                    Register elements,
    163                                    Register name,
    164                                    Register r0,
    165                                    Register r1,
    166                                    Register result) {
    167   // Register use:
    168   //
    169   // elements - holds the property dictionary on entry and is unchanged.
    170   //
    171   // name - holds the name of the property on entry and is unchanged.
    172   //
    173   // r0   - used to hold the capacity of the property dictionary.
    174   //
    175   // r1   - used to hold the index into the property dictionary.
    176   //
    177   // result - holds the result on exit if the load succeeded.
    178 
    179   Label done;
    180 
    181   // Probe the dictionary.
    182   GenerateStringDictionaryProbes(masm,
    183                                  miss_label,
    184                                  &done,
    185                                  elements,
    186                                  name,
    187                                  r0,
    188                                  r1);
    189 
    190   // If probing finds an entry in the dictionary, r0 contains the
    191   // index into the dictionary. Check that the value is a normal
    192   // property.
    193   __ bind(&done);
    194   const int kElementsStartOffset =
    195       StringDictionary::kHeaderSize +
    196       StringDictionary::kElementsStartIndex * kPointerSize;
    197   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    198   __ Test(Operand(elements, r1, times_pointer_size,
    199                   kDetailsOffset - kHeapObjectTag),
    200           Smi::FromInt(PropertyDetails::TypeField::mask()));
    201   __ j(not_zero, miss_label);
    202 
    203   // Get the value at the masked, scaled index.
    204   const int kValueOffset = kElementsStartOffset + kPointerSize;
    205   __ movq(result,
    206           Operand(elements, r1, times_pointer_size,
    207                   kValueOffset - kHeapObjectTag));
    208 }
    209 
    210 
    211 // Helper function used to store a property to a dictionary backing
    212 // storage. This function may fail to store a property even though it
    213 // is in the dictionary, so code at miss_label must always call a
    214 // backup property store that is complete. This function is safe to
    215 // call if name is not a symbol, and will jump to the miss_label in
    216 // that case. The generated code assumes that the receiver has slow
    217 // properties, is not a global object and does not have interceptors.
    218 static void GenerateDictionaryStore(MacroAssembler* masm,
    219                                     Label* miss_label,
    220                                     Register elements,
    221                                     Register name,
    222                                     Register value,
    223                                     Register scratch0,
    224                                     Register scratch1) {
    225   // Register use:
    226   //
    227   // elements - holds the property dictionary on entry and is clobbered.
    228   //
    229   // name - holds the name of the property on entry and is unchanged.
    230   //
    231   // value - holds the value to store and is unchanged.
    232   //
    233   // scratch0 - used for index into the property dictionary and is clobbered.
    234   //
    235   // scratch1 - used to hold the capacity of the property dictionary and is
    236   //            clobbered.
    237   Label done;
    238 
    239   // Probe the dictionary.
    240   GenerateStringDictionaryProbes(masm,
    241                                  miss_label,
    242                                  &done,
    243                                  elements,
    244                                  name,
    245                                  scratch0,
    246                                  scratch1);
    247 
    248   // If probing finds an entry in the dictionary, scratch0 contains the
    249   // index into the dictionary. Check that the value is a normal
    250   // property that is not read only.
    251   __ bind(&done);
    252   const int kElementsStartOffset =
    253       StringDictionary::kHeaderSize +
    254       StringDictionary::kElementsStartIndex * kPointerSize;
    255   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
    256   const int kTypeAndReadOnlyMask
    257       = (PropertyDetails::TypeField::mask() |
    258          PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
    259   __ Test(Operand(elements,
    260                   scratch1,
    261                   times_pointer_size,
    262                   kDetailsOffset - kHeapObjectTag),
    263           Smi::FromInt(kTypeAndReadOnlyMask));
    264   __ j(not_zero, miss_label);
    265 
    266   // Store the value at the masked, scaled index.
    267   const int kValueOffset = kElementsStartOffset + kPointerSize;
    268   __ lea(scratch1, Operand(elements,
    269                            scratch1,
    270                            times_pointer_size,
    271                            kValueOffset - kHeapObjectTag));
    272   __ movq(Operand(scratch1, 0), value);
    273 
    274   // Update write barrier. Make sure not to clobber the value.
    275   __ movq(scratch0, value);
    276   __ RecordWrite(elements, scratch1, scratch0);
    277 }
    278 
    279 
    280 static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
    281                                          Label* miss,
    282                                          Register elements,
    283                                          Register key,
    284                                          Register r0,
    285                                          Register r1,
    286                                          Register r2,
    287                                          Register result) {
    288   // Register use:
    289   //
    290   // elements - holds the slow-case elements of the receiver on entry.
    291   //            Unchanged unless 'result' is the same register.
    292   //
    293   // key      - holds the smi key on entry.
    294   //            Unchanged unless 'result' is the same register.
    295   //
    296   // Scratch registers:
    297   //
    298   // r0 - holds the untagged key on entry and holds the hash once computed.
    299   //
    300   // r1 - used to hold the capacity mask of the dictionary
    301   //
    302   // r2 - used for the index into the dictionary.
    303   //
    304   // result - holds the result on exit if the load succeeded.
    305   //          Allowed to be the same as 'key' or 'result'.
    306   //          Unchanged on bailout so 'key' or 'result' can be used
    307   //          in further computation.
    308 
    309   Label done;
    310 
    311   // Compute the hash code from the untagged key.  This must be kept in sync
    312   // with ComputeIntegerHash in utils.h.
    313   //
    314   // hash = ~hash + (hash << 15);
    315   __ movl(r1, r0);
    316   __ notl(r0);
    317   __ shll(r1, Immediate(15));
    318   __ addl(r0, r1);
    319   // hash = hash ^ (hash >> 12);
    320   __ movl(r1, r0);
    321   __ shrl(r1, Immediate(12));
    322   __ xorl(r0, r1);
    323   // hash = hash + (hash << 2);
    324   __ leal(r0, Operand(r0, r0, times_4, 0));
    325   // hash = hash ^ (hash >> 4);
    326   __ movl(r1, r0);
    327   __ shrl(r1, Immediate(4));
    328   __ xorl(r0, r1);
    329   // hash = hash * 2057;
    330   __ imull(r0, r0, Immediate(2057));
    331   // hash = hash ^ (hash >> 16);
    332   __ movl(r1, r0);
    333   __ shrl(r1, Immediate(16));
    334   __ xorl(r0, r1);
    335 
    336   // Compute capacity mask.
    337   __ SmiToInteger32(r1,
    338                     FieldOperand(elements, NumberDictionary::kCapacityOffset));
    339   __ decl(r1);
    340 
    341   // Generate an unrolled loop that performs a few probes before giving up.
    342   const int kProbes = 4;
    343   for (int i = 0; i < kProbes; i++) {
    344     // Use r2 for index calculations and keep the hash intact in r0.
    345     __ movq(r2, r0);
    346     // Compute the masked index: (hash + i + i * i) & mask.
    347     if (i > 0) {
    348       __ addl(r2, Immediate(NumberDictionary::GetProbeOffset(i)));
    349     }
    350     __ and_(r2, r1);
    351 
    352     // Scale the index by multiplying by the entry size.
    353     ASSERT(NumberDictionary::kEntrySize == 3);
    354     __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
    355 
    356     // Check if the key matches.
    357     __ cmpq(key, FieldOperand(elements,
    358                               r2,
    359                               times_pointer_size,
    360                               NumberDictionary::kElementsStartOffset));
    361     if (i != (kProbes - 1)) {
    362       __ j(equal, &done);
    363     } else {
    364       __ j(not_equal, miss);
    365     }
    366   }
    367 
    368   __ bind(&done);
    369   // Check that the value is a normal propety.
    370   const int kDetailsOffset =
    371       NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
    372   ASSERT_EQ(NORMAL, 0);
    373   __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
    374           Smi::FromInt(PropertyDetails::TypeField::mask()));
    375   __ j(not_zero, miss);
    376 
    377   // Get the value at the masked, scaled index.
    378   const int kValueOffset =
    379       NumberDictionary::kElementsStartOffset + kPointerSize;
    380   __ movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
    381 }
    382 
    383 
    384 // The offset from the inlined patch site to the start of the inlined
    385 // load instruction.
    386 const int LoadIC::kOffsetToLoadInstruction = 20;
    387 
    388 
    389 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
    390   // ----------- S t a t e -------------
    391   //  -- rax    : receiver
    392   //  -- rcx    : name
    393   //  -- rsp[0] : return address
    394   // -----------------------------------
    395   Label miss;
    396 
    397   StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
    398   __ bind(&miss);
    399   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    400 }
    401 
    402 
    403 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
    404   // ----------- S t a t e -------------
    405   //  -- rax    : receiver
    406   //  -- rcx    : name
    407   //  -- rsp[0] : return address
    408   // -----------------------------------
    409   Label miss;
    410 
    411   StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss,
    412                                          support_wrappers);
    413   __ bind(&miss);
    414   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    415 }
    416 
    417 
    418 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
    419   // ----------- S t a t e -------------
    420   //  -- rax    : receiver
    421   //  -- rcx    : name
    422   //  -- rsp[0] : return address
    423   // -----------------------------------
    424   Label miss;
    425 
    426   StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
    427   __ bind(&miss);
    428   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
    429 }
    430 
    431 
    432 // Checks the receiver for special cases (value type, slow case bits).
    433 // Falls through for regular JS object.
    434 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
    435                                            Register receiver,
    436                                            Register map,
    437                                            int interceptor_bit,
    438                                            Label* slow) {
    439   // Register use:
    440   //   receiver - holds the receiver and is unchanged.
    441   // Scratch registers:
    442   //   map - used to hold the map of the receiver.
    443 
    444   // Check that the object isn't a smi.
    445   __ JumpIfSmi(receiver, slow);
    446 
    447   // Check that the object is some kind of JS object EXCEPT JS Value type.
    448   // In the case that the object is a value-wrapper object,
    449   // we enter the runtime system to make sure that indexing
    450   // into string objects work as intended.
    451   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
    452   __ CmpObjectType(receiver, JS_OBJECT_TYPE, map);
    453   __ j(below, slow);
    454 
    455   // Check bit field.
    456   __ testb(FieldOperand(map, Map::kBitFieldOffset),
    457            Immediate((1 << Map::kIsAccessCheckNeeded) |
    458                      (1 << interceptor_bit)));
    459   __ j(not_zero, slow);
    460 }
    461 
    462 
    463 // Loads an indexed element from a fast case array.
    464 // If not_fast_array is NULL, doesn't perform the elements map check.
    465 static void GenerateFastArrayLoad(MacroAssembler* masm,
    466                                   Register receiver,
    467                                   Register key,
    468                                   Register elements,
    469                                   Register scratch,
    470                                   Register result,
    471                                   Label* not_fast_array,
    472                                   Label* out_of_range) {
    473   // Register use:
    474   //
    475   // receiver - holds the receiver on entry.
    476   //            Unchanged unless 'result' is the same register.
    477   //
    478   // key      - holds the smi key on entry.
    479   //            Unchanged unless 'result' is the same register.
    480   //
    481   // elements - holds the elements of the receiver on exit.
    482   //
    483   // result   - holds the result on exit if the load succeeded.
    484   //            Allowed to be the the same as 'receiver' or 'key'.
    485   //            Unchanged on bailout so 'receiver' and 'key' can be safely
    486   //            used by further computation.
    487   //
    488   // Scratch registers:
    489   //
    490   //   scratch - used to hold elements of the receiver and the loaded value.
    491 
    492   __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
    493   if (not_fast_array != NULL) {
    494     // Check that the object is in fast mode and writable.
    495     __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
    496                    Heap::kFixedArrayMapRootIndex);
    497     __ j(not_equal, not_fast_array);
    498   } else {
    499     __ AssertFastElements(elements);
    500   }
    501   // Check that the key (index) is within bounds.
    502   __ SmiCompare(key, FieldOperand(elements, FixedArray::kLengthOffset));
    503   // Unsigned comparison rejects negative indices.
    504   __ j(above_equal, out_of_range);
    505   // Fast case: Do the load.
    506   SmiIndex index = masm->SmiToIndex(scratch, key, kPointerSizeLog2);
    507   __ movq(scratch, FieldOperand(elements,
    508                                 index.reg,
    509                                 index.scale,
    510                                 FixedArray::kHeaderSize));
    511   __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
    512   // In case the loaded value is the_hole we have to consult GetProperty
    513   // to ensure the prototype chain is searched.
    514   __ j(equal, out_of_range);
    515   if (!result.is(scratch)) {
    516     __ movq(result, scratch);
    517   }
    518 }
    519 
    520 
    521 // Checks whether a key is an array index string or a symbol string.
    522 // Falls through if the key is a symbol.
    523 static void GenerateKeyStringCheck(MacroAssembler* masm,
    524                                    Register key,
    525                                    Register map,
    526                                    Register hash,
    527                                    Label* index_string,
    528                                    Label* not_symbol) {
    529   // Register use:
    530   //   key - holds the key and is unchanged. Assumed to be non-smi.
    531   // Scratch registers:
    532   //   map - used to hold the map of the key.
    533   //   hash - used to hold the hash of the key.
    534   __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
    535   __ j(above_equal, not_symbol);
    536   // Is the string an array index, with cached numeric value?
    537   __ movl(hash, FieldOperand(key, String::kHashFieldOffset));
    538   __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask));
    539   __ j(zero, index_string);  // The value in hash is used at jump target.
    540 
    541   // Is the string a symbol?
    542   ASSERT(kSymbolTag != 0);
    543   __ testb(FieldOperand(map, Map::kInstanceTypeOffset),
    544            Immediate(kIsSymbolMask));
    545   __ j(zero, not_symbol);
    546 }
    547 
    548 
    549 
    550 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
    551   // ----------- S t a t e -------------
    552   //  -- rax    : key
    553   //  -- rdx    : receiver
    554   //  -- rsp[0] : return address
    555   // -----------------------------------
    556   Label slow, check_string, index_smi, index_string, property_array_property;
    557   Label probe_dictionary, check_number_dictionary;
    558 
    559   // Check that the key is a smi.
    560   __ JumpIfNotSmi(rax, &check_string);
    561   __ bind(&index_smi);
    562   // Now the key is known to be a smi. This place is also jumped to from below
    563   // where a numeric string is converted to a smi.
    564 
    565   GenerateKeyedLoadReceiverCheck(
    566       masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
    567 
    568   // Check the "has fast elements" bit in the receiver's map which is
    569   // now in rcx.
    570   __ testb(FieldOperand(rcx, Map::kBitField2Offset),
    571            Immediate(1 << Map::kHasFastElements));
    572   __ j(zero, &check_number_dictionary);
    573 
    574   GenerateFastArrayLoad(masm,
    575                         rdx,
    576                         rax,
    577                         rcx,
    578                         rbx,
    579                         rax,
    580                         NULL,
    581                         &slow);
    582   Counters* counters = masm->isolate()->counters();
    583   __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
    584   __ ret(0);
    585 
    586   __ bind(&check_number_dictionary);
    587   __ SmiToInteger32(rbx, rax);
    588   __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
    589 
    590   // Check whether the elements is a number dictionary.
    591   // rdx: receiver
    592   // rax: key
    593   // rbx: key as untagged int32
    594   // rcx: elements
    595   __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
    596                  Heap::kHashTableMapRootIndex);
    597   __ j(not_equal, &slow);
    598   GenerateNumberDictionaryLoad(masm, &slow, rcx, rax, rbx, r9, rdi, rax);
    599   __ ret(0);
    600 
    601   __ bind(&slow);
    602   // Slow case: Jump to runtime.
    603   // rdx: receiver
    604   // rax: key
    605   __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
    606   GenerateRuntimeGetProperty(masm);
    607 
    608   __ bind(&check_string);
    609   GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
    610 
    611   GenerateKeyedLoadReceiverCheck(
    612       masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
    613 
    614   // If the receiver is a fast-case object, check the keyed lookup
    615   // cache. Otherwise probe the dictionary leaving result in rcx.
    616   __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
    617   __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
    618                  Heap::kHashTableMapRootIndex);
    619   __ j(equal, &probe_dictionary);
    620 
    621   // Load the map of the receiver, compute the keyed lookup cache hash
    622   // based on 32 bits of the map pointer and the string hash.
    623   __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
    624   __ movl(rcx, rbx);
    625   __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift));
    626   __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset));
    627   __ shr(rdi, Immediate(String::kHashShift));
    628   __ xor_(rcx, rdi);
    629   __ and_(rcx, Immediate(KeyedLookupCache::kCapacityMask));
    630 
    631   // Load the key (consisting of map and symbol) from the cache and
    632   // check for match.
    633   ExternalReference cache_keys
    634       = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
    635   __ movq(rdi, rcx);
    636   __ shl(rdi, Immediate(kPointerSizeLog2 + 1));
    637   __ LoadAddress(kScratchRegister, cache_keys);
    638   __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, 0));
    639   __ j(not_equal, &slow);
    640   __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, kPointerSize));
    641   __ j(not_equal, &slow);
    642 
    643   // Get field offset, which is a 32-bit integer.
    644   ExternalReference cache_field_offsets
    645       = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
    646   __ LoadAddress(kScratchRegister, cache_field_offsets);
    647   __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
    648   __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
    649   __ subq(rdi, rcx);
    650   __ j(above_equal, &property_array_property);
    651 
    652   // Load in-object property.
    653   __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
    654   __ addq(rcx, rdi);
    655   __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
    656   __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
    657   __ ret(0);
    658 
    659   // Load property array property.
    660   __ bind(&property_array_property);
    661   __ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
    662   __ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
    663                             FixedArray::kHeaderSize));
    664   __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
    665   __ ret(0);
    666 
    667   // Do a quick inline probe of the receiver's dictionary, if it
    668   // exists.
    669   __ bind(&probe_dictionary);
    670   // rdx: receiver
    671   // rax: key
    672   // rbx: elements
    673 
    674   __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
    675   __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
    676   GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
    677 
    678   GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
    679   __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
    680   __ ret(0);
    681 
    682   __ bind(&index_string);
    683   __ IndexFromHash(rbx, rax);
    684   __ jmp(&index_smi);
    685 }
    686 
    687 
    688 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
    689   // ----------- S t a t e -------------
    690   //  -- rax    : key
    691   //  -- rdx    : receiver
    692   //  -- rsp[0] : return address
    693   // -----------------------------------
    694   Label miss;
    695 
    696   Register receiver = rdx;
    697   Register index = rax;
    698   Register scratch1 = rbx;
    699   Register scratch2 = rcx;
    700   Register result = rax;
    701 
    702   StringCharAtGenerator char_at_generator(receiver,
    703                                           index,
    704                                           scratch1,
    705                                           scratch2,
    706                                           result,
    707                                           &miss,  // When not a string.
    708                                           &miss,  // When not a number.
    709                                           &miss,  // When index out of range.
    710                                           STRING_INDEX_IS_ARRAY_INDEX);
    711   char_at_generator.GenerateFast(masm);
    712   __ ret(0);
    713 
    714   StubRuntimeCallHelper call_helper;
    715   char_at_generator.GenerateSlow(masm, call_helper);
    716 
    717   __ bind(&miss);
    718   GenerateMiss(masm);
    719 }
    720 
    721 
    722 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
    723   // ----------- S t a t e -------------
    724   //  -- rax    : key
    725   //  -- rdx    : receiver
    726   //  -- rsp[0] : return address
    727   // -----------------------------------
    728   Label slow;
    729 
    730   // Check that the receiver isn't a smi.
    731   __ JumpIfSmi(rdx, &slow);
    732 
    733   // Check that the key is an array index, that is Uint32.
    734   STATIC_ASSERT(kSmiValueSize <= 32);
    735   __ JumpUnlessNonNegativeSmi(rax, &slow);
    736 
    737   // Get the map of the receiver.
    738   __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
    739 
    740   // Check that it has indexed interceptor and access checks
    741   // are not enabled for this object.
    742   __ movb(rcx, FieldOperand(rcx, Map::kBitFieldOffset));
    743   __ andb(rcx, Immediate(kSlowCaseBitFieldMask));
    744   __ cmpb(rcx, Immediate(1 << Map::kHasIndexedInterceptor));
    745   __ j(not_zero, &slow);
    746 
    747   // Everything is fine, call runtime.
    748   __ pop(rcx);
    749   __ push(rdx);  // receiver
    750   __ push(rax);  // key
    751   __ push(rcx);  // return address
    752 
    753   // Perform tail call to the entry.
    754   __ TailCallExternalReference(
    755       ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
    756                         masm->isolate()),
    757       2,
    758       1);
    759 
    760   __ bind(&slow);
    761   GenerateMiss(masm);
    762 }
    763 
    764 
    765 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
    766                                    StrictModeFlag strict_mode) {
    767   // ----------- S t a t e -------------
    768   //  -- rax     : value
    769   //  -- rcx     : key
    770   //  -- rdx     : receiver
    771   //  -- rsp[0]  : return address
    772   // -----------------------------------
    773   Label slow, slow_with_tagged_index, fast, array, extra;
    774 
    775   // Check that the object isn't a smi.
    776   __ JumpIfSmi(rdx, &slow_with_tagged_index);
    777   // Get the map from the receiver.
    778   __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
    779   // Check that the receiver does not require access checks.  We need
    780   // to do this because this generic stub does not perform map checks.
    781   __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
    782            Immediate(1 << Map::kIsAccessCheckNeeded));
    783   __ j(not_zero, &slow_with_tagged_index);
    784   // Check that the key is a smi.
    785   __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
    786   __ SmiToInteger32(rcx, rcx);
    787 
    788   __ CmpInstanceType(rbx, JS_ARRAY_TYPE);
    789   __ j(equal, &array);
    790   // Check that the object is some kind of JS object.
    791   __ CmpInstanceType(rbx, FIRST_JS_OBJECT_TYPE);
    792   __ j(below, &slow);
    793 
    794   // Object case: Check key against length in the elements array.
    795   // rax: value
    796   // rdx: JSObject
    797   // rcx: index
    798   __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
    799   // Check that the object is in fast mode and writable.
    800   __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
    801                  Heap::kFixedArrayMapRootIndex);
    802   __ j(not_equal, &slow);
    803   __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
    804   // rax: value
    805   // rbx: FixedArray
    806   // rcx: index
    807   __ j(above, &fast);
    808 
    809   // Slow case: call runtime.
    810   __ bind(&slow);
    811   __ Integer32ToSmi(rcx, rcx);
    812   __ bind(&slow_with_tagged_index);
    813   GenerateRuntimeSetProperty(masm, strict_mode);
    814   // Never returns to here.
    815 
    816   // Extra capacity case: Check if there is extra capacity to
    817   // perform the store and update the length. Used for adding one
    818   // element to the array by writing to array[array.length].
    819   __ bind(&extra);
    820   // rax: value
    821   // rdx: receiver (a JSArray)
    822   // rbx: receiver's elements array (a FixedArray)
    823   // rcx: index
    824   // flags: smicompare (rdx.length(), rbx)
    825   __ j(not_equal, &slow);  // do not leave holes in the array
    826   __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
    827   __ j(below_equal, &slow);
    828   // Increment index to get new length.
    829   __ leal(rdi, Operand(rcx, 1));
    830   __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
    831   __ jmp(&fast);
    832 
    833   // Array case: Get the length and the elements array from the JS
    834   // array. Check that the array is in fast mode (and writable); if it
    835   // is the length is always a smi.
    836   __ bind(&array);
    837   // rax: value
    838   // rdx: receiver (a JSArray)
    839   // rcx: index
    840   __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
    841   __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
    842                  Heap::kFixedArrayMapRootIndex);
    843   __ j(not_equal, &slow);
    844 
    845   // Check the key against the length in the array, compute the
    846   // address to store into and fall through to fast case.
    847   __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
    848   __ j(below_equal, &extra);
    849 
    850   // Fast case: Do the store.
    851   __ bind(&fast);
    852   // rax: value
    853   // rbx: receiver's elements array (a FixedArray)
    854   // rcx: index
    855   NearLabel non_smi_value;
    856   __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
    857           rax);
    858   __ JumpIfNotSmi(rax, &non_smi_value);
    859   __ ret(0);
    860   __ bind(&non_smi_value);
    861   // Slow case that needs to retain rcx for use by RecordWrite.
    862   // Update write barrier for the elements array address.
    863   __ movq(rdx, rax);
    864   __ RecordWriteNonSmi(rbx, 0, rdx, rcx);
    865   __ ret(0);
    866 }
    867 
    868 
    869 // The generated code does not accept smi keys.
    870 // The generated code falls through if both probes miss.
    871 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
    872                                           int argc,
    873                                           Code::Kind kind) {
    874   // ----------- S t a t e -------------
    875   // rcx                      : function name
    876   // rdx                      : receiver
    877   // -----------------------------------
    878   Label number, non_number, non_string, boolean, probe, miss;
    879 
    880   // Probe the stub cache.
    881   Code::Flags flags = Code::ComputeFlags(kind,
    882                                          NOT_IN_LOOP,
    883                                          MONOMORPHIC,
    884                                          Code::kNoExtraICState,
    885                                          NORMAL,
    886                                          argc);
    887   Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
    888                                                   rax);
    889 
    890   // If the stub cache probing failed, the receiver might be a value.
    891   // For value objects, we use the map of the prototype objects for
    892   // the corresponding JSValue for the cache and that is what we need
    893   // to probe.
    894   //
    895   // Check for number.
    896   __ JumpIfSmi(rdx, &number);
    897   __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
    898   __ j(not_equal, &non_number);
    899   __ bind(&number);
    900   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    901       masm, Context::NUMBER_FUNCTION_INDEX, rdx);
    902   __ jmp(&probe);
    903 
    904   // Check for string.
    905   __ bind(&non_number);
    906   __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
    907   __ j(above_equal, &non_string);
    908   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    909       masm, Context::STRING_FUNCTION_INDEX, rdx);
    910   __ jmp(&probe);
    911 
    912   // Check for boolean.
    913   __ bind(&non_string);
    914   __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
    915   __ j(equal, &boolean);
    916   __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
    917   __ j(not_equal, &miss);
    918   __ bind(&boolean);
    919   StubCompiler::GenerateLoadGlobalFunctionPrototype(
    920       masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
    921 
    922   // Probe the stub cache for the value object.
    923   __ bind(&probe);
    924   Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
    925                                                   no_reg);
    926 
    927   __ bind(&miss);
    928 }
    929 
    930 
    931 static void GenerateFunctionTailCall(MacroAssembler* masm,
    932                                      int argc,
    933                                      Label* miss) {
    934   // ----------- S t a t e -------------
    935   // rcx                    : function name
    936   // rdi                    : function
    937   // rsp[0]                 : return address
    938   // rsp[8]                 : argument argc
    939   // rsp[16]                : argument argc - 1
    940   // ...
    941   // rsp[argc * 8]          : argument 1
    942   // rsp[(argc + 1) * 8]    : argument 0 = receiver
    943   // -----------------------------------
    944   __ JumpIfSmi(rdi, miss);
    945   // Check that the value is a JavaScript function.
    946   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
    947   __ j(not_equal, miss);
    948 
    949   // Invoke the function.
    950   ParameterCount actual(argc);
    951   __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
    952 }
    953 
    954 
    955 // The generated code falls through if the call should be handled by runtime.
    956 static void GenerateCallNormal(MacroAssembler* masm, int argc) {
    957   // ----------- S t a t e -------------
    958   // rcx                    : function name
    959   // rsp[0]                 : return address
    960   // rsp[8]                 : argument argc
    961   // rsp[16]                : argument argc - 1
    962   // ...
    963   // rsp[argc * 8]          : argument 1
    964   // rsp[(argc + 1) * 8]    : argument 0 = receiver
    965   // -----------------------------------
    966   Label miss;
    967 
    968   // Get the receiver of the function from the stack.
    969   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
    970 
    971   GenerateStringDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
    972 
    973   // rax: elements
    974   // Search the dictionary placing the result in rdi.
    975   GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
    976 
    977   GenerateFunctionTailCall(masm, argc, &miss);
    978 
    979   __ bind(&miss);
    980 }
    981 
    982 
    983 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
    984   // ----------- S t a t e -------------
    985   // rcx                      : function name
    986   // rsp[0]                   : return address
    987   // rsp[8]                   : argument argc
    988   // rsp[16]                  : argument argc - 1
    989   // ...
    990   // rsp[argc * 8]            : argument 1
    991   // rsp[(argc + 1) * 8]      : argument 0 = receiver
    992   // -----------------------------------
    993 
    994   Counters* counters = masm->isolate()->counters();
    995   if (id == IC::kCallIC_Miss) {
    996     __ IncrementCounter(counters->call_miss(), 1);
    997   } else {
    998     __ IncrementCounter(counters->keyed_call_miss(), 1);
    999   }
   1000 
   1001   // Get the receiver of the function from the stack; 1 ~ return address.
   1002   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
   1003 
   1004   // Enter an internal frame.
   1005   __ EnterInternalFrame();
   1006 
   1007   // Push the receiver and the name of the function.
   1008   __ push(rdx);
   1009   __ push(rcx);
   1010 
   1011   // Call the entry.
   1012   CEntryStub stub(1);
   1013   __ Set(rax, 2);
   1014   __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
   1015   __ CallStub(&stub);
   1016 
   1017   // Move result to rdi and exit the internal frame.
   1018   __ movq(rdi, rax);
   1019   __ LeaveInternalFrame();
   1020 
   1021   // Check if the receiver is a global object of some sort.
   1022   // This can happen only for regular CallIC but not KeyedCallIC.
   1023   if (id == IC::kCallIC_Miss) {
   1024     Label invoke, global;
   1025     __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));  // receiver
   1026     __ JumpIfSmi(rdx, &invoke);
   1027     __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
   1028     __ j(equal, &global);
   1029     __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
   1030     __ j(not_equal, &invoke);
   1031 
   1032     // Patch the receiver on the stack.
   1033     __ bind(&global);
   1034     __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
   1035     __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
   1036     __ bind(&invoke);
   1037   }
   1038 
   1039   // Invoke the function.
   1040   ParameterCount actual(argc);
   1041   __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
   1042 }
   1043 
   1044 
   1045 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   1046   // ----------- S t a t e -------------
   1047   // rcx                      : function name
   1048   // rsp[0]                   : return address
   1049   // rsp[8]                   : argument argc
   1050   // rsp[16]                  : argument argc - 1
   1051   // ...
   1052   // rsp[argc * 8]            : argument 1
   1053   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1054   // -----------------------------------
   1055 
   1056   // Get the receiver of the function from the stack; 1 ~ return address.
   1057   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
   1058   GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
   1059   GenerateMiss(masm, argc);
   1060 }
   1061 
   1062 
   1063 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   1064   // ----------- S t a t e -------------
   1065   // rcx                      : function name
   1066   // rsp[0]                   : return address
   1067   // rsp[8]                   : argument argc
   1068   // rsp[16]                  : argument argc - 1
   1069   // ...
   1070   // rsp[argc * 8]            : argument 1
   1071   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1072   // -----------------------------------
   1073 
   1074   GenerateCallNormal(masm, argc);
   1075   GenerateMiss(masm, argc);
   1076 }
   1077 
   1078 
   1079 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
   1080   // ----------- S t a t e -------------
   1081   // rcx                      : function name
   1082   // rsp[0]                   : return address
   1083   // rsp[8]                   : argument argc
   1084   // rsp[16]                  : argument argc - 1
   1085   // ...
   1086   // rsp[argc * 8]            : argument 1
   1087   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1088   // -----------------------------------
   1089 
   1090   GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
   1091 }
   1092 
   1093 
   1094 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   1095   // ----------- S t a t e -------------
   1096   // rcx                      : function name
   1097   // rsp[0]                   : return address
   1098   // rsp[8]                   : argument argc
   1099   // rsp[16]                  : argument argc - 1
   1100   // ...
   1101   // rsp[argc * 8]            : argument 1
   1102   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1103   // -----------------------------------
   1104 
   1105   // Get the receiver of the function from the stack; 1 ~ return address.
   1106   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
   1107 
   1108   Label do_call, slow_call, slow_load;
   1109   Label check_number_dictionary, check_string, lookup_monomorphic_cache;
   1110   Label index_smi, index_string;
   1111 
   1112   // Check that the key is a smi.
   1113   __ JumpIfNotSmi(rcx, &check_string);
   1114 
   1115   __ bind(&index_smi);
   1116   // Now the key is known to be a smi. This place is also jumped to from below
   1117   // where a numeric string is converted to a smi.
   1118 
   1119   GenerateKeyedLoadReceiverCheck(
   1120       masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
   1121 
   1122   GenerateFastArrayLoad(
   1123       masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
   1124   Counters* counters = masm->isolate()->counters();
   1125   __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
   1126 
   1127   __ bind(&do_call);
   1128   // receiver in rdx is not used after this point.
   1129   // rcx: key
   1130   // rdi: function
   1131   GenerateFunctionTailCall(masm, argc, &slow_call);
   1132 
   1133   __ bind(&check_number_dictionary);
   1134   // rax: elements
   1135   // rcx: smi key
   1136   // Check whether the elements is a number dictionary.
   1137   __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
   1138                  Heap::kHashTableMapRootIndex);
   1139   __ j(not_equal, &slow_load);
   1140   __ SmiToInteger32(rbx, rcx);
   1141   // ebx: untagged index
   1142   GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi);
   1143   __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
   1144   __ jmp(&do_call);
   1145 
   1146   __ bind(&slow_load);
   1147   // This branch is taken when calling KeyedCallIC_Miss is neither required
   1148   // nor beneficial.
   1149   __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
   1150   __ EnterInternalFrame();
   1151   __ push(rcx);  // save the key
   1152   __ push(rdx);  // pass the receiver
   1153   __ push(rcx);  // pass the key
   1154   __ CallRuntime(Runtime::kKeyedGetProperty, 2);
   1155   __ pop(rcx);  // restore the key
   1156   __ LeaveInternalFrame();
   1157   __ movq(rdi, rax);
   1158   __ jmp(&do_call);
   1159 
   1160   __ bind(&check_string);
   1161   GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call);
   1162 
   1163   // The key is known to be a symbol.
   1164   // If the receiver is a regular JS object with slow properties then do
   1165   // a quick inline probe of the receiver's dictionary.
   1166   // Otherwise do the monomorphic cache probe.
   1167   GenerateKeyedLoadReceiverCheck(
   1168       masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
   1169 
   1170   __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
   1171   __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
   1172                  Heap::kHashTableMapRootIndex);
   1173   __ j(not_equal, &lookup_monomorphic_cache);
   1174 
   1175   GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
   1176   __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
   1177   __ jmp(&do_call);
   1178 
   1179   __ bind(&lookup_monomorphic_cache);
   1180   __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
   1181   GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
   1182   // Fall through on miss.
   1183 
   1184   __ bind(&slow_call);
   1185   // This branch is taken if:
   1186   // - the receiver requires boxing or access check,
   1187   // - the key is neither smi nor symbol,
   1188   // - the value loaded is not a function,
   1189   // - there is hope that the runtime will create a monomorphic call stub
   1190   //   that will get fetched next time.
   1191   __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
   1192   GenerateMiss(masm, argc);
   1193 
   1194   __ bind(&index_string);
   1195   __ IndexFromHash(rbx, rcx);
   1196   // Now jump to the place where smi keys are handled.
   1197   __ jmp(&index_smi);
   1198 }
   1199 
   1200 
   1201 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   1202   // ----------- S t a t e -------------
   1203   // rcx                      : function name
   1204   // rsp[0]                   : return address
   1205   // rsp[8]                   : argument argc
   1206   // rsp[16]                  : argument argc - 1
   1207   // ...
   1208   // rsp[argc * 8]            : argument 1
   1209   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1210   // -----------------------------------
   1211 
   1212   // Check if the name is a string.
   1213   Label miss;
   1214   __ JumpIfSmi(rcx, &miss);
   1215   Condition cond = masm->IsObjectStringType(rcx, rax, rax);
   1216   __ j(NegateCondition(cond), &miss);
   1217   GenerateCallNormal(masm, argc);
   1218   __ bind(&miss);
   1219   GenerateMiss(masm, argc);
   1220 }
   1221 
   1222 
   1223 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
   1224   // ----------- S t a t e -------------
   1225   // rcx                      : function name
   1226   // rsp[0]                   : return address
   1227   // rsp[8]                   : argument argc
   1228   // rsp[16]                  : argument argc - 1
   1229   // ...
   1230   // rsp[argc * 8]            : argument 1
   1231   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   1232   // -----------------------------------
   1233 
   1234   GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
   1235 }
   1236 
   1237 
   1238 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   1239   // ----------- S t a t e -------------
   1240   //  -- rax    : receiver
   1241   //  -- rcx    : name
   1242   //  -- rsp[0] : return address
   1243   // -----------------------------------
   1244 
   1245   // Probe the stub cache.
   1246   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
   1247                                          NOT_IN_LOOP,
   1248                                          MONOMORPHIC);
   1249   Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
   1250                                                   rdx);
   1251 
   1252   // Cache miss: Jump to runtime.
   1253   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
   1254 }
   1255 
   1256 
   1257 void LoadIC::GenerateNormal(MacroAssembler* masm) {
   1258   // ----------- S t a t e -------------
   1259   //  -- rax    : receiver
   1260   //  -- rcx    : name
   1261   //  -- rsp[0] : return address
   1262   // -----------------------------------
   1263   Label miss;
   1264 
   1265   GenerateStringDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
   1266 
   1267   //  rdx: elements
   1268   // Search the dictionary placing the result in rax.
   1269   GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
   1270   __ ret(0);
   1271 
   1272   // Cache miss: Jump to runtime.
   1273   __ bind(&miss);
   1274   GenerateMiss(masm);
   1275 }
   1276 
   1277 
   1278 void LoadIC::GenerateMiss(MacroAssembler* masm) {
   1279   // ----------- S t a t e -------------
   1280   //  -- rax    : receiver
   1281   //  -- rcx    : name
   1282   //  -- rsp[0] : return address
   1283   // -----------------------------------
   1284 
   1285   Counters* counters = masm->isolate()->counters();
   1286   __ IncrementCounter(counters->load_miss(), 1);
   1287 
   1288   __ pop(rbx);
   1289   __ push(rax);  // receiver
   1290   __ push(rcx);  // name
   1291   __ push(rbx);  // return address
   1292 
   1293   // Perform tail call to the entry.
   1294   ExternalReference ref =
   1295       ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
   1296   __ TailCallExternalReference(ref, 2, 1);
   1297 }
   1298 
   1299 
   1300 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
   1301   if (V8::UseCrankshaft()) return false;
   1302 
   1303   // The address of the instruction following the call.
   1304   Address test_instruction_address =
   1305       address + Assembler::kCallTargetAddressOffset;
   1306   // If the instruction following the call is not a test rax, nothing
   1307   // was inlined.
   1308   if (*test_instruction_address != Assembler::kTestEaxByte) return false;
   1309 
   1310   Address delta_address = test_instruction_address + 1;
   1311   // The delta to the start of the map check instruction.
   1312   int delta = *reinterpret_cast<int*>(delta_address);
   1313 
   1314   // The map address is the last 8 bytes of the 10-byte
   1315   // immediate move instruction, so we add 2 to get the
   1316   // offset to the last 8 bytes.
   1317   Address map_address = test_instruction_address + delta + 2;
   1318   *(reinterpret_cast<Object**>(map_address)) = map;
   1319 
   1320   // The offset is in the 32-bit displacement of a seven byte
   1321   // memory-to-register move instruction (REX.W 0x88 ModR/M disp32),
   1322   // so we add 3 to get the offset of the displacement.
   1323   Address offset_address =
   1324       test_instruction_address + delta + kOffsetToLoadInstruction + 3;
   1325   *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
   1326   return true;
   1327 }
   1328 
   1329 
   1330 bool LoadIC::PatchInlinedContextualLoad(Address address,
   1331                                         Object* map,
   1332                                         Object* cell,
   1333                                         bool is_dont_delete) {
   1334   // TODO(<bug#>): implement this.
   1335   return false;
   1336 }
   1337 
   1338 
   1339 bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
   1340   if (V8::UseCrankshaft()) return false;
   1341 
   1342   // The address of the instruction following the call.
   1343   Address test_instruction_address =
   1344       address + Assembler::kCallTargetAddressOffset;
   1345 
   1346   // If the instruction following the call is not a test rax, nothing
   1347   // was inlined.
   1348   if (*test_instruction_address != Assembler::kTestEaxByte) return false;
   1349 
   1350   // Extract the encoded deltas from the test rax instruction.
   1351   Address encoded_offsets_address = test_instruction_address + 1;
   1352   int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
   1353   int delta_to_map_check = -(encoded_offsets & 0xFFFF);
   1354   int delta_to_record_write = encoded_offsets >> 16;
   1355 
   1356   // Patch the map to check. The map address is the last 8 bytes of
   1357   // the 10-byte immediate move instruction.
   1358   Address map_check_address = test_instruction_address + delta_to_map_check;
   1359   Address map_address = map_check_address + 2;
   1360   *(reinterpret_cast<Object**>(map_address)) = map;
   1361 
   1362   // Patch the offset in the store instruction. The offset is in the
   1363   // last 4 bytes of a 7 byte register-to-memory move instruction.
   1364   Address offset_address =
   1365       map_check_address + StoreIC::kOffsetToStoreInstruction + 3;
   1366   // The offset should have initial value (kMaxInt - 1), cleared value
   1367   // (-1) or we should be clearing the inlined version.
   1368   ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
   1369          *reinterpret_cast<int*>(offset_address) == -1 ||
   1370          (offset == 0 && map == HEAP->null_value()));
   1371   *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
   1372 
   1373   // Patch the offset in the write-barrier code. The offset is the
   1374   // last 4 bytes of a 7 byte lea instruction.
   1375   offset_address = map_check_address + delta_to_record_write + 3;
   1376   // The offset should have initial value (kMaxInt), cleared value
   1377   // (-1) or we should be clearing the inlined version.
   1378   ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
   1379          *reinterpret_cast<int*>(offset_address) == -1 ||
   1380          (offset == 0 && map == HEAP->null_value()));
   1381   *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
   1382 
   1383   return true;
   1384 }
   1385 
   1386 
   1387 static bool PatchInlinedMapCheck(Address address, Object* map) {
   1388   if (V8::UseCrankshaft()) return false;
   1389 
   1390   // Arguments are address of start of call sequence that called
   1391   // the IC,
   1392   Address test_instruction_address =
   1393       address + Assembler::kCallTargetAddressOffset;
   1394   // The keyed load has a fast inlined case if the IC call instruction
   1395   // is immediately followed by a test instruction.
   1396   if (*test_instruction_address != Assembler::kTestEaxByte) return false;
   1397 
   1398   // Fetch the offset from the test instruction to the map compare
   1399   // instructions (starting with the 64-bit immediate mov of the map
   1400   // address). This offset is stored in the last 4 bytes of the 5
   1401   // byte test instruction.
   1402   Address delta_address = test_instruction_address + 1;
   1403   int delta = *reinterpret_cast<int*>(delta_address);
   1404   // Compute the map address.  The map address is in the last 8 bytes
   1405   // of the 10-byte immediate mov instruction (incl. REX prefix), so we add 2
   1406   // to the offset to get the map address.
   1407   Address map_address = test_instruction_address + delta + 2;
   1408   // Patch the map check.
   1409   *(reinterpret_cast<Object**>(map_address)) = map;
   1410   return true;
   1411 }
   1412 
   1413 
   1414 bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
   1415   return PatchInlinedMapCheck(address, map);
   1416 }
   1417 
   1418 
   1419 bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
   1420   return PatchInlinedMapCheck(address, map);
   1421 }
   1422 
   1423 
   1424 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   1425   // ----------- S t a t e -------------
   1426   //  -- rax    : key
   1427   //  -- rdx    : receiver
   1428   //  -- rsp[0]  : return address
   1429   // -----------------------------------
   1430 
   1431   Counters* counters = masm->isolate()->counters();
   1432   __ IncrementCounter(counters->keyed_load_miss(), 1);
   1433 
   1434   __ pop(rbx);
   1435   __ push(rdx);  // receiver
   1436   __ push(rax);  // name
   1437   __ push(rbx);  // return address
   1438 
   1439   // Perform tail call to the entry.
   1440   ExternalReference ref
   1441       = ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
   1442   __ TailCallExternalReference(ref, 2, 1);
   1443 }
   1444 
   1445 
   1446 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
   1447   // ----------- S t a t e -------------
   1448   //  -- rax    : key
   1449   //  -- rdx    : receiver
   1450   //  -- rsp[0]  : return address
   1451   // -----------------------------------
   1452 
   1453   __ pop(rbx);
   1454   __ push(rdx);  // receiver
   1455   __ push(rax);  // name
   1456   __ push(rbx);  // return address
   1457 
   1458   // Perform tail call to the entry.
   1459   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
   1460 }
   1461 
   1462 
   1463 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
   1464                                   StrictModeFlag strict_mode) {
   1465   // ----------- S t a t e -------------
   1466   //  -- rax    : value
   1467   //  -- rcx    : name
   1468   //  -- rdx    : receiver
   1469   //  -- rsp[0] : return address
   1470   // -----------------------------------
   1471 
   1472   // Get the receiver from the stack and probe the stub cache.
   1473   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
   1474                                          NOT_IN_LOOP,
   1475                                          MONOMORPHIC,
   1476                                          strict_mode);
   1477   Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
   1478                                                   no_reg);
   1479 
   1480   // Cache miss: Jump to runtime.
   1481   GenerateMiss(masm);
   1482 }
   1483 
   1484 
   1485 void StoreIC::GenerateMiss(MacroAssembler* masm) {
   1486   // ----------- S t a t e -------------
   1487   //  -- rax    : value
   1488   //  -- rcx    : name
   1489   //  -- rdx    : receiver
   1490   //  -- rsp[0] : return address
   1491   // -----------------------------------
   1492 
   1493   __ pop(rbx);
   1494   __ push(rdx);  // receiver
   1495   __ push(rcx);  // name
   1496   __ push(rax);  // value
   1497   __ push(rbx);  // return address
   1498 
   1499   // Perform tail call to the entry.
   1500   ExternalReference ref =
   1501       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
   1502   __ TailCallExternalReference(ref, 3, 1);
   1503 }
   1504 
   1505 
   1506 // The offset from the inlined patch site to the start of the inlined
   1507 // store instruction.
   1508 const int StoreIC::kOffsetToStoreInstruction = 20;
   1509 
   1510 
   1511 void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
   1512   // ----------- S t a t e -------------
   1513   //  -- rax    : value
   1514   //  -- rcx    : name
   1515   //  -- rdx    : receiver
   1516   //  -- rsp[0] : return address
   1517   // -----------------------------------
   1518   //
   1519   // This accepts as a receiver anything JSObject::SetElementsLength accepts
   1520   // (currently anything except for external and pixel arrays which means
   1521   // anything with elements of FixedArray type.), but currently is restricted
   1522   // to JSArray.
   1523   // Value must be a number, but only smis are accepted as the most common case.
   1524 
   1525   Label miss;
   1526 
   1527   Register receiver = rdx;
   1528   Register value = rax;
   1529   Register scratch = rbx;
   1530 
   1531   // Check that the receiver isn't a smi.
   1532   __ JumpIfSmi(receiver, &miss);
   1533 
   1534   // Check that the object is a JS array.
   1535   __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
   1536   __ j(not_equal, &miss);
   1537 
   1538   // Check that elements are FixedArray.
   1539   // We rely on StoreIC_ArrayLength below to deal with all types of
   1540   // fast elements (including COW).
   1541   __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
   1542   __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
   1543   __ j(not_equal, &miss);
   1544 
   1545   // Check that value is a smi.
   1546   __ JumpIfNotSmi(value, &miss);
   1547 
   1548   // Prepare tail call to StoreIC_ArrayLength.
   1549   __ pop(scratch);
   1550   __ push(receiver);
   1551   __ push(value);
   1552   __ push(scratch);  // return address
   1553 
   1554   ExternalReference ref =
   1555       ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
   1556   __ TailCallExternalReference(ref, 2, 1);
   1557 
   1558   __ bind(&miss);
   1559 
   1560   GenerateMiss(masm);
   1561 }
   1562 
   1563 
   1564 void StoreIC::GenerateNormal(MacroAssembler* masm) {
   1565   // ----------- S t a t e -------------
   1566   //  -- rax    : value
   1567   //  -- rcx    : name
   1568   //  -- rdx    : receiver
   1569   //  -- rsp[0] : return address
   1570   // -----------------------------------
   1571 
   1572   Label miss;
   1573 
   1574   GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
   1575 
   1576   GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
   1577   Counters* counters = masm->isolate()->counters();
   1578   __ IncrementCounter(counters->store_normal_hit(), 1);
   1579   __ ret(0);
   1580 
   1581   __ bind(&miss);
   1582   __ IncrementCounter(counters->store_normal_miss(), 1);
   1583   GenerateMiss(masm);
   1584 }
   1585 
   1586 
   1587 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
   1588                                   StrictModeFlag strict_mode) {
   1589   // ----------- S t a t e -------------
   1590   //  -- rax    : value
   1591   //  -- rcx    : name
   1592   //  -- rdx    : receiver
   1593   //  -- rsp[0] : return address
   1594   // -----------------------------------
   1595   __ pop(rbx);
   1596   __ push(rdx);
   1597   __ push(rcx);
   1598   __ push(rax);
   1599   __ Push(Smi::FromInt(NONE));  // PropertyAttributes
   1600   __ Push(Smi::FromInt(strict_mode));
   1601   __ push(rbx);  // return address
   1602 
   1603   // Do tail-call to runtime routine.
   1604   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1605 }
   1606 
   1607 
   1608 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
   1609                                               StrictModeFlag strict_mode) {
   1610   // ----------- S t a t e -------------
   1611   //  -- rax     : value
   1612   //  -- rcx     : key
   1613   //  -- rdx     : receiver
   1614   //  -- rsp[0]  : return address
   1615   // -----------------------------------
   1616 
   1617   __ pop(rbx);
   1618   __ push(rdx);  // receiver
   1619   __ push(rcx);  // key
   1620   __ push(rax);  // value
   1621   __ Push(Smi::FromInt(NONE));          // PropertyAttributes
   1622   __ Push(Smi::FromInt(strict_mode));   // Strict mode.
   1623   __ push(rbx);  // return address
   1624 
   1625   // Do tail-call to runtime routine.
   1626   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
   1627 }
   1628 
   1629 
   1630 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   1631   // ----------- S t a t e -------------
   1632   //  -- rax     : value
   1633   //  -- rcx     : key
   1634   //  -- rdx     : receiver
   1635   //  -- rsp[0]  : return address
   1636   // -----------------------------------
   1637 
   1638   __ pop(rbx);
   1639   __ push(rdx);  // receiver
   1640   __ push(rcx);  // key
   1641   __ push(rax);  // value
   1642   __ push(rbx);  // return address
   1643 
   1644   // Do tail-call to runtime routine.
   1645   ExternalReference ref =
   1646       ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
   1647   __ TailCallExternalReference(ref, 3, 1);
   1648 }
   1649 
   1650 
   1651 #undef __
   1652 
   1653 
   1654 Condition CompareIC::ComputeCondition(Token::Value op) {
   1655   switch (op) {
   1656     case Token::EQ_STRICT:
   1657     case Token::EQ:
   1658       return equal;
   1659     case Token::LT:
   1660       return less;
   1661     case Token::GT:
   1662       // Reverse left and right operands to obtain ECMA-262 conversion order.
   1663       return less;
   1664     case Token::LTE:
   1665       // Reverse left and right operands to obtain ECMA-262 conversion order.
   1666       return greater_equal;
   1667     case Token::GTE:
   1668       return greater_equal;
   1669     default:
   1670       UNREACHABLE();
   1671       return no_condition;
   1672   }
   1673 }
   1674 
   1675 
   1676 static bool HasInlinedSmiCode(Address address) {
   1677   // The address of the instruction following the call.
   1678   Address test_instruction_address =
   1679       address + Assembler::kCallTargetAddressOffset;
   1680 
   1681   // If the instruction following the call is not a test al, nothing
   1682   // was inlined.
   1683   return *test_instruction_address == Assembler::kTestAlByte;
   1684 }
   1685 
   1686 
   1687 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
   1688   HandleScope scope;
   1689   Handle<Code> rewritten;
   1690   State previous_state = GetState();
   1691 
   1692   State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
   1693   if (state == GENERIC) {
   1694     CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
   1695     rewritten = stub.GetCode();
   1696   } else {
   1697     ICCompareStub stub(op_, state);
   1698     rewritten = stub.GetCode();
   1699   }
   1700   set_target(*rewritten);
   1701 
   1702 #ifdef DEBUG
   1703   if (FLAG_trace_ic) {
   1704     PrintF("[CompareIC (%s->%s)#%s]\n",
   1705            GetStateName(previous_state),
   1706            GetStateName(state),
   1707            Token::Name(op_));
   1708   }
   1709 #endif
   1710 
   1711   // Activate inlined smi code.
   1712   if (previous_state == UNINITIALIZED) {
   1713     PatchInlinedSmiCode(address());
   1714   }
   1715 }
   1716 
   1717 void PatchInlinedSmiCode(Address address) {
   1718   // The address of the instruction following the call.
   1719   Address test_instruction_address =
   1720       address + Assembler::kCallTargetAddressOffset;
   1721 
   1722   // If the instruction following the call is not a test al, nothing
   1723   // was inlined.
   1724   if (*test_instruction_address != Assembler::kTestAlByte) {
   1725     ASSERT(*test_instruction_address == Assembler::kNopByte);
   1726     return;
   1727   }
   1728 
   1729   Address delta_address = test_instruction_address + 1;
   1730   // The delta to the start of the map check instruction and the
   1731   // condition code uses at the patched jump.
   1732   int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
   1733   if (FLAG_trace_ic) {
   1734     PrintF("[  patching ic at %p, test=%p, delta=%d\n",
   1735            address, test_instruction_address, delta);
   1736   }
   1737 
   1738   // Patch with a short conditional jump. There must be a
   1739   // short jump-if-carry/not-carry at this position.
   1740   Address jmp_address = test_instruction_address - delta;
   1741   ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
   1742          *jmp_address == Assembler::kJcShortOpcode);
   1743   Condition cc = *jmp_address == Assembler::kJncShortOpcode
   1744       ? not_zero
   1745       : zero;
   1746   *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
   1747 }
   1748 
   1749 
   1750 } }  // namespace v8::internal
   1751 
   1752 #endif  // V8_TARGET_ARCH_X64
   1753