V8 Project
codegen-mips.cc
Go to the documentation of this file.
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"
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;
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 
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);
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)
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 
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 
639 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 
646 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 
659  MacroAssembler* masm,
660  Register receiver,
661  Register key,
662  Register value,
663  Register target_map,
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,
680  target_map,
681  t5,
686 }
687 
688 
690  MacroAssembler* masm,
691  Register receiver,
692  Register key,
693  Register value,
694  Register target_map,
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,
745  target_map,
746  scratch2,
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,
756  scratch1,
757  scratch2,
762 
763 
764  // Prepare for conversion loop.
765  __ Addu(scratch1, elements,
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,
788  target_map,
789  scratch2,
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 
840  MacroAssembler* masm,
841  Register receiver,
842  Register key,
843  Register value,
844  Register target_map,
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,
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(
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,
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,
966  array,
967  scratch,
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,
979  target_map,
980  scratch,
985 }
986 
987 
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);
1037  __ And(at, result, Operand(kStringRepresentationMask));
1038  __ Branch(&external_string, ne, at, Operand(zero_reg));
1039 
1040  // Prepare sequential strings
1042  __ Addu(string,
1043  string,
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.
1058  __ And(at, result, Operand(kShortExternalStringMask));
1059  __ Branch(call_runtime, ne, at, Operand(zero_reg));
1061 
1062  Label one_byte, done;
1063  __ bind(&check_encoding);
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 
1080 static MemOperand ExpConstant(int index, Register base) {
1081  return MemOperand(base, index * kDoubleSize);
1082 }
1083 
1084 
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 
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(),
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(
1190 }
1191 
1192 
1193 #ifdef DEBUG
1194 bool CodeAgingHelper::IsOld(byte* candidate) const {
1195  return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
1196 }
1197 #endif
1198 
1199 
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 
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 
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
#define kDoubleRegZero
static void * Allocate(const size_t requested, size_t *allocated, bool is_executable)
static void ProtectCode(void *address, const size_t size)
static const int kInstrSize
static Address target_address_at(Address pc, ConstantPoolArray *constant_pool)
const EmbeddedVector< byte, kNoCodeAgeSequenceLength > young_sequence_
Definition: codegen.h:171
static Code * GetCodeAgeStub(Isolate *isolate, Age age, MarkingParity parity)
Definition: objects.cc:10561
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:5018
static void PatchPlatformCodeAge(Isolate *isolate, byte *sequence, Age age, MarkingParity parity)
static bool IsYoungSequence(Isolate *isolate, byte *sequence)
static void GetCodeAgeAndParity(Code *code, Age *age, MarkingParity *parity)
Definition: objects.cc:10525
static const int kFirstOffset
Definition: objects.h:9061
static const int kSecondOffset
Definition: objects.h:9062
static void FlushICache(void *start, size_t size)
static void GenerateSmiToDouble(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static void GenerateMapChangeElementsTransition(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *allocation_memento_found)
static void GenerateDoubleToObject(MacroAssembler *masm, Register receiver, Register key, Register value, Register target_map, AllocationSiteMode mode, Label *fail)
static const int kResourceDataOffset
Definition: objects.h:9138
static const int kLengthOffset
Definition: objects.h:2392
static const int kHeaderSize
Definition: objects.h:2393
static const int kMapOffset
Definition: objects.h:1427
static const int kElementsOffset
Definition: objects.h:2194
static const int kInstanceTypeOffset
Definition: objects.h:6229
static void EmitMathExp(MacroAssembler *masm, DwVfpRegister input, DwVfpRegister result, DwVfpRegister double_scratch1, DwVfpRegister double_scratch2, Register temp1, Register temp2, Register temp3)
static uint32_t & uint32_at(Address addr)
Definition: v8memory.h:24
static const int kHeaderSize
Definition: objects.h:8941
static const int kParentOffset
Definition: objects.h:9104
static const int kOffsetOffset
Definition: objects.h:9105
static const int kFixedFrameSizeFromFp
Definition: frames.h:157
static void Generate(MacroAssembler *masm, Register string, Register index, Register result, Label *call_runtime)
virtual void AfterCall(MacroAssembler *masm) const
virtual void BeforeCall(MacroAssembler *masm) const
T * start() const
Definition: vector.h:47
int length() const
Definition: vector.h:41
@ kLittle
#define __
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be aligned(ARM64 only)") DEFINE_STRING(expose_gc_as
#define DCHECK(condition)
Definition: logging.h:205
@ DOUBLE_ALIGNMENT
@ NO_ALLOCATION_FLAGS
int int32_t
Definition: unicode.cc:24
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
const uint32_t kStringEncodingMask
Definition: objects.h:555
const int32_t kPrefHintLoadStreamed
const int KB
Definition: globals.h:106
@ TRACK_ALLOCATION_SITE
Definition: objects.h:8085
@ kSeqStringTag
Definition: objects.h:563
bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const Register cp
const uint32_t kTwoByteStringTag
Definition: objects.h:556
const uint32_t kShortExternalStringTag
Definition: objects.h:590
const int kSmiTagSize
Definition: v8.h:5743
const int kDoubleSize
Definition: globals.h:127
const Register fp
DwVfpRegister DoubleRegister
const FPURegister f4
const FPURegister f6
const Register sp
MemOperand FieldMemOperand(Register object, int offset)
UnaryMathFunction CreateExpFunction()
@ NO_MARKING_PARITY
Definition: objects.h:298
const FPURegister f12
const uint32_t kShortExternalStringMask
Definition: objects.h:589
const uint32_t kStringRepresentationMask
Definition: objects.h:561
byte * Address
Definition: globals.h:101
const uint32_t kSlicedNotConsMask
Definition: objects.h:579
const int32_t kPrefHintPrepareForStore
const int kIntSize
Definition: globals.h:124
const int kHeapObjectTag
Definition: v8.h:5737
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
UnaryMathFunction CreateSqrtFunction()
double(* UnaryMathFunction)(double x)
Definition: codegen.h:98
static const int kNoCodeAgeSequenceLength
const uint32_t kHoleNanLower32
Definition: globals.h:657
const uint32_t kIsIndirectStringMask
Definition: objects.h:568
const FPURegister f0
const uint32_t kHoleNanUpper32
Definition: globals.h:656
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20