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