Home | History | Annotate | Download | only in mips64
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/mips64/codegen-mips64.h"
      6 
      7 #if V8_TARGET_ARCH_MIPS64
      8 
      9 #include "src/codegen.h"
     10 #include "src/macro-assembler.h"
     11 #include "src/mips64/simulator-mips64.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 
     17 #define __ masm.
     18 
     19 
     20 #if defined(USE_SIMULATOR)
     21 byte* fast_exp_mips_machine_code = nullptr;
     22 double fast_exp_simulator(double x, Isolate* isolate) {
     23   return Simulator::current(isolate)->CallFP(fast_exp_mips_machine_code, x, 0);
     24 }
     25 #endif
     26 
     27 
     28 UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
     29   size_t actual_size;
     30   byte* buffer =
     31       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
     32   if (buffer == nullptr) return nullptr;
     33   ExternalReference::InitializeMathExpData();
     34 
     35   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
     36                       CodeObjectRequired::kNo);
     37 
     38   {
     39     DoubleRegister input = f12;
     40     DoubleRegister result = f0;
     41     DoubleRegister double_scratch1 = f4;
     42     DoubleRegister double_scratch2 = f6;
     43     Register temp1 = a4;
     44     Register temp2 = a5;
     45     Register temp3 = a6;
     46 
     47     __ MovFromFloatParameter(input);
     48     __ Push(temp3, temp2, temp1);
     49     MathExpGenerator::EmitMathExp(
     50         &masm, input, result, double_scratch1, double_scratch2,
     51         temp1, temp2, temp3);
     52     __ Pop(temp3, temp2, temp1);
     53     __ MovToFloatResult(result);
     54     __ Ret();
     55   }
     56 
     57   CodeDesc desc;
     58   masm.GetCode(&desc);
     59   DCHECK(!RelocInfo::RequiresRelocation(desc));
     60 
     61   Assembler::FlushICache(isolate, buffer, actual_size);
     62   base::OS::ProtectCode(buffer, actual_size);
     63 
     64 #if !defined(USE_SIMULATOR)
     65   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
     66 #else
     67   fast_exp_mips_machine_code = buffer;
     68   return &fast_exp_simulator;
     69 #endif
     70 }
     71 
     72 
     73 #if defined(V8_HOST_ARCH_MIPS)
     74 MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
     75                                                 MemCopyUint8Function stub) {
     76 #if defined(USE_SIMULATOR)
     77   return stub;
     78 #else
     79 
     80   size_t actual_size;
     81   byte* buffer =
     82       static_cast<byte*>(base::OS::Allocate(3 * KB, &actual_size, true));
     83   if (buffer == nullptr) return stub;
     84 
     85   // This code assumes that cache lines are 32 bytes and if the cache line is
     86   // larger it will not work correctly.
     87   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
     88                       CodeObjectRequired::kNo);
     89 
     90   {
     91     Label lastb, unaligned, aligned, chkw,
     92           loop16w, chk1w, wordCopy_loop, skip_pref, lastbloop,
     93           leave, ua_chk16w, ua_loop16w, ua_skip_pref, ua_chkw,
     94           ua_chk1w, ua_wordCopy_loop, ua_smallCopy, ua_smallCopy_loop;
     95 
     96     // The size of each prefetch.
     97     uint32_t pref_chunk = 32;
     98     // The maximum size of a prefetch, it must not be less then pref_chunk.
     99     // If the real size of a prefetch is greater then max_pref_size and
    100     // the kPrefHintPrepareForStore hint is used, the code will not work
    101     // correctly.
    102     uint32_t max_pref_size = 128;
    103     DCHECK(pref_chunk < max_pref_size);
    104 
    105     // pref_limit is set based on the fact that we never use an offset
    106     // greater then 5 on a store pref and that a single pref can
    107     // never be larger then max_pref_size.
    108     uint32_t pref_limit = (5 * pref_chunk) + max_pref_size;
    109     int32_t pref_hint_load = kPrefHintLoadStreamed;
    110     int32_t pref_hint_store = kPrefHintPrepareForStore;
    111     uint32_t loadstore_chunk = 4;
    112 
    113     // The initial prefetches may fetch bytes that are before the buffer being
    114     // copied. Start copies with an offset of 4 so avoid this situation when
    115     // using kPrefHintPrepareForStore.
    116     DCHECK(pref_hint_store != kPrefHintPrepareForStore ||
    117            pref_chunk * 4 >= max_pref_size);
    118     // If the size is less than 8, go to lastb. Regardless of size,
    119     // copy dst pointer to v0 for the retuen value.
    120     __ slti(a6, a2, 2 * loadstore_chunk);
    121     __ bne(a6, zero_reg, &lastb);
    122     __ mov(v0, a0);  // In delay slot.
    123 
    124     // If src and dst have different alignments, go to unaligned, if they
    125     // have the same alignment (but are not actually aligned) do a partial
    126     // load/store to make them aligned. If they are both already aligned
    127     // we can start copying at aligned.
    128     __ xor_(t8, a1, a0);
    129     __ andi(t8, t8, loadstore_chunk - 1);  // t8 is a0/a1 word-displacement.
    130     __ bne(t8, zero_reg, &unaligned);
    131     __ subu(a3, zero_reg, a0);  // In delay slot.
    132 
    133     __ andi(a3, a3, loadstore_chunk - 1);  // Copy a3 bytes to align a0/a1.
    134     __ beq(a3, zero_reg, &aligned);  // Already aligned.
    135     __ subu(a2, a2, a3);  // In delay slot. a2 is the remining bytes count.
    136 
    137     if (kArchEndian == kLittle) {
    138       __ lwr(t8, MemOperand(a1));
    139       __ addu(a1, a1, a3);
    140       __ swr(t8, MemOperand(a0));
    141       __ addu(a0, a0, a3);
    142     } else {
    143       __ lwl(t8, MemOperand(a1));
    144       __ addu(a1, a1, a3);
    145       __ swl(t8, MemOperand(a0));
    146       __ addu(a0, a0, a3);
    147     }
    148 
    149     // Now dst/src are both aligned to (word) aligned addresses. Set a2 to
    150     // count how many bytes we have to copy after all the 64 byte chunks are
    151     // copied and a3 to the dst pointer after all the 64 byte chunks have been
    152     // copied. We will loop, incrementing a0 and a1 until a0 equals a3.
    153     __ bind(&aligned);
    154     __ andi(t8, a2, 0x3f);
    155     __ beq(a2, t8, &chkw);  // Less than 64?
    156     __ subu(a3, a2, t8);  // In delay slot.
    157     __ addu(a3, a0, a3);  // Now a3 is the final dst after loop.
    158 
    159     // When in the loop we prefetch with kPrefHintPrepareForStore hint,
    160     // in this case the a0+x should be past the "a4-32" address. This means:
    161     // for x=128 the last "safe" a0 address is "a4-160". Alternatively, for
    162     // x=64 the last "safe" a0 address is "a4-96". In the current version we
    163     // will use "pref hint, 128(a0)", so "a4-160" is the limit.
    164     if (pref_hint_store == kPrefHintPrepareForStore) {
    165       __ addu(a4, a0, a2);  // a4 is the "past the end" address.
    166       __ Subu(t9, a4, pref_limit);  // t9 is the "last safe pref" address.
    167     }
    168 
    169     __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk));
    170     __ Pref(pref_hint_load, MemOperand(a1, 1 * pref_chunk));
    171     __ Pref(pref_hint_load, MemOperand(a1, 2 * pref_chunk));
    172     __ Pref(pref_hint_load, MemOperand(a1, 3 * pref_chunk));
    173 
    174     if (pref_hint_store != kPrefHintPrepareForStore) {
    175       __ Pref(pref_hint_store, MemOperand(a0, 1 * pref_chunk));
    176       __ Pref(pref_hint_store, MemOperand(a0, 2 * pref_chunk));
    177       __ Pref(pref_hint_store, MemOperand(a0, 3 * pref_chunk));
    178     }
    179     __ bind(&loop16w);
    180     __ lw(a4, MemOperand(a1));
    181 
    182     if (pref_hint_store == kPrefHintPrepareForStore) {
    183       __ sltu(v1, t9, a0);  // If a0 > t9, don't use next prefetch.
    184       __ Branch(USE_DELAY_SLOT, &skip_pref, gt, v1, Operand(zero_reg));
    185     }
    186     __ lw(a5, MemOperand(a1, 1, loadstore_chunk));  // Maybe in delay slot.
    187 
    188     __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk));
    189     __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk));
    190 
    191     __ bind(&skip_pref);
    192     __ lw(a6, MemOperand(a1, 2, loadstore_chunk));
    193     __ lw(a7, MemOperand(a1, 3, loadstore_chunk));
    194     __ lw(t0, MemOperand(a1, 4, loadstore_chunk));
    195     __ lw(t1, MemOperand(a1, 5, loadstore_chunk));
    196     __ lw(t2, MemOperand(a1, 6, loadstore_chunk));
    197     __ lw(t3, MemOperand(a1, 7, loadstore_chunk));
    198     __ Pref(pref_hint_load, MemOperand(a1, 4 * pref_chunk));
    199 
    200     __ sw(a4, MemOperand(a0));
    201     __ sw(a5, MemOperand(a0, 1, loadstore_chunk));
    202     __ sw(a6, MemOperand(a0, 2, loadstore_chunk));
    203     __ sw(a7, MemOperand(a0, 3, loadstore_chunk));
    204     __ sw(t0, MemOperand(a0, 4, loadstore_chunk));
    205     __ sw(t1, MemOperand(a0, 5, loadstore_chunk));
    206     __ sw(t2, MemOperand(a0, 6, loadstore_chunk));
    207     __ sw(t3, MemOperand(a0, 7, loadstore_chunk));
    208 
    209     __ lw(a4, MemOperand(a1, 8, loadstore_chunk));
    210     __ lw(a5, MemOperand(a1, 9, loadstore_chunk));
    211     __ lw(a6, MemOperand(a1, 10, loadstore_chunk));
    212     __ lw(a7, MemOperand(a1, 11, loadstore_chunk));
    213     __ lw(t0, MemOperand(a1, 12, loadstore_chunk));
    214     __ lw(t1, MemOperand(a1, 13, loadstore_chunk));
    215     __ lw(t2, MemOperand(a1, 14, loadstore_chunk));
    216     __ lw(t3, MemOperand(a1, 15, loadstore_chunk));
    217     __ Pref(pref_hint_load, MemOperand(a1, 5 * pref_chunk));
    218 
    219     __ sw(a4, MemOperand(a0, 8, loadstore_chunk));
    220     __ sw(a5, MemOperand(a0, 9, loadstore_chunk));
    221     __ sw(a6, MemOperand(a0, 10, loadstore_chunk));
    222     __ sw(a7, MemOperand(a0, 11, loadstore_chunk));
    223     __ sw(t0, MemOperand(a0, 12, loadstore_chunk));
    224     __ sw(t1, MemOperand(a0, 13, loadstore_chunk));
    225     __ sw(t2, MemOperand(a0, 14, loadstore_chunk));
    226     __ sw(t3, MemOperand(a0, 15, loadstore_chunk));
    227     __ addiu(a0, a0, 16 * loadstore_chunk);
    228     __ bne(a0, a3, &loop16w);
    229     __ addiu(a1, a1, 16 * loadstore_chunk);  // In delay slot.
    230     __ mov(a2, t8);
    231 
    232     // Here we have src and dest word-aligned but less than 64-bytes to go.
    233     // Check for a 32 bytes chunk and copy if there is one. Otherwise jump
    234     // down to chk1w to handle the tail end of the copy.
    235     __ bind(&chkw);
    236     __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk));
    237     __ andi(t8, a2, 0x1f);
    238     __ beq(a2, t8, &chk1w);  // Less than 32?
    239     __ nop();  // In delay slot.
    240     __ lw(a4, MemOperand(a1));
    241     __ lw(a5, MemOperand(a1, 1, loadstore_chunk));
    242     __ lw(a6, MemOperand(a1, 2, loadstore_chunk));
    243     __ lw(a7, MemOperand(a1, 3, loadstore_chunk));
    244     __ lw(t0, MemOperand(a1, 4, loadstore_chunk));
    245     __ lw(t1, MemOperand(a1, 5, loadstore_chunk));
    246     __ lw(t2, MemOperand(a1, 6, loadstore_chunk));
    247     __ lw(t3, MemOperand(a1, 7, loadstore_chunk));
    248     __ addiu(a1, a1, 8 * loadstore_chunk);
    249     __ sw(a4, MemOperand(a0));
    250     __ sw(a5, MemOperand(a0, 1, loadstore_chunk));
    251     __ sw(a6, MemOperand(a0, 2, loadstore_chunk));
    252     __ sw(a7, MemOperand(a0, 3, loadstore_chunk));
    253     __ sw(t0, MemOperand(a0, 4, loadstore_chunk));
    254     __ sw(t1, MemOperand(a0, 5, loadstore_chunk));
    255     __ sw(t2, MemOperand(a0, 6, loadstore_chunk));
    256     __ sw(t3, MemOperand(a0, 7, loadstore_chunk));
    257     __ addiu(a0, a0, 8 * loadstore_chunk);
    258 
    259     // Here we have less than 32 bytes to copy. Set up for a loop to copy
    260     // one word at a time. Set a2 to count how many bytes we have to copy
    261     // after all the word chunks are copied and a3 to the dst pointer after
    262     // all the word chunks have been copied. We will loop, incrementing a0
    263     // and a1 untill a0 equals a3.
    264     __ bind(&chk1w);
    265     __ andi(a2, t8, loadstore_chunk - 1);
    266     __ beq(a2, t8, &lastb);
    267     __ subu(a3, t8, a2);  // In delay slot.
    268     __ addu(a3, a0, a3);
    269 
    270     __ bind(&wordCopy_loop);
    271     __ lw(a7, MemOperand(a1));
    272     __ addiu(a0, a0, loadstore_chunk);
    273     __ addiu(a1, a1, loadstore_chunk);
    274     __ bne(a0, a3, &wordCopy_loop);
    275     __ sw(a7, MemOperand(a0, -1, loadstore_chunk));  // In delay slot.
    276 
    277     __ bind(&lastb);
    278     __ Branch(&leave, le, a2, Operand(zero_reg));
    279     __ addu(a3, a0, a2);
    280 
    281     __ bind(&lastbloop);
    282     __ lb(v1, MemOperand(a1));
    283     __ addiu(a0, a0, 1);
    284     __ addiu(a1, a1, 1);
    285     __ bne(a0, a3, &lastbloop);
    286     __ sb(v1, MemOperand(a0, -1));  // In delay slot.
    287 
    288     __ bind(&leave);
    289     __ jr(ra);
    290     __ nop();
    291 
    292     // Unaligned case. Only the dst gets aligned so we need to do partial
    293     // loads of the source followed by normal stores to the dst (once we
    294     // have aligned the destination).
    295     __ bind(&unaligned);
    296     __ andi(a3, a3, loadstore_chunk - 1);  // Copy a3 bytes to align a0/a1.
    297     __ beq(a3, zero_reg, &ua_chk16w);
    298     __ subu(a2, a2, a3);  // In delay slot.
    299 
    300     if (kArchEndian == kLittle) {
    301       __ lwr(v1, MemOperand(a1));
    302       __ lwl(v1,
    303              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    304       __ addu(a1, a1, a3);
    305       __ swr(v1, MemOperand(a0));
    306       __ addu(a0, a0, a3);
    307     } else {
    308       __ lwl(v1, MemOperand(a1));
    309       __ lwr(v1,
    310              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    311       __ addu(a1, a1, a3);
    312       __ swl(v1, MemOperand(a0));
    313       __ addu(a0, a0, a3);
    314     }
    315 
    316     // Now the dst (but not the source) is aligned. Set a2 to count how many
    317     // bytes we have to copy after all the 64 byte chunks are copied and a3 to
    318     // the dst pointer after all the 64 byte chunks have been copied. We will
    319     // loop, incrementing a0 and a1 until a0 equals a3.
    320     __ bind(&ua_chk16w);
    321     __ andi(t8, a2, 0x3f);
    322     __ beq(a2, t8, &ua_chkw);
    323     __ subu(a3, a2, t8);  // In delay slot.
    324     __ addu(a3, a0, a3);
    325 
    326     if (pref_hint_store == kPrefHintPrepareForStore) {
    327       __ addu(a4, a0, a2);
    328       __ Subu(t9, a4, pref_limit);
    329     }
    330 
    331     __ Pref(pref_hint_load, MemOperand(a1, 0 * pref_chunk));
    332     __ Pref(pref_hint_load, MemOperand(a1, 1 * pref_chunk));
    333     __ Pref(pref_hint_load, MemOperand(a1, 2 * pref_chunk));
    334 
    335     if (pref_hint_store != kPrefHintPrepareForStore) {
    336       __ Pref(pref_hint_store, MemOperand(a0, 1 * pref_chunk));
    337       __ Pref(pref_hint_store, MemOperand(a0, 2 * pref_chunk));
    338       __ Pref(pref_hint_store, MemOperand(a0, 3 * pref_chunk));
    339     }
    340 
    341     __ bind(&ua_loop16w);
    342     if (kArchEndian == kLittle) {
    343       __ Pref(pref_hint_load, MemOperand(a1, 3 * pref_chunk));
    344       __ lwr(a4, MemOperand(a1));
    345       __ lwr(a5, MemOperand(a1, 1, loadstore_chunk));
    346       __ lwr(a6, MemOperand(a1, 2, loadstore_chunk));
    347 
    348       if (pref_hint_store == kPrefHintPrepareForStore) {
    349         __ sltu(v1, t9, a0);
    350         __ Branch(USE_DELAY_SLOT, &ua_skip_pref, gt, v1, Operand(zero_reg));
    351       }
    352       __ lwr(a7, MemOperand(a1, 3, loadstore_chunk));  // Maybe in delay slot.
    353 
    354       __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk));
    355       __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk));
    356 
    357       __ bind(&ua_skip_pref);
    358       __ lwr(t0, MemOperand(a1, 4, loadstore_chunk));
    359       __ lwr(t1, MemOperand(a1, 5, loadstore_chunk));
    360       __ lwr(t2, MemOperand(a1, 6, loadstore_chunk));
    361       __ lwr(t3, MemOperand(a1, 7, loadstore_chunk));
    362       __ lwl(a4,
    363              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    364       __ lwl(a5,
    365              MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one));
    366       __ lwl(a6,
    367              MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one));
    368       __ lwl(a7,
    369              MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one));
    370       __ lwl(t0,
    371              MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one));
    372       __ lwl(t1,
    373              MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one));
    374       __ lwl(t2,
    375              MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one));
    376       __ lwl(t3,
    377              MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one));
    378     } else {
    379       __ Pref(pref_hint_load, MemOperand(a1, 3 * pref_chunk));
    380       __ lwl(a4, MemOperand(a1));
    381       __ lwl(a5, MemOperand(a1, 1, loadstore_chunk));
    382       __ lwl(a6, MemOperand(a1, 2, loadstore_chunk));
    383 
    384       if (pref_hint_store == kPrefHintPrepareForStore) {
    385         __ sltu(v1, t9, a0);
    386         __ Branch(USE_DELAY_SLOT, &ua_skip_pref, gt, v1, Operand(zero_reg));
    387       }
    388       __ lwl(a7, MemOperand(a1, 3, loadstore_chunk));  // Maybe in delay slot.
    389 
    390       __ Pref(pref_hint_store, MemOperand(a0, 4 * pref_chunk));
    391       __ Pref(pref_hint_store, MemOperand(a0, 5 * pref_chunk));
    392 
    393       __ bind(&ua_skip_pref);
    394       __ lwl(t0, MemOperand(a1, 4, loadstore_chunk));
    395       __ lwl(t1, MemOperand(a1, 5, loadstore_chunk));
    396       __ lwl(t2, MemOperand(a1, 6, loadstore_chunk));
    397       __ lwl(t3, MemOperand(a1, 7, loadstore_chunk));
    398       __ lwr(a4,
    399              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    400       __ lwr(a5,
    401              MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one));
    402       __ lwr(a6,
    403              MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one));
    404       __ lwr(a7,
    405              MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one));
    406       __ lwr(t0,
    407              MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one));
    408       __ lwr(t1,
    409              MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one));
    410       __ lwr(t2,
    411              MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one));
    412       __ lwr(t3,
    413              MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one));
    414     }
    415     __ Pref(pref_hint_load, MemOperand(a1, 4 * pref_chunk));
    416     __ sw(a4, MemOperand(a0));
    417     __ sw(a5, MemOperand(a0, 1, loadstore_chunk));
    418     __ sw(a6, MemOperand(a0, 2, loadstore_chunk));
    419     __ sw(a7, MemOperand(a0, 3, loadstore_chunk));
    420     __ sw(t0, MemOperand(a0, 4, loadstore_chunk));
    421     __ sw(t1, MemOperand(a0, 5, loadstore_chunk));
    422     __ sw(t2, MemOperand(a0, 6, loadstore_chunk));
    423     __ sw(t3, MemOperand(a0, 7, loadstore_chunk));
    424     if (kArchEndian == kLittle) {
    425       __ lwr(a4, MemOperand(a1, 8, loadstore_chunk));
    426       __ lwr(a5, MemOperand(a1, 9, loadstore_chunk));
    427       __ lwr(a6, MemOperand(a1, 10, loadstore_chunk));
    428       __ lwr(a7, MemOperand(a1, 11, loadstore_chunk));
    429       __ lwr(t0, MemOperand(a1, 12, loadstore_chunk));
    430       __ lwr(t1, MemOperand(a1, 13, loadstore_chunk));
    431       __ lwr(t2, MemOperand(a1, 14, loadstore_chunk));
    432       __ lwr(t3, MemOperand(a1, 15, loadstore_chunk));
    433       __ lwl(a4,
    434              MemOperand(a1, 9, loadstore_chunk, MemOperand::offset_minus_one));
    435       __ lwl(a5,
    436              MemOperand(a1, 10, loadstore_chunk, MemOperand::offset_minus_one));
    437       __ lwl(a6,
    438              MemOperand(a1, 11, loadstore_chunk, MemOperand::offset_minus_one));
    439       __ lwl(a7,
    440              MemOperand(a1, 12, loadstore_chunk, MemOperand::offset_minus_one));
    441       __ lwl(t0,
    442              MemOperand(a1, 13, loadstore_chunk, MemOperand::offset_minus_one));
    443       __ lwl(t1,
    444              MemOperand(a1, 14, loadstore_chunk, MemOperand::offset_minus_one));
    445       __ lwl(t2,
    446              MemOperand(a1, 15, loadstore_chunk, MemOperand::offset_minus_one));
    447       __ lwl(t3,
    448              MemOperand(a1, 16, loadstore_chunk, MemOperand::offset_minus_one));
    449     } else {
    450       __ lwl(a4, MemOperand(a1, 8, loadstore_chunk));
    451       __ lwl(a5, MemOperand(a1, 9, loadstore_chunk));
    452       __ lwl(a6, MemOperand(a1, 10, loadstore_chunk));
    453       __ lwl(a7, MemOperand(a1, 11, loadstore_chunk));
    454       __ lwl(t0, MemOperand(a1, 12, loadstore_chunk));
    455       __ lwl(t1, MemOperand(a1, 13, loadstore_chunk));
    456       __ lwl(t2, MemOperand(a1, 14, loadstore_chunk));
    457       __ lwl(t3, MemOperand(a1, 15, loadstore_chunk));
    458       __ lwr(a4,
    459              MemOperand(a1, 9, loadstore_chunk, MemOperand::offset_minus_one));
    460       __ lwr(a5,
    461              MemOperand(a1, 10, loadstore_chunk, MemOperand::offset_minus_one));
    462       __ lwr(a6,
    463              MemOperand(a1, 11, loadstore_chunk, MemOperand::offset_minus_one));
    464       __ lwr(a7,
    465              MemOperand(a1, 12, loadstore_chunk, MemOperand::offset_minus_one));
    466       __ lwr(t0,
    467              MemOperand(a1, 13, loadstore_chunk, MemOperand::offset_minus_one));
    468       __ lwr(t1,
    469              MemOperand(a1, 14, loadstore_chunk, MemOperand::offset_minus_one));
    470       __ lwr(t2,
    471              MemOperand(a1, 15, loadstore_chunk, MemOperand::offset_minus_one));
    472       __ lwr(t3,
    473              MemOperand(a1, 16, loadstore_chunk, MemOperand::offset_minus_one));
    474     }
    475     __ Pref(pref_hint_load, MemOperand(a1, 5 * pref_chunk));
    476     __ sw(a4, MemOperand(a0, 8, loadstore_chunk));
    477     __ sw(a5, MemOperand(a0, 9, loadstore_chunk));
    478     __ sw(a6, MemOperand(a0, 10, loadstore_chunk));
    479     __ sw(a7, MemOperand(a0, 11, loadstore_chunk));
    480     __ sw(t0, MemOperand(a0, 12, loadstore_chunk));
    481     __ sw(t1, MemOperand(a0, 13, loadstore_chunk));
    482     __ sw(t2, MemOperand(a0, 14, loadstore_chunk));
    483     __ sw(t3, MemOperand(a0, 15, loadstore_chunk));
    484     __ addiu(a0, a0, 16 * loadstore_chunk);
    485     __ bne(a0, a3, &ua_loop16w);
    486     __ addiu(a1, a1, 16 * loadstore_chunk);  // In delay slot.
    487     __ mov(a2, t8);
    488 
    489     // Here less than 64-bytes. Check for
    490     // a 32 byte chunk and copy if there is one. Otherwise jump down to
    491     // ua_chk1w to handle the tail end of the copy.
    492     __ bind(&ua_chkw);
    493     __ Pref(pref_hint_load, MemOperand(a1));
    494     __ andi(t8, a2, 0x1f);
    495 
    496     __ beq(a2, t8, &ua_chk1w);
    497     __ nop();  // In delay slot.
    498     if (kArchEndian == kLittle) {
    499       __ lwr(a4, MemOperand(a1));
    500       __ lwr(a5, MemOperand(a1, 1, loadstore_chunk));
    501       __ lwr(a6, MemOperand(a1, 2, loadstore_chunk));
    502       __ lwr(a7, MemOperand(a1, 3, loadstore_chunk));
    503       __ lwr(t0, MemOperand(a1, 4, loadstore_chunk));
    504       __ lwr(t1, MemOperand(a1, 5, loadstore_chunk));
    505       __ lwr(t2, MemOperand(a1, 6, loadstore_chunk));
    506       __ lwr(t3, MemOperand(a1, 7, loadstore_chunk));
    507       __ lwl(a4,
    508              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    509       __ lwl(a5,
    510              MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one));
    511       __ lwl(a6,
    512              MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one));
    513       __ lwl(a7,
    514              MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one));
    515       __ lwl(t0,
    516              MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one));
    517       __ lwl(t1,
    518              MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one));
    519       __ lwl(t2,
    520              MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one));
    521       __ lwl(t3,
    522              MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one));
    523     } else {
    524       __ lwl(a4, MemOperand(a1));
    525       __ lwl(a5, MemOperand(a1, 1, loadstore_chunk));
    526       __ lwl(a6, MemOperand(a1, 2, loadstore_chunk));
    527       __ lwl(a7, MemOperand(a1, 3, loadstore_chunk));
    528       __ lwl(t0, MemOperand(a1, 4, loadstore_chunk));
    529       __ lwl(t1, MemOperand(a1, 5, loadstore_chunk));
    530       __ lwl(t2, MemOperand(a1, 6, loadstore_chunk));
    531       __ lwl(t3, MemOperand(a1, 7, loadstore_chunk));
    532       __ lwr(a4,
    533              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    534       __ lwr(a5,
    535              MemOperand(a1, 2, loadstore_chunk, MemOperand::offset_minus_one));
    536       __ lwr(a6,
    537              MemOperand(a1, 3, loadstore_chunk, MemOperand::offset_minus_one));
    538       __ lwr(a7,
    539              MemOperand(a1, 4, loadstore_chunk, MemOperand::offset_minus_one));
    540       __ lwr(t0,
    541              MemOperand(a1, 5, loadstore_chunk, MemOperand::offset_minus_one));
    542       __ lwr(t1,
    543              MemOperand(a1, 6, loadstore_chunk, MemOperand::offset_minus_one));
    544       __ lwr(t2,
    545              MemOperand(a1, 7, loadstore_chunk, MemOperand::offset_minus_one));
    546       __ lwr(t3,
    547              MemOperand(a1, 8, loadstore_chunk, MemOperand::offset_minus_one));
    548     }
    549     __ addiu(a1, a1, 8 * loadstore_chunk);
    550     __ sw(a4, MemOperand(a0));
    551     __ sw(a5, MemOperand(a0, 1, loadstore_chunk));
    552     __ sw(a6, MemOperand(a0, 2, loadstore_chunk));
    553     __ sw(a7, MemOperand(a0, 3, loadstore_chunk));
    554     __ sw(t0, MemOperand(a0, 4, loadstore_chunk));
    555     __ sw(t1, MemOperand(a0, 5, loadstore_chunk));
    556     __ sw(t2, MemOperand(a0, 6, loadstore_chunk));
    557     __ sw(t3, MemOperand(a0, 7, loadstore_chunk));
    558     __ addiu(a0, a0, 8 * loadstore_chunk);
    559 
    560     // Less than 32 bytes to copy. Set up for a loop to
    561     // copy one word at a time.
    562     __ bind(&ua_chk1w);
    563     __ andi(a2, t8, loadstore_chunk - 1);
    564     __ beq(a2, t8, &ua_smallCopy);
    565     __ subu(a3, t8, a2);  // In delay slot.
    566     __ addu(a3, a0, a3);
    567 
    568     __ bind(&ua_wordCopy_loop);
    569     if (kArchEndian == kLittle) {
    570       __ lwr(v1, MemOperand(a1));
    571       __ lwl(v1,
    572              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    573     } else {
    574       __ lwl(v1, MemOperand(a1));
    575       __ lwr(v1,
    576              MemOperand(a1, 1, loadstore_chunk, MemOperand::offset_minus_one));
    577     }
    578     __ addiu(a0, a0, loadstore_chunk);
    579     __ addiu(a1, a1, loadstore_chunk);
    580     __ bne(a0, a3, &ua_wordCopy_loop);
    581     __ sw(v1, MemOperand(a0, -1, loadstore_chunk));  // In delay slot.
    582 
    583     // Copy the last 8 bytes.
    584     __ bind(&ua_smallCopy);
    585     __ beq(a2, zero_reg, &leave);
    586     __ addu(a3, a0, a2);  // In delay slot.
    587 
    588     __ bind(&ua_smallCopy_loop);
    589     __ lb(v1, MemOperand(a1));
    590     __ addiu(a0, a0, 1);
    591     __ addiu(a1, a1, 1);
    592     __ bne(a0, a3, &ua_smallCopy_loop);
    593     __ sb(v1, MemOperand(a0, -1));  // In delay slot.
    594 
    595     __ jr(ra);
    596     __ nop();
    597   }
    598   CodeDesc desc;
    599   masm.GetCode(&desc);
    600   DCHECK(!RelocInfo::RequiresRelocation(desc));
    601 
    602   Assembler::FlushICache(isolate, buffer, actual_size);
    603   base::OS::ProtectCode(buffer, actual_size);
    604   return FUNCTION_CAST<MemCopyUint8Function>(buffer);
    605 #endif
    606 }
    607 #endif
    608 
    609 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
    610 #if defined(USE_SIMULATOR)
    611   return nullptr;
    612 #else
    613   size_t actual_size;
    614   byte* buffer =
    615       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
    616   if (buffer == nullptr) return nullptr;
    617 
    618   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
    619                       CodeObjectRequired::kNo);
    620 
    621   __ MovFromFloatParameter(f12);
    622   __ sqrt_d(f0, f12);
    623   __ MovToFloatResult(f0);
    624   __ Ret();
    625 
    626   CodeDesc desc;
    627   masm.GetCode(&desc);
    628   DCHECK(!RelocInfo::RequiresRelocation(desc));
    629 
    630   Assembler::FlushICache(isolate, buffer, actual_size);
    631   base::OS::ProtectCode(buffer, actual_size);
    632   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
    633 #endif
    634 }
    635 
    636 #undef __
    637 
    638 
    639 // -------------------------------------------------------------------------
    640 // Platform-specific RuntimeCallHelper functions.
    641 
    642 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
    643   masm->EnterFrame(StackFrame::INTERNAL);
    644   DCHECK(!masm->has_frame());
    645   masm->set_has_frame(true);
    646 }
    647 
    648 
    649 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
    650   masm->LeaveFrame(StackFrame::INTERNAL);
    651   DCHECK(masm->has_frame());
    652   masm->set_has_frame(false);
    653 }
    654 
    655 
    656 // -------------------------------------------------------------------------
    657 // Code generators
    658 
    659 #define __ ACCESS_MASM(masm)
    660 
    661 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
    662     MacroAssembler* masm,
    663     Register receiver,
    664     Register key,
    665     Register value,
    666     Register target_map,
    667     AllocationSiteMode mode,
    668     Label* allocation_memento_found) {
    669   Register scratch_elements = a4;
    670   DCHECK(!AreAliased(receiver, key, value, target_map,
    671                      scratch_elements));
    672 
    673   if (mode == TRACK_ALLOCATION_SITE) {
    674     __ JumpIfJSArrayHasAllocationMemento(
    675         receiver, scratch_elements, allocation_memento_found);
    676   }
    677 
    678   // Set transitioned map.
    679   __ sd(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    680   __ RecordWriteField(receiver,
    681                       HeapObject::kMapOffset,
    682                       target_map,
    683                       t1,
    684                       kRAHasNotBeenSaved,
    685                       kDontSaveFPRegs,
    686                       EMIT_REMEMBERED_SET,
    687                       OMIT_SMI_CHECK);
    688 }
    689 
    690 
    691 void ElementsTransitionGenerator::GenerateSmiToDouble(
    692     MacroAssembler* masm,
    693     Register receiver,
    694     Register key,
    695     Register value,
    696     Register target_map,
    697     AllocationSiteMode mode,
    698     Label* fail) {
    699   // Register ra contains the return address.
    700   Label loop, entry, convert_hole, gc_required, only_change_map, done;
    701   Register elements = a4;
    702   Register length = a5;
    703   Register array = a6;
    704   Register array_end = array;
    705 
    706   // target_map parameter can be clobbered.
    707   Register scratch1 = target_map;
    708   Register scratch2 = t1;
    709   Register scratch3 = a7;
    710 
    711   // Verify input registers don't conflict with locals.
    712   DCHECK(!AreAliased(receiver, key, value, target_map,
    713                      elements, length, array, scratch2));
    714 
    715   Register scratch = t2;
    716   if (mode == TRACK_ALLOCATION_SITE) {
    717     __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
    718   }
    719 
    720   // Check for empty arrays, which only require a map transition and no changes
    721   // to the backing store.
    722   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    723   __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
    724   __ Branch(&only_change_map, eq, at, Operand(elements));
    725 
    726   __ push(ra);
    727   __ ld(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
    728   // elements: source FixedArray
    729   // length: number of elements (smi-tagged)
    730 
    731   // Allocate new FixedDoubleArray.
    732   __ SmiScale(scratch, length, kDoubleSizeLog2);
    733   __ Daddu(scratch, scratch, FixedDoubleArray::kHeaderSize);
    734   __ Allocate(scratch, array, t3, scratch2, &gc_required, DOUBLE_ALIGNMENT);
    735   // array: destination FixedDoubleArray, not tagged as heap object
    736 
    737   // Set destination FixedDoubleArray's length and map.
    738   __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex);
    739   __ sd(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
    740   // Update receiver's map.
    741   __ sd(scratch2, MemOperand(array, HeapObject::kMapOffset));
    742 
    743   __ sd(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    744   __ RecordWriteField(receiver,
    745                       HeapObject::kMapOffset,
    746                       target_map,
    747                       scratch2,
    748                       kRAHasBeenSaved,
    749                       kDontSaveFPRegs,
    750                       OMIT_REMEMBERED_SET,
    751                       OMIT_SMI_CHECK);
    752   // Replace receiver's backing store with newly created FixedDoubleArray.
    753   __ Daddu(scratch1, array, Operand(kHeapObjectTag));
    754   __ sd(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset));
    755   __ RecordWriteField(receiver,
    756                       JSObject::kElementsOffset,
    757                       scratch1,
    758                       scratch2,
    759                       kRAHasBeenSaved,
    760                       kDontSaveFPRegs,
    761                       EMIT_REMEMBERED_SET,
    762                       OMIT_SMI_CHECK);
    763 
    764 
    765   // Prepare for conversion loop.
    766   __ Daddu(scratch1, elements,
    767       Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    768   __ Daddu(scratch3, array, Operand(FixedDoubleArray::kHeaderSize));
    769   __ SmiScale(array_end, length, kDoubleSizeLog2);
    770   __ Daddu(array_end, array_end, scratch3);
    771 
    772   // Repurpose registers no longer in use.
    773   Register hole_lower = elements;
    774   Register hole_upper = length;
    775   __ li(hole_lower, Operand(kHoleNanLower32));
    776   __ li(hole_upper, Operand(kHoleNanUpper32));
    777 
    778   // scratch1: begin of source FixedArray element fields, not tagged
    779   // hole_lower: kHoleNanLower32
    780   // hole_upper: kHoleNanUpper32
    781   // array_end: end of destination FixedDoubleArray, not tagged
    782   // scratch3: begin of FixedDoubleArray element fields, not tagged
    783 
    784   __ Branch(&entry);
    785 
    786   __ bind(&only_change_map);
    787   __ sd(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    788   __ RecordWriteField(receiver,
    789                       HeapObject::kMapOffset,
    790                       target_map,
    791                       scratch2,
    792                       kRAHasBeenSaved,
    793                       kDontSaveFPRegs,
    794                       OMIT_REMEMBERED_SET,
    795                       OMIT_SMI_CHECK);
    796   __ Branch(&done);
    797 
    798   // Call into runtime if GC is required.
    799   __ bind(&gc_required);
    800   __ ld(ra, MemOperand(sp, 0));
    801   __ Branch(USE_DELAY_SLOT, fail);
    802   __ daddiu(sp, sp, kPointerSize);  // In delay slot.
    803 
    804   // Convert and copy elements.
    805   __ bind(&loop);
    806   __ ld(scratch2, MemOperand(scratch1));
    807   __ Daddu(scratch1, scratch1, kPointerSize);
    808   // scratch2: current element
    809   __ JumpIfNotSmi(scratch2, &convert_hole);
    810   __ SmiUntag(scratch2);
    811 
    812   // Normal smi, convert to double and store.
    813   __ mtc1(scratch2, f0);
    814   __ cvt_d_w(f0, f0);
    815   __ sdc1(f0, MemOperand(scratch3));
    816   __ Branch(USE_DELAY_SLOT, &entry);
    817   __ daddiu(scratch3, scratch3, kDoubleSize);  // In delay slot.
    818 
    819   // Hole found, store the-hole NaN.
    820   __ bind(&convert_hole);
    821   if (FLAG_debug_code) {
    822     // Restore a "smi-untagged" heap object.
    823     __ Or(scratch2, scratch2, Operand(1));
    824     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
    825     __ Assert(eq, kObjectFoundInSmiOnlyArray, at, Operand(scratch2));
    826   }
    827   // mantissa
    828   __ sw(hole_lower, MemOperand(scratch3, Register::kMantissaOffset));
    829   // exponent
    830   __ sw(hole_upper, MemOperand(scratch3, Register::kExponentOffset));
    831   __ Daddu(scratch3, scratch3, kDoubleSize);
    832 
    833   __ bind(&entry);
    834   __ Branch(&loop, lt, scratch3, Operand(array_end));
    835 
    836   __ bind(&done);
    837   __ pop(ra);
    838 }
    839 
    840 
    841 void ElementsTransitionGenerator::GenerateDoubleToObject(
    842     MacroAssembler* masm,
    843     Register receiver,
    844     Register key,
    845     Register value,
    846     Register target_map,
    847     AllocationSiteMode mode,
    848     Label* fail) {
    849   // Register ra contains the return address.
    850   Label entry, loop, convert_hole, gc_required, only_change_map;
    851   Register elements = a4;
    852   Register array = a6;
    853   Register length = a5;
    854   Register scratch = t1;
    855 
    856   // Verify input registers don't conflict with locals.
    857   DCHECK(!AreAliased(receiver, key, value, target_map,
    858                      elements, array, length, scratch));
    859   if (mode == TRACK_ALLOCATION_SITE) {
    860     __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail);
    861   }
    862 
    863   // Check for empty arrays, which only require a map transition and no changes
    864   // to the backing store.
    865   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
    866   __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
    867   __ Branch(&only_change_map, eq, at, Operand(elements));
    868 
    869   __ MultiPush(
    870       value.bit() | key.bit() | receiver.bit() | target_map.bit() | ra.bit());
    871 
    872   __ ld(length, FieldMemOperand(elements, FixedArray::kLengthOffset));
    873   // elements: source FixedArray
    874   // length: number of elements (smi-tagged)
    875 
    876   // Allocate new FixedArray.
    877   // Re-use value and target_map registers, as they have been saved on the
    878   // stack.
    879   Register array_size = value;
    880   Register allocate_scratch = target_map;
    881   __ SmiScale(array_size, length, kPointerSizeLog2);
    882   __ Daddu(array_size, array_size, FixedDoubleArray::kHeaderSize);
    883   __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required,
    884               NO_ALLOCATION_FLAGS);
    885   // array: destination FixedArray, not tagged as heap object
    886   // Set destination FixedDoubleArray's length and map.
    887   __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex);
    888   __ sd(length, MemOperand(array, FixedDoubleArray::kLengthOffset));
    889   __ sd(scratch, MemOperand(array, HeapObject::kMapOffset));
    890 
    891   // Prepare for conversion loop.
    892   Register src_elements = elements;
    893   Register dst_elements = target_map;
    894   Register dst_end = length;
    895   Register heap_number_map = scratch;
    896   __ Daddu(src_elements, src_elements,
    897            Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
    898   __ Daddu(dst_elements, array, Operand(FixedArray::kHeaderSize));
    899   __ SmiScale(dst_end, dst_end, kPointerSizeLog2);
    900   __ Daddu(dst_end, dst_elements, dst_end);
    901 
    902   // Allocating heap numbers in the loop below can fail and cause a jump to
    903   // gc_required. We can't leave a partly initialized FixedArray behind,
    904   // so pessimistically fill it with holes now.
    905   Label initialization_loop, initialization_loop_entry;
    906   __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
    907   __ Branch(&initialization_loop_entry);
    908   __ bind(&initialization_loop);
    909   __ sd(scratch, MemOperand(dst_elements));
    910   __ Daddu(dst_elements, dst_elements, Operand(kPointerSize));
    911   __ bind(&initialization_loop_entry);
    912   __ Branch(&initialization_loop, lt, dst_elements, Operand(dst_end));
    913 
    914   __ Daddu(dst_elements, array, Operand(FixedArray::kHeaderSize));
    915   __ Daddu(array, array, Operand(kHeapObjectTag));
    916   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
    917   // Using offsetted addresses.
    918   // dst_elements: begin of destination FixedArray element fields, not tagged
    919   // src_elements: begin of source FixedDoubleArray element fields, not tagged,
    920   //               points to the exponent
    921   // dst_end: end of destination FixedArray, not tagged
    922   // array: destination FixedArray
    923   // heap_number_map: heap number map
    924   __ Branch(&entry);
    925 
    926   // Call into runtime if GC is required.
    927   __ bind(&gc_required);
    928   __ MultiPop(
    929       value.bit() | key.bit() | receiver.bit() | target_map.bit() | ra.bit());
    930 
    931   __ Branch(fail);
    932 
    933   __ bind(&loop);
    934   Register upper_bits = key;
    935   __ lw(upper_bits, MemOperand(src_elements, Register::kExponentOffset));
    936   __ Daddu(src_elements, src_elements, kDoubleSize);
    937   // upper_bits: current element's upper 32 bit
    938   // src_elements: address of next element
    939   __ Branch(&convert_hole, eq, a1, Operand(kHoleNanUpper32));
    940 
    941   // Non-hole double, copy value into a heap number.
    942   Register heap_number = receiver;
    943   Register scratch2 = value;
    944   Register scratch3 = t2;
    945   __ AllocateHeapNumber(heap_number, scratch2, scratch3, heap_number_map,
    946                         &gc_required);
    947   // heap_number: new heap number
    948   // Load current element, src_elements point to next element.
    949 
    950   __ ld(scratch2, MemOperand(src_elements, -kDoubleSize));
    951   __ sd(scratch2, FieldMemOperand(heap_number, HeapNumber::kValueOffset));
    952 
    953   __ mov(scratch2, dst_elements);
    954   __ sd(heap_number, MemOperand(dst_elements));
    955   __ Daddu(dst_elements, dst_elements, kPointerSize);
    956   __ RecordWrite(array,
    957                  scratch2,
    958                  heap_number,
    959                  kRAHasBeenSaved,
    960                  kDontSaveFPRegs,
    961                  EMIT_REMEMBERED_SET,
    962                  OMIT_SMI_CHECK);
    963   __ Branch(&entry);
    964 
    965   // Replace the-hole NaN with the-hole pointer.
    966   __ bind(&convert_hole);
    967   __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex);
    968   __ sd(scratch2, MemOperand(dst_elements));
    969   __ Daddu(dst_elements, dst_elements, kPointerSize);
    970 
    971   __ bind(&entry);
    972   __ Branch(&loop, lt, dst_elements, Operand(dst_end));
    973 
    974   __ MultiPop(receiver.bit() | target_map.bit() | value.bit() | key.bit());
    975   // Replace receiver's backing store with newly created and filled FixedArray.
    976   __ sd(array, FieldMemOperand(receiver, JSObject::kElementsOffset));
    977   __ RecordWriteField(receiver,
    978                       JSObject::kElementsOffset,
    979                       array,
    980                       scratch,
    981                       kRAHasBeenSaved,
    982                       kDontSaveFPRegs,
    983                       EMIT_REMEMBERED_SET,
    984                       OMIT_SMI_CHECK);
    985   __ pop(ra);
    986 
    987   __ bind(&only_change_map);
    988   // Update receiver's map.
    989   __ sd(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
    990   __ RecordWriteField(receiver,
    991                       HeapObject::kMapOffset,
    992                       target_map,
    993                       scratch,
    994                       kRAHasNotBeenSaved,
    995                       kDontSaveFPRegs,
    996                       OMIT_REMEMBERED_SET,
    997                       OMIT_SMI_CHECK);
    998 }
    999 
   1000 
   1001 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
   1002                                        Register string,
   1003                                        Register index,
   1004                                        Register result,
   1005                                        Label* call_runtime) {
   1006   // Fetch the instance type of the receiver into result register.
   1007   __ ld(result, FieldMemOperand(string, HeapObject::kMapOffset));
   1008   __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
   1009 
   1010   // We need special handling for indirect strings.
   1011   Label check_sequential;
   1012   __ And(at, result, Operand(kIsIndirectStringMask));
   1013   __ Branch(&check_sequential, eq, at, Operand(zero_reg));
   1014 
   1015   // Dispatch on the indirect string shape: slice or cons.
   1016   Label cons_string;
   1017   __ And(at, result, Operand(kSlicedNotConsMask));
   1018   __ Branch(&cons_string, eq, at, Operand(zero_reg));
   1019 
   1020   // Handle slices.
   1021   Label indirect_string_loaded;
   1022   __ ld(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
   1023   __ ld(string, FieldMemOperand(string, SlicedString::kParentOffset));
   1024   __ dsra32(at, result, 0);
   1025   __ Daddu(index, index, at);
   1026   __ jmp(&indirect_string_loaded);
   1027 
   1028   // Handle cons strings.
   1029   // Check whether the right hand side is the empty string (i.e. if
   1030   // this is really a flat string in a cons string). If that is not
   1031   // the case we would rather go to the runtime system now to flatten
   1032   // the string.
   1033   __ bind(&cons_string);
   1034   __ ld(result, FieldMemOperand(string, ConsString::kSecondOffset));
   1035   __ LoadRoot(at, Heap::kempty_stringRootIndex);
   1036   __ Branch(call_runtime, ne, result, Operand(at));
   1037   // Get the first of the two strings and load its instance type.
   1038   __ ld(string, FieldMemOperand(string, ConsString::kFirstOffset));
   1039 
   1040   __ bind(&indirect_string_loaded);
   1041   __ ld(result, FieldMemOperand(string, HeapObject::kMapOffset));
   1042   __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
   1043 
   1044   // Distinguish sequential and external strings. Only these two string
   1045   // representations can reach here (slices and flat cons strings have been
   1046   // reduced to the underlying sequential or external string).
   1047   Label external_string, check_encoding;
   1048   __ bind(&check_sequential);
   1049   STATIC_ASSERT(kSeqStringTag == 0);
   1050   __ And(at, result, Operand(kStringRepresentationMask));
   1051   __ Branch(&external_string, ne, at, Operand(zero_reg));
   1052 
   1053   // Prepare sequential strings
   1054   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
   1055   __ Daddu(string,
   1056           string,
   1057           SeqTwoByteString::kHeaderSize - kHeapObjectTag);
   1058   __ jmp(&check_encoding);
   1059 
   1060   // Handle external strings.
   1061   __ bind(&external_string);
   1062   if (FLAG_debug_code) {
   1063     // Assert that we do not have a cons or slice (indirect strings) here.
   1064     // Sequential strings have already been ruled out.
   1065     __ And(at, result, Operand(kIsIndirectStringMask));
   1066     __ Assert(eq, kExternalStringExpectedButNotFound,
   1067         at, Operand(zero_reg));
   1068   }
   1069   // Rule out short external strings.
   1070   STATIC_ASSERT(kShortExternalStringTag != 0);
   1071   __ And(at, result, Operand(kShortExternalStringMask));
   1072   __ Branch(call_runtime, ne, at, Operand(zero_reg));
   1073   __ ld(string, FieldMemOperand(string, ExternalString::kResourceDataOffset));
   1074 
   1075   Label one_byte, done;
   1076   __ bind(&check_encoding);
   1077   STATIC_ASSERT(kTwoByteStringTag == 0);
   1078   __ And(at, result, Operand(kStringEncodingMask));
   1079   __ Branch(&one_byte, ne, at, Operand(zero_reg));
   1080   // Two-byte string.
   1081   __ dsll(at, index, 1);
   1082   __ Daddu(at, string, at);
   1083   __ lhu(result, MemOperand(at));
   1084   __ jmp(&done);
   1085   __ bind(&one_byte);
   1086   // One_byte string.
   1087   __ Daddu(at, string, index);
   1088   __ lbu(result, MemOperand(at));
   1089   __ bind(&done);
   1090 }
   1091 
   1092 
   1093 static MemOperand ExpConstant(int index, Register base) {
   1094   return MemOperand(base, index * kDoubleSize);
   1095 }
   1096 
   1097 
   1098 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
   1099                                    DoubleRegister input,
   1100                                    DoubleRegister result,
   1101                                    DoubleRegister double_scratch1,
   1102                                    DoubleRegister double_scratch2,
   1103                                    Register temp1,
   1104                                    Register temp2,
   1105                                    Register temp3) {
   1106   DCHECK(!input.is(result));
   1107   DCHECK(!input.is(double_scratch1));
   1108   DCHECK(!input.is(double_scratch2));
   1109   DCHECK(!result.is(double_scratch1));
   1110   DCHECK(!result.is(double_scratch2));
   1111   DCHECK(!double_scratch1.is(double_scratch2));
   1112   DCHECK(!temp1.is(temp2));
   1113   DCHECK(!temp1.is(temp3));
   1114   DCHECK(!temp2.is(temp3));
   1115   DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
   1116   DCHECK(!masm->serializer_enabled());  // External references not serializable.
   1117 
   1118   Label zero, infinity, done;
   1119   __ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
   1120 
   1121   __ ldc1(double_scratch1, ExpConstant(0, temp3));
   1122   __ BranchF(&zero, NULL, ge, double_scratch1, input);
   1123 
   1124   __ ldc1(double_scratch2, ExpConstant(1, temp3));
   1125   __ BranchF(&infinity, NULL, ge, input, double_scratch2);
   1126 
   1127   __ ldc1(double_scratch1, ExpConstant(3, temp3));
   1128   __ ldc1(result, ExpConstant(4, temp3));
   1129   __ mul_d(double_scratch1, double_scratch1, input);
   1130   __ add_d(double_scratch1, double_scratch1, result);
   1131   __ FmoveLow(temp2, double_scratch1);
   1132   __ sub_d(double_scratch1, double_scratch1, result);
   1133   __ ldc1(result, ExpConstant(6, temp3));
   1134   __ ldc1(double_scratch2, ExpConstant(5, temp3));
   1135   __ mul_d(double_scratch1, double_scratch1, double_scratch2);
   1136   __ sub_d(double_scratch1, double_scratch1, input);
   1137   __ sub_d(result, result, double_scratch1);
   1138   __ mul_d(double_scratch2, double_scratch1, double_scratch1);
   1139   __ mul_d(result, result, double_scratch2);
   1140   __ ldc1(double_scratch2, ExpConstant(7, temp3));
   1141   __ mul_d(result, result, double_scratch2);
   1142   __ sub_d(result, result, double_scratch1);
   1143   // Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
   1144   DCHECK(*reinterpret_cast<double*>
   1145          (ExternalReference::math_exp_constants(8).address()) == 1);
   1146   __ Move(double_scratch2, 1.);
   1147   __ add_d(result, result, double_scratch2);
   1148   __ dsrl(temp1, temp2, 11);
   1149   __ Ext(temp2, temp2, 0, 11);
   1150   __ Daddu(temp1, temp1, Operand(0x3ff));
   1151 
   1152   // Must not call ExpConstant() after overwriting temp3!
   1153   __ li(temp3, Operand(ExternalReference::math_exp_log_table()));
   1154   __ dsll(at, temp2, 3);
   1155   __ Daddu(temp3, temp3, Operand(at));
   1156   __ lwu(temp2, MemOperand(temp3, Register::kMantissaOffset));
   1157   __ lwu(temp3, MemOperand(temp3, Register::kExponentOffset));
   1158   // The first word is loaded is the lower number register.
   1159   if (temp2.code() < temp3.code()) {
   1160     __ dsll(at, temp1, 20);
   1161     __ Or(temp1, temp3, at);
   1162     __ Move(double_scratch1, temp2, temp1);
   1163   } else {
   1164     __ dsll(at, temp1, 20);
   1165     __ Or(temp1, temp2, at);
   1166     __ Move(double_scratch1, temp3, temp1);
   1167   }
   1168   __ mul_d(result, result, double_scratch1);
   1169   __ BranchShort(&done);
   1170 
   1171   __ bind(&zero);
   1172   __ Move(result, kDoubleRegZero);
   1173   __ BranchShort(&done);
   1174 
   1175   __ bind(&infinity);
   1176   __ ldc1(result, ExpConstant(2, temp3));
   1177 
   1178   __ bind(&done);
   1179 }
   1180 
   1181 #ifdef DEBUG
   1182 // nop(CODE_AGE_MARKER_NOP)
   1183 static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
   1184 #endif
   1185 
   1186 
   1187 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) {
   1188   USE(isolate);
   1189   DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
   1190   // Since patcher is a large object, allocate it dynamically when needed,
   1191   // to avoid overloading the stack in stress conditions.
   1192   // DONT_FLUSH is used because the CodeAgingHelper is initialized early in
   1193   // the process, before MIPS simulator ICache is setup.
   1194   base::SmartPointer<CodePatcher> patcher(
   1195       new CodePatcher(isolate, young_sequence_.start(),
   1196                       young_sequence_.length() / Assembler::kInstrSize,
   1197                       CodePatcher::DONT_FLUSH));
   1198   PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length());
   1199   patcher->masm()->Push(ra, fp, cp, a1);
   1200   patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
   1201   patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
   1202   patcher->masm()->nop(Assembler::CODE_AGE_SEQUENCE_NOP);
   1203   patcher->masm()->Daddu(
   1204       fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
   1205 }
   1206 
   1207 
   1208 #ifdef DEBUG
   1209 bool CodeAgingHelper::IsOld(byte* candidate) const {
   1210   return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
   1211 }
   1212 #endif
   1213 
   1214 
   1215 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
   1216   bool result = isolate->code_aging_helper()->IsYoung(sequence);
   1217   DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
   1218   return result;
   1219 }
   1220 
   1221 
   1222 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
   1223                                MarkingParity* parity) {
   1224   if (IsYoungSequence(isolate, sequence)) {
   1225     *age = kNoAgeCodeAge;
   1226     *parity = NO_MARKING_PARITY;
   1227   } else {
   1228     Address target_address = Assembler::target_address_at(
   1229         sequence + Assembler::kInstrSize);
   1230     Code* stub = GetCodeFromTargetAddress(target_address);
   1231     GetCodeAgeAndParity(stub, age, parity);
   1232   }
   1233 }
   1234 
   1235 
   1236 void Code::PatchPlatformCodeAge(Isolate* isolate,
   1237                                 byte* sequence,
   1238                                 Code::Age age,
   1239                                 MarkingParity parity) {
   1240   uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
   1241   if (age == kNoAgeCodeAge) {
   1242     isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
   1243     Assembler::FlushICache(isolate, sequence, young_length);
   1244   } else {
   1245     Code* stub = GetCodeAgeStub(isolate, age, parity);
   1246     CodePatcher patcher(isolate, sequence,
   1247                         young_length / Assembler::kInstrSize);
   1248     // Mark this code sequence for FindPlatformCodeAgeSequence().
   1249     patcher.masm()->nop(Assembler::CODE_AGE_MARKER_NOP);
   1250     // Load the stub address to t9 and call it,
   1251     // GetCodeAgeAndParity() extracts the stub address from this instruction.
   1252     patcher.masm()->li(
   1253         t9,
   1254         Operand(reinterpret_cast<uint64_t>(stub->instruction_start())),
   1255         ADDRESS_LOAD);
   1256     patcher.masm()->nop();  // Prevent jalr to jal optimization.
   1257     patcher.masm()->jalr(t9, a0);
   1258     patcher.masm()->nop();  // Branch delay slot nop.
   1259     patcher.masm()->nop();  // Pad the empty space.
   1260   }
   1261 }
   1262 
   1263 
   1264 #undef __
   1265 
   1266 }  // namespace internal
   1267 }  // namespace v8
   1268 
   1269 #endif  // V8_TARGET_ARCH_MIPS64
   1270