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