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 
15 namespace v8 {
16 namespace internal {
17 
18 
19 #define __ masm.
20 
21 #if defined(V8_HOST_ARCH_MIPS)
CreateMemCopyUint8Function(Isolate * isolate,MemCopyUint8Function stub)22 MemCopyUint8Function 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 
CreateSqrtFunction(Isolate * isolate)556 UnaryMathFunctionWithIsolate 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 
BeforeCall(MacroAssembler * masm) const589 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
590   masm->EnterFrame(StackFrame::INTERNAL);
591   DCHECK(!masm->has_frame());
592   masm->set_has_frame(true);
593 }
594 
595 
AfterCall(MacroAssembler * masm) const596 void 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 
GenerateMapChangeElementsTransition(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * allocation_memento_found)608 void 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 
GenerateSmiToDouble(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)639 void 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 
GenerateDoubleToObject(MacroAssembler * masm,Register receiver,Register key,Register value,Register target_map,AllocationSiteMode mode,Label * fail)790 void 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 
Generate(MacroAssembler * masm,Register string,Register index,Register result,Label * call_runtime)953 void 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)
1045 static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
1046 #endif
1047 
1048 
CodeAgingHelper(Isolate * isolate)1049 CodeAgingHelper::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
IsOld(byte * candidate) const1067 bool CodeAgingHelper::IsOld(byte* candidate) const {
1068   return Memory::uint32_at(candidate) == kCodeAgePatchFirstInstruction;
1069 }
1070 #endif
1071 
1072 
IsYoungSequence(Isolate * isolate,byte * sequence)1073 bool 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 
GetCodeAgeAndParity(Isolate * isolate,byte * sequence,Age * age,MarkingParity * parity)1080 void 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 
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age,MarkingParity parity)1094 void 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