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