• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace v8 {
14 namespace internal {
15 
16 
17 #define __ masm.
18 
19 
20 #if defined(USE_SIMULATOR)
21 byte* fast_exp_mips_machine_code = NULL;
fast_exp_simulator(double x)22 double 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 
CreateExpFunction()29 UnaryMathFunction 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)
CreateMemCopyUint8Function(MemCopyUint8Function stub)75 MemCopyUint8Function 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 
CreateSqrtFunction()607 UnaryMathFunction 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 
BeforeCall(MacroAssembler * masm) const639 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
640   masm->EnterFrame(StackFrame::INTERNAL);
641   DCHECK(!masm->has_frame());
642   masm->set_has_frame(true);
643 }
644 
645 
AfterCall(MacroAssembler * masm) const646 void 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 
GenerateMapChangeElementsTransition(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * allocation_memento_found)658 void 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 
GenerateSmiToDouble(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)689 void 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 
GenerateDoubleToObject(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)839 void 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 
Generate(MacroAssembler * masm,Register string,Register index,Register result,Label * call_runtime)988 void 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 
ExpConstant(int index,Register base)1080 static MemOperand ExpConstant(int index, Register base) {
1081   return MemOperand(base, index * kDoubleSize);
1082 }
1083 
1084 
EmitMathExp(MacroAssembler * masm,DoubleRegister input,DoubleRegister result,DoubleRegister double_scratch1,DoubleRegister double_scratch2,Register temp1,Register temp2,Register temp3)1085 void 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)
1171 static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
1172 #endif
1173 
1174 
CodeAgingHelper()1175 CodeAgingHelper::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
IsOld(byte * candidate) const1194 bool CodeAgingHelper::IsOld(byte* candidate) const {
1195   return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
1196 }
1197 #endif
1198 
1199 
IsYoungSequence(Isolate * isolate,byte * sequence)1200 bool 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 
GetCodeAgeAndParity(Isolate * isolate,byte * sequence,Age * age,MarkingParity * parity)1207 void 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 
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age,MarkingParity parity)1221 void 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