Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(957)

Side by Side Diff: src/a64/macro-assembler-a64.cc

Issue 207823003: Rename A64 port to ARM64 port (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: retry Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/a64/macro-assembler-a64.h ('k') | src/a64/macro-assembler-a64-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #if V8_TARGET_ARCH_A64
31
32 #include "bootstrapper.h"
33 #include "codegen.h"
34 #include "cpu-profiler.h"
35 #include "debug.h"
36 #include "isolate-inl.h"
37 #include "runtime.h"
38
39 namespace v8 {
40 namespace internal {
41
42 // Define a fake double underscore to use with the ASM_UNIMPLEMENTED macros.
43 #define __
44
45
46 MacroAssembler::MacroAssembler(Isolate* arg_isolate,
47 byte * buffer,
48 unsigned buffer_size)
49 : Assembler(arg_isolate, buffer, buffer_size),
50 generating_stub_(false),
51 #if DEBUG
52 allow_macro_instructions_(true),
53 #endif
54 has_frame_(false),
55 use_real_aborts_(true),
56 sp_(jssp), tmp_list_(ip0, ip1), fptmp_list_(fp_scratch) {
57 if (isolate() != NULL) {
58 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
59 isolate());
60 }
61 }
62
63
64 void MacroAssembler::LogicalMacro(const Register& rd,
65 const Register& rn,
66 const Operand& operand,
67 LogicalOp op) {
68 UseScratchRegisterScope temps(this);
69
70 if (operand.NeedsRelocation()) {
71 Register temp = temps.AcquireX();
72 LoadRelocated(temp, operand);
73 Logical(rd, rn, temp, op);
74
75 } else if (operand.IsImmediate()) {
76 int64_t immediate = operand.immediate();
77 unsigned reg_size = rd.SizeInBits();
78 ASSERT(rd.Is64Bits() || is_uint32(immediate));
79
80 // If the operation is NOT, invert the operation and immediate.
81 if ((op & NOT) == NOT) {
82 op = static_cast<LogicalOp>(op & ~NOT);
83 immediate = ~immediate;
84 if (rd.Is32Bits()) {
85 immediate &= kWRegMask;
86 }
87 }
88
89 // Special cases for all set or all clear immediates.
90 if (immediate == 0) {
91 switch (op) {
92 case AND:
93 Mov(rd, 0);
94 return;
95 case ORR: // Fall through.
96 case EOR:
97 Mov(rd, rn);
98 return;
99 case ANDS: // Fall through.
100 case BICS:
101 break;
102 default:
103 UNREACHABLE();
104 }
105 } else if ((rd.Is64Bits() && (immediate == -1L)) ||
106 (rd.Is32Bits() && (immediate == 0xffffffffL))) {
107 switch (op) {
108 case AND:
109 Mov(rd, rn);
110 return;
111 case ORR:
112 Mov(rd, immediate);
113 return;
114 case EOR:
115 Mvn(rd, rn);
116 return;
117 case ANDS: // Fall through.
118 case BICS:
119 break;
120 default:
121 UNREACHABLE();
122 }
123 }
124
125 unsigned n, imm_s, imm_r;
126 if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
127 // Immediate can be encoded in the instruction.
128 LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
129 } else {
130 // Immediate can't be encoded: synthesize using move immediate.
131 Register temp = temps.AcquireSameSizeAs(rn);
132 Mov(temp, immediate);
133 if (rd.Is(csp)) {
134 // If rd is the stack pointer we cannot use it as the destination
135 // register so we use the temp register as an intermediate again.
136 Logical(temp, rn, temp, op);
137 Mov(csp, temp);
138 } else {
139 Logical(rd, rn, temp, op);
140 }
141 }
142
143 } else if (operand.IsExtendedRegister()) {
144 ASSERT(operand.reg().SizeInBits() <= rd.SizeInBits());
145 // Add/sub extended supports shift <= 4. We want to support exactly the
146 // same modes here.
147 ASSERT(operand.shift_amount() <= 4);
148 ASSERT(operand.reg().Is64Bits() ||
149 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
150 Register temp = temps.AcquireSameSizeAs(rn);
151 EmitExtendShift(temp, operand.reg(), operand.extend(),
152 operand.shift_amount());
153 Logical(rd, rn, temp, op);
154
155 } else {
156 // The operand can be encoded in the instruction.
157 ASSERT(operand.IsShiftedRegister());
158 Logical(rd, rn, operand, op);
159 }
160 }
161
162
163 void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
164 ASSERT(allow_macro_instructions_);
165 ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits());
166 ASSERT(!rd.IsZero());
167
168 // TODO(all) extend to support more immediates.
169 //
170 // Immediates on Aarch64 can be produced using an initial value, and zero to
171 // three move keep operations.
172 //
173 // Initial values can be generated with:
174 // 1. 64-bit move zero (movz).
175 // 2. 32-bit move inverted (movn).
176 // 3. 64-bit move inverted.
177 // 4. 32-bit orr immediate.
178 // 5. 64-bit orr immediate.
179 // Move-keep may then be used to modify each of the 16-bit half-words.
180 //
181 // The code below supports all five initial value generators, and
182 // applying move-keep operations to move-zero and move-inverted initial
183 // values.
184
185 unsigned reg_size = rd.SizeInBits();
186 unsigned n, imm_s, imm_r;
187 if (IsImmMovz(imm, reg_size) && !rd.IsSP()) {
188 // Immediate can be represented in a move zero instruction. Movz can't
189 // write to the stack pointer.
190 movz(rd, imm);
191 } else if (IsImmMovn(imm, reg_size) && !rd.IsSP()) {
192 // Immediate can be represented in a move inverted instruction. Movn can't
193 // write to the stack pointer.
194 movn(rd, rd.Is64Bits() ? ~imm : (~imm & kWRegMask));
195 } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
196 // Immediate can be represented in a logical orr instruction.
197 LogicalImmediate(rd, AppropriateZeroRegFor(rd), n, imm_s, imm_r, ORR);
198 } else {
199 // Generic immediate case. Imm will be represented by
200 // [imm3, imm2, imm1, imm0], where each imm is 16 bits.
201 // A move-zero or move-inverted is generated for the first non-zero or
202 // non-0xffff immX, and a move-keep for subsequent non-zero immX.
203
204 uint64_t ignored_halfword = 0;
205 bool invert_move = false;
206 // If the number of 0xffff halfwords is greater than the number of 0x0000
207 // halfwords, it's more efficient to use move-inverted.
208 if (CountClearHalfWords(~imm, reg_size) >
209 CountClearHalfWords(imm, reg_size)) {
210 ignored_halfword = 0xffffL;
211 invert_move = true;
212 }
213
214 // Mov instructions can't move immediate values into the stack pointer, so
215 // set up a temporary register, if needed.
216 UseScratchRegisterScope temps(this);
217 Register temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
218
219 // Iterate through the halfwords. Use movn/movz for the first non-ignored
220 // halfword, and movk for subsequent halfwords.
221 ASSERT((reg_size % 16) == 0);
222 bool first_mov_done = false;
223 for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) {
224 uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
225 if (imm16 != ignored_halfword) {
226 if (!first_mov_done) {
227 if (invert_move) {
228 movn(temp, (~imm16) & 0xffffL, 16 * i);
229 } else {
230 movz(temp, imm16, 16 * i);
231 }
232 first_mov_done = true;
233 } else {
234 // Construct a wider constant.
235 movk(temp, imm16, 16 * i);
236 }
237 }
238 }
239 ASSERT(first_mov_done);
240
241 // Move the temporary if the original destination register was the stack
242 // pointer.
243 if (rd.IsSP()) {
244 mov(rd, temp);
245 }
246 }
247 }
248
249
250 void MacroAssembler::Mov(const Register& rd,
251 const Operand& operand,
252 DiscardMoveMode discard_mode) {
253 ASSERT(allow_macro_instructions_);
254 ASSERT(!rd.IsZero());
255
256 // Provide a swap register for instructions that need to write into the
257 // system stack pointer (and can't do this inherently).
258 UseScratchRegisterScope temps(this);
259 Register dst = (rd.IsSP()) ? temps.AcquireSameSizeAs(rd) : rd;
260
261 if (operand.NeedsRelocation()) {
262 LoadRelocated(dst, operand);
263
264 } else if (operand.IsImmediate()) {
265 // Call the macro assembler for generic immediates.
266 Mov(dst, operand.immediate());
267
268 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
269 // Emit a shift instruction if moving a shifted register. This operation
270 // could also be achieved using an orr instruction (like orn used by Mvn),
271 // but using a shift instruction makes the disassembly clearer.
272 EmitShift(dst, operand.reg(), operand.shift(), operand.shift_amount());
273
274 } else if (operand.IsExtendedRegister()) {
275 // Emit an extend instruction if moving an extended register. This handles
276 // extend with post-shift operations, too.
277 EmitExtendShift(dst, operand.reg(), operand.extend(),
278 operand.shift_amount());
279
280 } else {
281 // Otherwise, emit a register move only if the registers are distinct, or
282 // if they are not X registers.
283 //
284 // Note that mov(w0, w0) is not a no-op because it clears the top word of
285 // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W
286 // registers is not required to clear the top word of the X register. In
287 // this case, the instruction is discarded.
288 //
289 // If csp is an operand, add #0 is emitted, otherwise, orr #0.
290 if (!rd.Is(operand.reg()) || (rd.Is32Bits() &&
291 (discard_mode == kDontDiscardForSameWReg))) {
292 Assembler::mov(rd, operand.reg());
293 }
294 // This case can handle writes into the system stack pointer directly.
295 dst = rd;
296 }
297
298 // Copy the result to the system stack pointer.
299 if (!dst.Is(rd)) {
300 ASSERT(rd.IsSP());
301 Assembler::mov(rd, dst);
302 }
303 }
304
305
306 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
307 ASSERT(allow_macro_instructions_);
308
309 if (operand.NeedsRelocation()) {
310 LoadRelocated(rd, operand);
311 mvn(rd, rd);
312
313 } else if (operand.IsImmediate()) {
314 // Call the macro assembler for generic immediates.
315 Mov(rd, ~operand.immediate());
316
317 } else if (operand.IsExtendedRegister()) {
318 // Emit two instructions for the extend case. This differs from Mov, as
319 // the extend and invert can't be achieved in one instruction.
320 EmitExtendShift(rd, operand.reg(), operand.extend(),
321 operand.shift_amount());
322 mvn(rd, rd);
323
324 } else {
325 mvn(rd, operand);
326 }
327 }
328
329
330 unsigned MacroAssembler::CountClearHalfWords(uint64_t imm, unsigned reg_size) {
331 ASSERT((reg_size % 8) == 0);
332 int count = 0;
333 for (unsigned i = 0; i < (reg_size / 16); i++) {
334 if ((imm & 0xffff) == 0) {
335 count++;
336 }
337 imm >>= 16;
338 }
339 return count;
340 }
341
342
343 // The movz instruction can generate immediates containing an arbitrary 16-bit
344 // half-word, with remaining bits clear, eg. 0x00001234, 0x0000123400000000.
345 bool MacroAssembler::IsImmMovz(uint64_t imm, unsigned reg_size) {
346 ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits));
347 return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1);
348 }
349
350
351 // The movn instruction can generate immediates containing an arbitrary 16-bit
352 // half-word, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff.
353 bool MacroAssembler::IsImmMovn(uint64_t imm, unsigned reg_size) {
354 return IsImmMovz(~imm, reg_size);
355 }
356
357
358 void MacroAssembler::ConditionalCompareMacro(const Register& rn,
359 const Operand& operand,
360 StatusFlags nzcv,
361 Condition cond,
362 ConditionalCompareOp op) {
363 ASSERT((cond != al) && (cond != nv));
364 if (operand.NeedsRelocation()) {
365 UseScratchRegisterScope temps(this);
366 Register temp = temps.AcquireX();
367 LoadRelocated(temp, operand);
368 ConditionalCompareMacro(rn, temp, nzcv, cond, op);
369
370 } else if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) ||
371 (operand.IsImmediate() && IsImmConditionalCompare(operand.immediate()))) {
372 // The immediate can be encoded in the instruction, or the operand is an
373 // unshifted register: call the assembler.
374 ConditionalCompare(rn, operand, nzcv, cond, op);
375
376 } else {
377 // The operand isn't directly supported by the instruction: perform the
378 // operation on a temporary register.
379 UseScratchRegisterScope temps(this);
380 Register temp = temps.AcquireSameSizeAs(rn);
381 Mov(temp, operand);
382 ConditionalCompare(rn, temp, nzcv, cond, op);
383 }
384 }
385
386
387 void MacroAssembler::Csel(const Register& rd,
388 const Register& rn,
389 const Operand& operand,
390 Condition cond) {
391 ASSERT(allow_macro_instructions_);
392 ASSERT(!rd.IsZero());
393 ASSERT((cond != al) && (cond != nv));
394 if (operand.IsImmediate()) {
395 // Immediate argument. Handle special cases of 0, 1 and -1 using zero
396 // register.
397 int64_t imm = operand.immediate();
398 Register zr = AppropriateZeroRegFor(rn);
399 if (imm == 0) {
400 csel(rd, rn, zr, cond);
401 } else if (imm == 1) {
402 csinc(rd, rn, zr, cond);
403 } else if (imm == -1) {
404 csinv(rd, rn, zr, cond);
405 } else {
406 UseScratchRegisterScope temps(this);
407 Register temp = temps.AcquireSameSizeAs(rn);
408 Mov(temp, operand.immediate());
409 csel(rd, rn, temp, cond);
410 }
411 } else if (operand.IsShiftedRegister() && (operand.shift_amount() == 0)) {
412 // Unshifted register argument.
413 csel(rd, rn, operand.reg(), cond);
414 } else {
415 // All other arguments.
416 UseScratchRegisterScope temps(this);
417 Register temp = temps.AcquireSameSizeAs(rn);
418 Mov(temp, operand);
419 csel(rd, rn, temp, cond);
420 }
421 }
422
423
424 void MacroAssembler::AddSubMacro(const Register& rd,
425 const Register& rn,
426 const Operand& operand,
427 FlagsUpdate S,
428 AddSubOp op) {
429 if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
430 !operand.NeedsRelocation() && (S == LeaveFlags)) {
431 // The instruction would be a nop. Avoid generating useless code.
432 return;
433 }
434
435 if (operand.NeedsRelocation()) {
436 UseScratchRegisterScope temps(this);
437 Register temp = temps.AcquireX();
438 LoadRelocated(temp, operand);
439 AddSubMacro(rd, rn, temp, S, op);
440 } else if ((operand.IsImmediate() && !IsImmAddSub(operand.immediate())) ||
441 (rn.IsZero() && !operand.IsShiftedRegister()) ||
442 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
443 UseScratchRegisterScope temps(this);
444 Register temp = temps.AcquireSameSizeAs(rn);
445 Mov(temp, operand);
446 AddSub(rd, rn, temp, S, op);
447 } else {
448 AddSub(rd, rn, operand, S, op);
449 }
450 }
451
452
453 void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
454 const Register& rn,
455 const Operand& operand,
456 FlagsUpdate S,
457 AddSubWithCarryOp op) {
458 ASSERT(rd.SizeInBits() == rn.SizeInBits());
459 UseScratchRegisterScope temps(this);
460
461 if (operand.NeedsRelocation()) {
462 Register temp = temps.AcquireX();
463 LoadRelocated(temp, operand);
464 AddSubWithCarryMacro(rd, rn, temp, S, op);
465
466 } else if (operand.IsImmediate() ||
467 (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
468 // Add/sub with carry (immediate or ROR shifted register.)
469 Register temp = temps.AcquireSameSizeAs(rn);
470 Mov(temp, operand);
471 AddSubWithCarry(rd, rn, temp, S, op);
472
473 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
474 // Add/sub with carry (shifted register).
475 ASSERT(operand.reg().SizeInBits() == rd.SizeInBits());
476 ASSERT(operand.shift() != ROR);
477 ASSERT(is_uintn(operand.shift_amount(),
478 rd.SizeInBits() == kXRegSizeInBits ? kXRegSizeInBitsLog2
479 : kWRegSizeInBitsLog2));
480 Register temp = temps.AcquireSameSizeAs(rn);
481 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
482 AddSubWithCarry(rd, rn, temp, S, op);
483
484 } else if (operand.IsExtendedRegister()) {
485 // Add/sub with carry (extended register).
486 ASSERT(operand.reg().SizeInBits() <= rd.SizeInBits());
487 // Add/sub extended supports a shift <= 4. We want to support exactly the
488 // same modes.
489 ASSERT(operand.shift_amount() <= 4);
490 ASSERT(operand.reg().Is64Bits() ||
491 ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
492 Register temp = temps.AcquireSameSizeAs(rn);
493 EmitExtendShift(temp, operand.reg(), operand.extend(),
494 operand.shift_amount());
495 AddSubWithCarry(rd, rn, temp, S, op);
496
497 } else {
498 // The addressing mode is directly supported by the instruction.
499 AddSubWithCarry(rd, rn, operand, S, op);
500 }
501 }
502
503
504 void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
505 const MemOperand& addr,
506 LoadStoreOp op) {
507 int64_t offset = addr.offset();
508 LSDataSize size = CalcLSDataSize(op);
509
510 // Check if an immediate offset fits in the immediate field of the
511 // appropriate instruction. If not, emit two instructions to perform
512 // the operation.
513 if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) &&
514 !IsImmLSUnscaled(offset)) {
515 // Immediate offset that can't be encoded using unsigned or unscaled
516 // addressing modes.
517 UseScratchRegisterScope temps(this);
518 Register temp = temps.AcquireSameSizeAs(addr.base());
519 Mov(temp, addr.offset());
520 LoadStore(rt, MemOperand(addr.base(), temp), op);
521 } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
522 // Post-index beyond unscaled addressing range.
523 LoadStore(rt, MemOperand(addr.base()), op);
524 add(addr.base(), addr.base(), offset);
525 } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
526 // Pre-index beyond unscaled addressing range.
527 add(addr.base(), addr.base(), offset);
528 LoadStore(rt, MemOperand(addr.base()), op);
529 } else {
530 // Encodable in one load/store instruction.
531 LoadStore(rt, addr, op);
532 }
533 }
534
535
536 void MacroAssembler::Load(const Register& rt,
537 const MemOperand& addr,
538 Representation r) {
539 ASSERT(!r.IsDouble());
540
541 if (r.IsInteger8()) {
542 Ldrsb(rt, addr);
543 } else if (r.IsUInteger8()) {
544 Ldrb(rt, addr);
545 } else if (r.IsInteger16()) {
546 Ldrsh(rt, addr);
547 } else if (r.IsUInteger16()) {
548 Ldrh(rt, addr);
549 } else if (r.IsInteger32()) {
550 Ldr(rt.W(), addr);
551 } else {
552 ASSERT(rt.Is64Bits());
553 Ldr(rt, addr);
554 }
555 }
556
557
558 void MacroAssembler::Store(const Register& rt,
559 const MemOperand& addr,
560 Representation r) {
561 ASSERT(!r.IsDouble());
562
563 if (r.IsInteger8() || r.IsUInteger8()) {
564 Strb(rt, addr);
565 } else if (r.IsInteger16() || r.IsUInteger16()) {
566 Strh(rt, addr);
567 } else if (r.IsInteger32()) {
568 Str(rt.W(), addr);
569 } else {
570 ASSERT(rt.Is64Bits());
571 Str(rt, addr);
572 }
573 }
574
575
576 bool MacroAssembler::NeedExtraInstructionsOrRegisterBranch(
577 Label *label, ImmBranchType b_type) {
578 bool need_longer_range = false;
579 // There are two situations in which we care about the offset being out of
580 // range:
581 // - The label is bound but too far away.
582 // - The label is not bound but linked, and the previous branch
583 // instruction in the chain is too far away.
584 if (label->is_bound() || label->is_linked()) {
585 need_longer_range =
586 !Instruction::IsValidImmPCOffset(b_type, label->pos() - pc_offset());
587 }
588 if (!need_longer_range && !label->is_bound()) {
589 int max_reachable_pc = pc_offset() + Instruction::ImmBranchRange(b_type);
590 unresolved_branches_.insert(
591 std::pair<int, FarBranchInfo>(max_reachable_pc,
592 FarBranchInfo(pc_offset(), label)));
593 // Also maintain the next pool check.
594 next_veneer_pool_check_ =
595 Min(next_veneer_pool_check_,
596 max_reachable_pc - kVeneerDistanceCheckMargin);
597 }
598 return need_longer_range;
599 }
600
601
602 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
603 ASSERT((reg.Is(NoReg) || type >= kBranchTypeFirstUsingReg) &&
604 (bit == -1 || type >= kBranchTypeFirstUsingBit));
605 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
606 B(static_cast<Condition>(type), label);
607 } else {
608 switch (type) {
609 case always: B(label); break;
610 case never: break;
611 case reg_zero: Cbz(reg, label); break;
612 case reg_not_zero: Cbnz(reg, label); break;
613 case reg_bit_clear: Tbz(reg, bit, label); break;
614 case reg_bit_set: Tbnz(reg, bit, label); break;
615 default:
616 UNREACHABLE();
617 }
618 }
619 }
620
621
622 void MacroAssembler::B(Label* label, Condition cond) {
623 ASSERT(allow_macro_instructions_);
624 ASSERT((cond != al) && (cond != nv));
625
626 Label done;
627 bool need_extra_instructions =
628 NeedExtraInstructionsOrRegisterBranch(label, CondBranchType);
629
630 if (need_extra_instructions) {
631 b(&done, InvertCondition(cond));
632 B(label);
633 } else {
634 b(label, cond);
635 }
636 bind(&done);
637 }
638
639
640 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
641 ASSERT(allow_macro_instructions_);
642
643 Label done;
644 bool need_extra_instructions =
645 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
646
647 if (need_extra_instructions) {
648 tbz(rt, bit_pos, &done);
649 B(label);
650 } else {
651 tbnz(rt, bit_pos, label);
652 }
653 bind(&done);
654 }
655
656
657 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
658 ASSERT(allow_macro_instructions_);
659
660 Label done;
661 bool need_extra_instructions =
662 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
663
664 if (need_extra_instructions) {
665 tbnz(rt, bit_pos, &done);
666 B(label);
667 } else {
668 tbz(rt, bit_pos, label);
669 }
670 bind(&done);
671 }
672
673
674 void MacroAssembler::Cbnz(const Register& rt, Label* label) {
675 ASSERT(allow_macro_instructions_);
676
677 Label done;
678 bool need_extra_instructions =
679 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
680
681 if (need_extra_instructions) {
682 cbz(rt, &done);
683 B(label);
684 } else {
685 cbnz(rt, label);
686 }
687 bind(&done);
688 }
689
690
691 void MacroAssembler::Cbz(const Register& rt, Label* label) {
692 ASSERT(allow_macro_instructions_);
693
694 Label done;
695 bool need_extra_instructions =
696 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
697
698 if (need_extra_instructions) {
699 cbnz(rt, &done);
700 B(label);
701 } else {
702 cbz(rt, label);
703 }
704 bind(&done);
705 }
706
707
708 // Pseudo-instructions.
709
710
711 void MacroAssembler::Abs(const Register& rd, const Register& rm,
712 Label* is_not_representable,
713 Label* is_representable) {
714 ASSERT(allow_macro_instructions_);
715 ASSERT(AreSameSizeAndType(rd, rm));
716
717 Cmp(rm, 1);
718 Cneg(rd, rm, lt);
719
720 // If the comparison sets the v flag, the input was the smallest value
721 // representable by rm, and the mathematical result of abs(rm) is not
722 // representable using two's complement.
723 if ((is_not_representable != NULL) && (is_representable != NULL)) {
724 B(is_not_representable, vs);
725 B(is_representable);
726 } else if (is_not_representable != NULL) {
727 B(is_not_representable, vs);
728 } else if (is_representable != NULL) {
729 B(is_representable, vc);
730 }
731 }
732
733
734 // Abstracted stack operations.
735
736
737 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
738 const CPURegister& src2, const CPURegister& src3) {
739 ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
740
741 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
742 int size = src0.SizeInBytes();
743
744 PrepareForPush(count, size);
745 PushHelper(count, size, src0, src1, src2, src3);
746 }
747
748
749 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
750 const CPURegister& src2, const CPURegister& src3,
751 const CPURegister& src4, const CPURegister& src5,
752 const CPURegister& src6, const CPURegister& src7) {
753 ASSERT(AreSameSizeAndType(src0, src1, src2, src3, src4, src5, src6, src7));
754
755 int count = 5 + src5.IsValid() + src6.IsValid() + src6.IsValid();
756 int size = src0.SizeInBytes();
757
758 PrepareForPush(count, size);
759 PushHelper(4, size, src0, src1, src2, src3);
760 PushHelper(count - 4, size, src4, src5, src6, src7);
761 }
762
763
764 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1,
765 const CPURegister& dst2, const CPURegister& dst3) {
766 // It is not valid to pop into the same register more than once in one
767 // instruction, not even into the zero register.
768 ASSERT(!AreAliased(dst0, dst1, dst2, dst3));
769 ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
770 ASSERT(dst0.IsValid());
771
772 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
773 int size = dst0.SizeInBytes();
774
775 PrepareForPop(count, size);
776 PopHelper(count, size, dst0, dst1, dst2, dst3);
777
778 if (!csp.Is(StackPointer()) && emit_debug_code()) {
779 // It is safe to leave csp where it is when unwinding the JavaScript stack,
780 // but if we keep it matching StackPointer, the simulator can detect memory
781 // accesses in the now-free part of the stack.
782 Mov(csp, StackPointer());
783 }
784 }
785
786
787 void MacroAssembler::PushPopQueue::PushQueued() {
788 if (queued_.empty()) return;
789
790 masm_->PrepareForPush(size_);
791
792 int count = queued_.size();
793 int index = 0;
794 while (index < count) {
795 // PushHelper can only handle registers with the same size and type, and it
796 // can handle only four at a time. Batch them up accordingly.
797 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg};
798 int batch_index = 0;
799 do {
800 batch[batch_index++] = queued_[index++];
801 } while ((batch_index < 4) && (index < count) &&
802 batch[0].IsSameSizeAndType(queued_[index]));
803
804 masm_->PushHelper(batch_index, batch[0].SizeInBytes(),
805 batch[0], batch[1], batch[2], batch[3]);
806 }
807
808 queued_.clear();
809 }
810
811
812 void MacroAssembler::PushPopQueue::PopQueued() {
813 if (queued_.empty()) return;
814
815 masm_->PrepareForPop(size_);
816
817 int count = queued_.size();
818 int index = 0;
819 while (index < count) {
820 // PopHelper can only handle registers with the same size and type, and it
821 // can handle only four at a time. Batch them up accordingly.
822 CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg};
823 int batch_index = 0;
824 do {
825 batch[batch_index++] = queued_[index++];
826 } while ((batch_index < 4) && (index < count) &&
827 batch[0].IsSameSizeAndType(queued_[index]));
828
829 masm_->PopHelper(batch_index, batch[0].SizeInBytes(),
830 batch[0], batch[1], batch[2], batch[3]);
831 }
832
833 queued_.clear();
834 }
835
836
837 void MacroAssembler::PushCPURegList(CPURegList registers) {
838 int size = registers.RegisterSizeInBytes();
839
840 PrepareForPush(registers.Count(), size);
841 // Push up to four registers at a time because if the current stack pointer is
842 // csp and reg_size is 32, registers must be pushed in blocks of four in order
843 // to maintain the 16-byte alignment for csp.
844 while (!registers.IsEmpty()) {
845 int count_before = registers.Count();
846 const CPURegister& src0 = registers.PopHighestIndex();
847 const CPURegister& src1 = registers.PopHighestIndex();
848 const CPURegister& src2 = registers.PopHighestIndex();
849 const CPURegister& src3 = registers.PopHighestIndex();
850 int count = count_before - registers.Count();
851 PushHelper(count, size, src0, src1, src2, src3);
852 }
853 }
854
855
856 void MacroAssembler::PopCPURegList(CPURegList registers) {
857 int size = registers.RegisterSizeInBytes();
858
859 PrepareForPop(registers.Count(), size);
860 // Pop up to four registers at a time because if the current stack pointer is
861 // csp and reg_size is 32, registers must be pushed in blocks of four in
862 // order to maintain the 16-byte alignment for csp.
863 while (!registers.IsEmpty()) {
864 int count_before = registers.Count();
865 const CPURegister& dst0 = registers.PopLowestIndex();
866 const CPURegister& dst1 = registers.PopLowestIndex();
867 const CPURegister& dst2 = registers.PopLowestIndex();
868 const CPURegister& dst3 = registers.PopLowestIndex();
869 int count = count_before - registers.Count();
870 PopHelper(count, size, dst0, dst1, dst2, dst3);
871 }
872
873 if (!csp.Is(StackPointer()) && emit_debug_code()) {
874 // It is safe to leave csp where it is when unwinding the JavaScript stack,
875 // but if we keep it matching StackPointer, the simulator can detect memory
876 // accesses in the now-free part of the stack.
877 Mov(csp, StackPointer());
878 }
879 }
880
881
882 void MacroAssembler::PushMultipleTimes(CPURegister src, int count) {
883 int size = src.SizeInBytes();
884
885 PrepareForPush(count, size);
886
887 if (FLAG_optimize_for_size && count > 8) {
888 UseScratchRegisterScope temps(this);
889 Register temp = temps.AcquireX();
890
891 Label loop;
892 __ Mov(temp, count / 2);
893 __ Bind(&loop);
894 PushHelper(2, size, src, src, NoReg, NoReg);
895 __ Subs(temp, temp, 1);
896 __ B(ne, &loop);
897
898 count %= 2;
899 }
900
901 // Push up to four registers at a time if possible because if the current
902 // stack pointer is csp and the register size is 32, registers must be pushed
903 // in blocks of four in order to maintain the 16-byte alignment for csp.
904 while (count >= 4) {
905 PushHelper(4, size, src, src, src, src);
906 count -= 4;
907 }
908 if (count >= 2) {
909 PushHelper(2, size, src, src, NoReg, NoReg);
910 count -= 2;
911 }
912 if (count == 1) {
913 PushHelper(1, size, src, NoReg, NoReg, NoReg);
914 count -= 1;
915 }
916 ASSERT(count == 0);
917 }
918
919
920 void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) {
921 PrepareForPush(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes())));
922
923 UseScratchRegisterScope temps(this);
924 Register temp = temps.AcquireSameSizeAs(count);
925
926 if (FLAG_optimize_for_size) {
927 Label loop, done;
928
929 Subs(temp, count, 1);
930 B(mi, &done);
931
932 // Push all registers individually, to save code size.
933 Bind(&loop);
934 Subs(temp, temp, 1);
935 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
936 B(pl, &loop);
937
938 Bind(&done);
939 } else {
940 Label loop, leftover2, leftover1, done;
941
942 Subs(temp, count, 4);
943 B(mi, &leftover2);
944
945 // Push groups of four first.
946 Bind(&loop);
947 Subs(temp, temp, 4);
948 PushHelper(4, src.SizeInBytes(), src, src, src, src);
949 B(pl, &loop);
950
951 // Push groups of two.
952 Bind(&leftover2);
953 Tbz(count, 1, &leftover1);
954 PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg);
955
956 // Push the last one (if required).
957 Bind(&leftover1);
958 Tbz(count, 0, &done);
959 PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
960
961 Bind(&done);
962 }
963 }
964
965
966 void MacroAssembler::PushHelper(int count, int size,
967 const CPURegister& src0,
968 const CPURegister& src1,
969 const CPURegister& src2,
970 const CPURegister& src3) {
971 // Ensure that we don't unintentially modify scratch or debug registers.
972 InstructionAccurateScope scope(this);
973
974 ASSERT(AreSameSizeAndType(src0, src1, src2, src3));
975 ASSERT(size == src0.SizeInBytes());
976
977 // When pushing multiple registers, the store order is chosen such that
978 // Push(a, b) is equivalent to Push(a) followed by Push(b).
979 switch (count) {
980 case 1:
981 ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone());
982 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
983 break;
984 case 2:
985 ASSERT(src2.IsNone() && src3.IsNone());
986 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
987 break;
988 case 3:
989 ASSERT(src3.IsNone());
990 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
991 str(src0, MemOperand(StackPointer(), 2 * size));
992 break;
993 case 4:
994 // Skip over 4 * size, then fill in the gap. This allows four W registers
995 // to be pushed using csp, whilst maintaining 16-byte alignment for csp
996 // at all times.
997 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
998 stp(src1, src0, MemOperand(StackPointer(), 2 * size));
999 break;
1000 default:
1001 UNREACHABLE();
1002 }
1003 }
1004
1005
1006 void MacroAssembler::PopHelper(int count, int size,
1007 const CPURegister& dst0,
1008 const CPURegister& dst1,
1009 const CPURegister& dst2,
1010 const CPURegister& dst3) {
1011 // Ensure that we don't unintentially modify scratch or debug registers.
1012 InstructionAccurateScope scope(this);
1013
1014 ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3));
1015 ASSERT(size == dst0.SizeInBytes());
1016
1017 // When popping multiple registers, the load order is chosen such that
1018 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
1019 switch (count) {
1020 case 1:
1021 ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
1022 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
1023 break;
1024 case 2:
1025 ASSERT(dst2.IsNone() && dst3.IsNone());
1026 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
1027 break;
1028 case 3:
1029 ASSERT(dst3.IsNone());
1030 ldr(dst2, MemOperand(StackPointer(), 2 * size));
1031 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
1032 break;
1033 case 4:
1034 // Load the higher addresses first, then load the lower addresses and
1035 // skip the whole block in the second instruction. This allows four W
1036 // registers to be popped using csp, whilst maintaining 16-byte alignment
1037 // for csp at all times.
1038 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
1039 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
1040 break;
1041 default:
1042 UNREACHABLE();
1043 }
1044 }
1045
1046
1047 void MacroAssembler::PrepareForPush(Operand total_size) {
1048 // TODO(jbramley): This assertion generates too much code in some debug tests.
1049 // AssertStackConsistency();
1050 if (csp.Is(StackPointer())) {
1051 // If the current stack pointer is csp, then it must be aligned to 16 bytes
1052 // on entry and the total size of the specified registers must also be a
1053 // multiple of 16 bytes.
1054 if (total_size.IsImmediate()) {
1055 ASSERT((total_size.immediate() % 16) == 0);
1056 }
1057
1058 // Don't check access size for non-immediate sizes. It's difficult to do
1059 // well, and it will be caught by hardware (or the simulator) anyway.
1060 } else {
1061 // Even if the current stack pointer is not the system stack pointer (csp),
1062 // the system stack pointer will still be modified in order to comply with
1063 // ABI rules about accessing memory below the system stack pointer.
1064 BumpSystemStackPointer(total_size);
1065 }
1066 }
1067
1068
1069 void MacroAssembler::PrepareForPop(Operand total_size) {
1070 AssertStackConsistency();
1071 if (csp.Is(StackPointer())) {
1072 // If the current stack pointer is csp, then it must be aligned to 16 bytes
1073 // on entry and the total size of the specified registers must also be a
1074 // multiple of 16 bytes.
1075 if (total_size.IsImmediate()) {
1076 ASSERT((total_size.immediate() % 16) == 0);
1077 }
1078
1079 // Don't check access size for non-immediate sizes. It's difficult to do
1080 // well, and it will be caught by hardware (or the simulator) anyway.
1081 }
1082 }
1083
1084
1085 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) {
1086 if (offset.IsImmediate()) {
1087 ASSERT(offset.immediate() >= 0);
1088 } else if (emit_debug_code()) {
1089 Cmp(xzr, offset);
1090 Check(le, kStackAccessBelowStackPointer);
1091 }
1092
1093 Str(src, MemOperand(StackPointer(), offset));
1094 }
1095
1096
1097 void MacroAssembler::Peek(const CPURegister& dst, const Operand& offset) {
1098 if (offset.IsImmediate()) {
1099 ASSERT(offset.immediate() >= 0);
1100 } else if (emit_debug_code()) {
1101 Cmp(xzr, offset);
1102 Check(le, kStackAccessBelowStackPointer);
1103 }
1104
1105 Ldr(dst, MemOperand(StackPointer(), offset));
1106 }
1107
1108
1109 void MacroAssembler::PokePair(const CPURegister& src1,
1110 const CPURegister& src2,
1111 int offset) {
1112 ASSERT(AreSameSizeAndType(src1, src2));
1113 ASSERT((offset >= 0) && ((offset % src1.SizeInBytes()) == 0));
1114 Stp(src1, src2, MemOperand(StackPointer(), offset));
1115 }
1116
1117
1118 void MacroAssembler::PeekPair(const CPURegister& dst1,
1119 const CPURegister& dst2,
1120 int offset) {
1121 ASSERT(AreSameSizeAndType(dst1, dst2));
1122 ASSERT((offset >= 0) && ((offset % dst1.SizeInBytes()) == 0));
1123 Ldp(dst1, dst2, MemOperand(StackPointer(), offset));
1124 }
1125
1126
1127 void MacroAssembler::PushCalleeSavedRegisters() {
1128 // Ensure that the macro-assembler doesn't use any scratch registers.
1129 InstructionAccurateScope scope(this);
1130
1131 // This method must not be called unless the current stack pointer is the
1132 // system stack pointer (csp).
1133 ASSERT(csp.Is(StackPointer()));
1134
1135 MemOperand tos(csp, -2 * kXRegSize, PreIndex);
1136
1137 stp(d14, d15, tos);
1138 stp(d12, d13, tos);
1139 stp(d10, d11, tos);
1140 stp(d8, d9, tos);
1141
1142 stp(x29, x30, tos);
1143 stp(x27, x28, tos); // x28 = jssp
1144 stp(x25, x26, tos);
1145 stp(x23, x24, tos);
1146 stp(x21, x22, tos);
1147 stp(x19, x20, tos);
1148 }
1149
1150
1151 void MacroAssembler::PopCalleeSavedRegisters() {
1152 // Ensure that the macro-assembler doesn't use any scratch registers.
1153 InstructionAccurateScope scope(this);
1154
1155 // This method must not be called unless the current stack pointer is the
1156 // system stack pointer (csp).
1157 ASSERT(csp.Is(StackPointer()));
1158
1159 MemOperand tos(csp, 2 * kXRegSize, PostIndex);
1160
1161 ldp(x19, x20, tos);
1162 ldp(x21, x22, tos);
1163 ldp(x23, x24, tos);
1164 ldp(x25, x26, tos);
1165 ldp(x27, x28, tos); // x28 = jssp
1166 ldp(x29, x30, tos);
1167
1168 ldp(d8, d9, tos);
1169 ldp(d10, d11, tos);
1170 ldp(d12, d13, tos);
1171 ldp(d14, d15, tos);
1172 }
1173
1174
1175 void MacroAssembler::AssertStackConsistency() {
1176 if (emit_debug_code()) {
1177 if (csp.Is(StackPointer())) {
1178 // We can't check the alignment of csp without using a scratch register
1179 // (or clobbering the flags), but the processor (or simulator) will abort
1180 // if it is not properly aligned during a load.
1181 ldr(xzr, MemOperand(csp, 0));
1182 } else if (FLAG_enable_slow_asserts) {
1183 Label ok;
1184 // Check that csp <= StackPointer(), preserving all registers and NZCV.
1185 sub(StackPointer(), csp, StackPointer());
1186 cbz(StackPointer(), &ok); // Ok if csp == StackPointer().
1187 tbnz(StackPointer(), kXSignBit, &ok); // Ok if csp < StackPointer().
1188
1189 Abort(kTheCurrentStackPointerIsBelowCsp);
1190
1191 bind(&ok);
1192 // Restore StackPointer().
1193 sub(StackPointer(), csp, StackPointer());
1194 }
1195 }
1196 }
1197
1198
1199 void MacroAssembler::LoadRoot(Register destination,
1200 Heap::RootListIndex index) {
1201 // TODO(jbramley): Most root values are constants, and can be synthesized
1202 // without a load. Refer to the ARM back end for details.
1203 Ldr(destination, MemOperand(root, index << kPointerSizeLog2));
1204 }
1205
1206
1207 void MacroAssembler::StoreRoot(Register source,
1208 Heap::RootListIndex index) {
1209 Str(source, MemOperand(root, index << kPointerSizeLog2));
1210 }
1211
1212
1213 void MacroAssembler::LoadTrueFalseRoots(Register true_root,
1214 Register false_root) {
1215 STATIC_ASSERT((Heap::kTrueValueRootIndex + 1) == Heap::kFalseValueRootIndex);
1216 Ldp(true_root, false_root,
1217 MemOperand(root, Heap::kTrueValueRootIndex << kPointerSizeLog2));
1218 }
1219
1220
1221 void MacroAssembler::LoadHeapObject(Register result,
1222 Handle<HeapObject> object) {
1223 AllowDeferredHandleDereference using_raw_address;
1224 if (isolate()->heap()->InNewSpace(*object)) {
1225 Handle<Cell> cell = isolate()->factory()->NewCell(object);
1226 Mov(result, Operand(cell));
1227 Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
1228 } else {
1229 Mov(result, Operand(object));
1230 }
1231 }
1232
1233
1234 void MacroAssembler::LoadInstanceDescriptors(Register map,
1235 Register descriptors) {
1236 Ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
1237 }
1238
1239
1240 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
1241 Ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
1242 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
1243 }
1244
1245
1246 void MacroAssembler::EnumLengthUntagged(Register dst, Register map) {
1247 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1248 Ldrsw(dst, UntagSmiFieldMemOperand(map, Map::kBitField3Offset));
1249 And(dst, dst, Map::EnumLengthBits::kMask);
1250 }
1251
1252
1253 void MacroAssembler::EnumLengthSmi(Register dst, Register map) {
1254 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
1255 Ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
1256 And(dst, dst, Smi::FromInt(Map::EnumLengthBits::kMask));
1257 }
1258
1259
1260 void MacroAssembler::CheckEnumCache(Register object,
1261 Register null_value,
1262 Register scratch0,
1263 Register scratch1,
1264 Register scratch2,
1265 Register scratch3,
1266 Label* call_runtime) {
1267 ASSERT(!AreAliased(object, null_value, scratch0, scratch1, scratch2,
1268 scratch3));
1269
1270 Register empty_fixed_array_value = scratch0;
1271 Register current_object = scratch1;
1272
1273 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
1274 Label next, start;
1275
1276 Mov(current_object, object);
1277
1278 // Check if the enum length field is properly initialized, indicating that
1279 // there is an enum cache.
1280 Register map = scratch2;
1281 Register enum_length = scratch3;
1282 Ldr(map, FieldMemOperand(current_object, HeapObject::kMapOffset));
1283
1284 EnumLengthUntagged(enum_length, map);
1285 Cmp(enum_length, kInvalidEnumCacheSentinel);
1286 B(eq, call_runtime);
1287
1288 B(&start);
1289
1290 Bind(&next);
1291 Ldr(map, FieldMemOperand(current_object, HeapObject::kMapOffset));
1292
1293 // For all objects but the receiver, check that the cache is empty.
1294 EnumLengthUntagged(enum_length, map);
1295 Cbnz(enum_length, call_runtime);
1296
1297 Bind(&start);
1298
1299 // Check that there are no elements. Register current_object contains the
1300 // current JS object we've reached through the prototype chain.
1301 Label no_elements;
1302 Ldr(current_object, FieldMemOperand(current_object,
1303 JSObject::kElementsOffset));
1304 Cmp(current_object, empty_fixed_array_value);
1305 B(eq, &no_elements);
1306
1307 // Second chance, the object may be using the empty slow element dictionary.
1308 CompareRoot(current_object, Heap::kEmptySlowElementDictionaryRootIndex);
1309 B(ne, call_runtime);
1310
1311 Bind(&no_elements);
1312 Ldr(current_object, FieldMemOperand(map, Map::kPrototypeOffset));
1313 Cmp(current_object, null_value);
1314 B(ne, &next);
1315 }
1316
1317
1318 void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver,
1319 Register scratch1,
1320 Register scratch2,
1321 Label* no_memento_found) {
1322 ExternalReference new_space_start =
1323 ExternalReference::new_space_start(isolate());
1324 ExternalReference new_space_allocation_top =
1325 ExternalReference::new_space_allocation_top_address(isolate());
1326
1327 Add(scratch1, receiver,
1328 JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag);
1329 Cmp(scratch1, new_space_start);
1330 B(lt, no_memento_found);
1331
1332 Mov(scratch2, new_space_allocation_top);
1333 Ldr(scratch2, MemOperand(scratch2));
1334 Cmp(scratch1, scratch2);
1335 B(gt, no_memento_found);
1336
1337 Ldr(scratch1, MemOperand(scratch1, -AllocationMemento::kSize));
1338 Cmp(scratch1,
1339 Operand(isolate()->factory()->allocation_memento_map()));
1340 }
1341
1342
1343 void MacroAssembler::JumpToHandlerEntry(Register exception,
1344 Register object,
1345 Register state,
1346 Register scratch1,
1347 Register scratch2) {
1348 // Handler expects argument in x0.
1349 ASSERT(exception.Is(x0));
1350
1351 // Compute the handler entry address and jump to it. The handler table is
1352 // a fixed array of (smi-tagged) code offsets.
1353 Ldr(scratch1, FieldMemOperand(object, Code::kHandlerTableOffset));
1354 Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
1355 STATIC_ASSERT(StackHandler::kKindWidth < kPointerSizeLog2);
1356 Lsr(scratch2, state, StackHandler::kKindWidth);
1357 Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
1358 Add(scratch1, object, Code::kHeaderSize - kHeapObjectTag);
1359 Add(scratch1, scratch1, Operand::UntagSmi(scratch2));
1360 Br(scratch1);
1361 }
1362
1363
1364 void MacroAssembler::InNewSpace(Register object,
1365 Condition cond,
1366 Label* branch) {
1367 ASSERT(cond == eq || cond == ne);
1368 UseScratchRegisterScope temps(this);
1369 Register temp = temps.AcquireX();
1370 And(temp, object, ExternalReference::new_space_mask(isolate()));
1371 Cmp(temp, ExternalReference::new_space_start(isolate()));
1372 B(cond, branch);
1373 }
1374
1375
1376 void MacroAssembler::Throw(Register value,
1377 Register scratch1,
1378 Register scratch2,
1379 Register scratch3,
1380 Register scratch4) {
1381 // Adjust this code if not the case.
1382 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1383 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1384 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1385 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1386 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1387 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1388
1389 // The handler expects the exception in x0.
1390 ASSERT(value.Is(x0));
1391
1392 // Drop the stack pointer to the top of the top handler.
1393 ASSERT(jssp.Is(StackPointer()));
1394 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
1395 isolate())));
1396 Ldr(jssp, MemOperand(scratch1));
1397 // Restore the next handler.
1398 Pop(scratch2);
1399 Str(scratch2, MemOperand(scratch1));
1400
1401 // Get the code object and state. Restore the context and frame pointer.
1402 Register object = scratch1;
1403 Register state = scratch2;
1404 Pop(object, state, cp, fp);
1405
1406 // If the handler is a JS frame, restore the context to the frame.
1407 // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
1408 // or cp.
1409 Label not_js_frame;
1410 Cbz(cp, &not_js_frame);
1411 Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1412 Bind(&not_js_frame);
1413
1414 JumpToHandlerEntry(value, object, state, scratch3, scratch4);
1415 }
1416
1417
1418 void MacroAssembler::ThrowUncatchable(Register value,
1419 Register scratch1,
1420 Register scratch2,
1421 Register scratch3,
1422 Register scratch4) {
1423 // Adjust this code if not the case.
1424 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1425 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1426 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1427 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1428 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1429 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1430
1431 // The handler expects the exception in x0.
1432 ASSERT(value.Is(x0));
1433
1434 // Drop the stack pointer to the top of the top stack handler.
1435 ASSERT(jssp.Is(StackPointer()));
1436 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
1437 isolate())));
1438 Ldr(jssp, MemOperand(scratch1));
1439
1440 // Unwind the handlers until the ENTRY handler is found.
1441 Label fetch_next, check_kind;
1442 B(&check_kind);
1443 Bind(&fetch_next);
1444 Peek(jssp, StackHandlerConstants::kNextOffset);
1445
1446 Bind(&check_kind);
1447 STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
1448 Peek(scratch2, StackHandlerConstants::kStateOffset);
1449 TestAndBranchIfAnySet(scratch2, StackHandler::KindField::kMask, &fetch_next);
1450
1451 // Set the top handler address to next handler past the top ENTRY handler.
1452 Pop(scratch2);
1453 Str(scratch2, MemOperand(scratch1));
1454
1455 // Get the code object and state. Clear the context and frame pointer (0 was
1456 // saved in the handler).
1457 Register object = scratch1;
1458 Register state = scratch2;
1459 Pop(object, state, cp, fp);
1460
1461 JumpToHandlerEntry(value, object, state, scratch3, scratch4);
1462 }
1463
1464
1465 void MacroAssembler::Throw(BailoutReason reason) {
1466 Label throw_start;
1467 Bind(&throw_start);
1468 #ifdef DEBUG
1469 const char* msg = GetBailoutReason(reason);
1470 RecordComment("Throw message: ");
1471 RecordComment((msg != NULL) ? msg : "UNKNOWN");
1472 #endif
1473
1474 Mov(x0, Smi::FromInt(reason));
1475 Push(x0);
1476
1477 // Disable stub call restrictions to always allow calls to throw.
1478 if (!has_frame_) {
1479 // We don't actually want to generate a pile of code for this, so just
1480 // claim there is a stack frame, without generating one.
1481 FrameScope scope(this, StackFrame::NONE);
1482 CallRuntime(Runtime::kThrowMessage, 1);
1483 } else {
1484 CallRuntime(Runtime::kThrowMessage, 1);
1485 }
1486 // ThrowMessage should not return here.
1487 Unreachable();
1488 }
1489
1490
1491 void MacroAssembler::ThrowIf(Condition cc, BailoutReason reason) {
1492 Label ok;
1493 B(InvertCondition(cc), &ok);
1494 Throw(reason);
1495 Bind(&ok);
1496 }
1497
1498
1499 void MacroAssembler::ThrowIfSmi(const Register& value, BailoutReason reason) {
1500 Label ok;
1501 JumpIfNotSmi(value, &ok);
1502 Throw(reason);
1503 Bind(&ok);
1504 }
1505
1506
1507 void MacroAssembler::SmiAbs(const Register& smi, Label* slow) {
1508 ASSERT(smi.Is64Bits());
1509 Abs(smi, smi, slow);
1510 }
1511
1512
1513 void MacroAssembler::AssertSmi(Register object, BailoutReason reason) {
1514 if (emit_debug_code()) {
1515 STATIC_ASSERT(kSmiTag == 0);
1516 Tst(object, kSmiTagMask);
1517 Check(eq, reason);
1518 }
1519 }
1520
1521
1522 void MacroAssembler::AssertNotSmi(Register object, BailoutReason reason) {
1523 if (emit_debug_code()) {
1524 STATIC_ASSERT(kSmiTag == 0);
1525 Tst(object, kSmiTagMask);
1526 Check(ne, reason);
1527 }
1528 }
1529
1530
1531 void MacroAssembler::AssertName(Register object) {
1532 if (emit_debug_code()) {
1533 AssertNotSmi(object, kOperandIsASmiAndNotAName);
1534
1535 UseScratchRegisterScope temps(this);
1536 Register temp = temps.AcquireX();
1537
1538 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
1539 CompareInstanceType(temp, temp, LAST_NAME_TYPE);
1540 Check(ls, kOperandIsNotAName);
1541 }
1542 }
1543
1544
1545 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
1546 Register scratch) {
1547 if (emit_debug_code()) {
1548 Label done_checking;
1549 AssertNotSmi(object);
1550 JumpIfRoot(object, Heap::kUndefinedValueRootIndex, &done_checking);
1551 Ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1552 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
1553 Assert(eq, kExpectedUndefinedOrCell);
1554 Bind(&done_checking);
1555 }
1556 }
1557
1558
1559 void MacroAssembler::AssertString(Register object) {
1560 if (emit_debug_code()) {
1561 UseScratchRegisterScope temps(this);
1562 Register temp = temps.AcquireX();
1563 STATIC_ASSERT(kSmiTag == 0);
1564 Tst(object, kSmiTagMask);
1565 Check(ne, kOperandIsASmiAndNotAString);
1566 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
1567 CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE);
1568 Check(lo, kOperandIsNotAString);
1569 }
1570 }
1571
1572
1573 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
1574 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
1575 Call(stub->GetCode(isolate()), RelocInfo::CODE_TARGET, ast_id);
1576 }
1577
1578
1579 void MacroAssembler::TailCallStub(CodeStub* stub) {
1580 Jump(stub->GetCode(isolate()), RelocInfo::CODE_TARGET);
1581 }
1582
1583
1584 void MacroAssembler::CallRuntime(const Runtime::Function* f,
1585 int num_arguments,
1586 SaveFPRegsMode save_doubles) {
1587 // All arguments must be on the stack before this function is called.
1588 // x0 holds the return value after the call.
1589
1590 // Check that the number of arguments matches what the function expects.
1591 // If f->nargs is -1, the function can accept a variable number of arguments.
1592 if (f->nargs >= 0 && f->nargs != num_arguments) {
1593 // Illegal operation: drop the stack arguments and return undefined.
1594 if (num_arguments > 0) {
1595 Drop(num_arguments);
1596 }
1597 LoadRoot(x0, Heap::kUndefinedValueRootIndex);
1598 return;
1599 }
1600
1601 // Place the necessary arguments.
1602 Mov(x0, num_arguments);
1603 Mov(x1, ExternalReference(f, isolate()));
1604
1605 CEntryStub stub(1, save_doubles);
1606 CallStub(&stub);
1607 }
1608
1609
1610 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
1611 return ref0.address() - ref1.address();
1612 }
1613
1614
1615 void MacroAssembler::CallApiFunctionAndReturn(
1616 Register function_address,
1617 ExternalReference thunk_ref,
1618 int stack_space,
1619 int spill_offset,
1620 MemOperand return_value_operand,
1621 MemOperand* context_restore_operand) {
1622 ASM_LOCATION("CallApiFunctionAndReturn");
1623 ExternalReference next_address =
1624 ExternalReference::handle_scope_next_address(isolate());
1625 const int kNextOffset = 0;
1626 const int kLimitOffset = AddressOffset(
1627 ExternalReference::handle_scope_limit_address(isolate()),
1628 next_address);
1629 const int kLevelOffset = AddressOffset(
1630 ExternalReference::handle_scope_level_address(isolate()),
1631 next_address);
1632
1633 ASSERT(function_address.is(x1) || function_address.is(x2));
1634
1635 Label profiler_disabled;
1636 Label end_profiler_check;
1637 bool* is_profiling_flag = isolate()->cpu_profiler()->is_profiling_address();
1638 STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
1639 Mov(x10, reinterpret_cast<uintptr_t>(is_profiling_flag));
1640 Ldrb(w10, MemOperand(x10));
1641 Cbz(w10, &profiler_disabled);
1642 Mov(x3, thunk_ref);
1643 B(&end_profiler_check);
1644
1645 Bind(&profiler_disabled);
1646 Mov(x3, function_address);
1647 Bind(&end_profiler_check);
1648
1649 // Save the callee-save registers we are going to use.
1650 // TODO(all): Is this necessary? ARM doesn't do it.
1651 STATIC_ASSERT(kCallApiFunctionSpillSpace == 4);
1652 Poke(x19, (spill_offset + 0) * kXRegSize);
1653 Poke(x20, (spill_offset + 1) * kXRegSize);
1654 Poke(x21, (spill_offset + 2) * kXRegSize);
1655 Poke(x22, (spill_offset + 3) * kXRegSize);
1656
1657 // Allocate HandleScope in callee-save registers.
1658 // We will need to restore the HandleScope after the call to the API function,
1659 // by allocating it in callee-save registers they will be preserved by C code.
1660 Register handle_scope_base = x22;
1661 Register next_address_reg = x19;
1662 Register limit_reg = x20;
1663 Register level_reg = w21;
1664
1665 Mov(handle_scope_base, next_address);
1666 Ldr(next_address_reg, MemOperand(handle_scope_base, kNextOffset));
1667 Ldr(limit_reg, MemOperand(handle_scope_base, kLimitOffset));
1668 Ldr(level_reg, MemOperand(handle_scope_base, kLevelOffset));
1669 Add(level_reg, level_reg, 1);
1670 Str(level_reg, MemOperand(handle_scope_base, kLevelOffset));
1671
1672 if (FLAG_log_timer_events) {
1673 FrameScope frame(this, StackFrame::MANUAL);
1674 PushSafepointRegisters();
1675 Mov(x0, ExternalReference::isolate_address(isolate()));
1676 CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
1677 PopSafepointRegisters();
1678 }
1679
1680 // Native call returns to the DirectCEntry stub which redirects to the
1681 // return address pushed on stack (could have moved after GC).
1682 // DirectCEntry stub itself is generated early and never moves.
1683 DirectCEntryStub stub;
1684 stub.GenerateCall(this, x3);
1685
1686 if (FLAG_log_timer_events) {
1687 FrameScope frame(this, StackFrame::MANUAL);
1688 PushSafepointRegisters();
1689 Mov(x0, ExternalReference::isolate_address(isolate()));
1690 CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
1691 PopSafepointRegisters();
1692 }
1693
1694 Label promote_scheduled_exception;
1695 Label exception_handled;
1696 Label delete_allocated_handles;
1697 Label leave_exit_frame;
1698 Label return_value_loaded;
1699
1700 // Load value from ReturnValue.
1701 Ldr(x0, return_value_operand);
1702 Bind(&return_value_loaded);
1703 // No more valid handles (the result handle was the last one). Restore
1704 // previous handle scope.
1705 Str(next_address_reg, MemOperand(handle_scope_base, kNextOffset));
1706 if (emit_debug_code()) {
1707 Ldr(w1, MemOperand(handle_scope_base, kLevelOffset));
1708 Cmp(w1, level_reg);
1709 Check(eq, kUnexpectedLevelAfterReturnFromApiCall);
1710 }
1711 Sub(level_reg, level_reg, 1);
1712 Str(level_reg, MemOperand(handle_scope_base, kLevelOffset));
1713 Ldr(x1, MemOperand(handle_scope_base, kLimitOffset));
1714 Cmp(limit_reg, x1);
1715 B(ne, &delete_allocated_handles);
1716
1717 Bind(&leave_exit_frame);
1718 // Restore callee-saved registers.
1719 Peek(x19, (spill_offset + 0) * kXRegSize);
1720 Peek(x20, (spill_offset + 1) * kXRegSize);
1721 Peek(x21, (spill_offset + 2) * kXRegSize);
1722 Peek(x22, (spill_offset + 3) * kXRegSize);
1723
1724 // Check if the function scheduled an exception.
1725 Mov(x5, ExternalReference::scheduled_exception_address(isolate()));
1726 Ldr(x5, MemOperand(x5));
1727 JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex, &promote_scheduled_exception);
1728 Bind(&exception_handled);
1729
1730 bool restore_context = context_restore_operand != NULL;
1731 if (restore_context) {
1732 Ldr(cp, *context_restore_operand);
1733 }
1734
1735 LeaveExitFrame(false, x1, !restore_context);
1736 Drop(stack_space);
1737 Ret();
1738
1739 Bind(&promote_scheduled_exception);
1740 {
1741 FrameScope frame(this, StackFrame::INTERNAL);
1742 CallExternalReference(
1743 ExternalReference(Runtime::kPromoteScheduledException, isolate()), 0);
1744 }
1745 B(&exception_handled);
1746
1747 // HandleScope limit has changed. Delete allocated extensions.
1748 Bind(&delete_allocated_handles);
1749 Str(limit_reg, MemOperand(handle_scope_base, kLimitOffset));
1750 // Save the return value in a callee-save register.
1751 Register saved_result = x19;
1752 Mov(saved_result, x0);
1753 Mov(x0, ExternalReference::isolate_address(isolate()));
1754 CallCFunction(
1755 ExternalReference::delete_handle_scope_extensions(isolate()), 1);
1756 Mov(x0, saved_result);
1757 B(&leave_exit_frame);
1758 }
1759
1760
1761 void MacroAssembler::CallExternalReference(const ExternalReference& ext,
1762 int num_arguments) {
1763 Mov(x0, num_arguments);
1764 Mov(x1, ext);
1765
1766 CEntryStub stub(1);
1767 CallStub(&stub);
1768 }
1769
1770
1771 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
1772 Mov(x1, builtin);
1773 CEntryStub stub(1);
1774 Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
1775 }
1776
1777
1778 void MacroAssembler::GetBuiltinFunction(Register target,
1779 Builtins::JavaScript id) {
1780 // Load the builtins object into target register.
1781 Ldr(target, GlobalObjectMemOperand());
1782 Ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
1783 // Load the JavaScript builtin function from the builtins object.
1784 Ldr(target, FieldMemOperand(target,
1785 JSBuiltinsObject::OffsetOfFunctionWithId(id)));
1786 }
1787
1788
1789 void MacroAssembler::GetBuiltinEntry(Register target,
1790 Register function,
1791 Builtins::JavaScript id) {
1792 ASSERT(!AreAliased(target, function));
1793 GetBuiltinFunction(function, id);
1794 // Load the code entry point from the builtins object.
1795 Ldr(target, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1796 }
1797
1798
1799 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
1800 InvokeFlag flag,
1801 const CallWrapper& call_wrapper) {
1802 ASM_LOCATION("MacroAssembler::InvokeBuiltin");
1803 // You can't call a builtin without a valid frame.
1804 ASSERT(flag == JUMP_FUNCTION || has_frame());
1805
1806 // Get the builtin entry in x2 and setup the function object in x1.
1807 GetBuiltinEntry(x2, x1, id);
1808 if (flag == CALL_FUNCTION) {
1809 call_wrapper.BeforeCall(CallSize(x2));
1810 Call(x2);
1811 call_wrapper.AfterCall();
1812 } else {
1813 ASSERT(flag == JUMP_FUNCTION);
1814 Jump(x2);
1815 }
1816 }
1817
1818
1819 void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
1820 int num_arguments,
1821 int result_size) {
1822 // TODO(1236192): Most runtime routines don't need the number of
1823 // arguments passed in because it is constant. At some point we
1824 // should remove this need and make the runtime routine entry code
1825 // smarter.
1826 Mov(x0, num_arguments);
1827 JumpToExternalReference(ext);
1828 }
1829
1830
1831 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
1832 int num_arguments,
1833 int result_size) {
1834 TailCallExternalReference(ExternalReference(fid, isolate()),
1835 num_arguments,
1836 result_size);
1837 }
1838
1839
1840 void MacroAssembler::InitializeNewString(Register string,
1841 Register length,
1842 Heap::RootListIndex map_index,
1843 Register scratch1,
1844 Register scratch2) {
1845 ASSERT(!AreAliased(string, length, scratch1, scratch2));
1846 LoadRoot(scratch2, map_index);
1847 SmiTag(scratch1, length);
1848 Str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
1849
1850 Mov(scratch2, String::kEmptyHashField);
1851 Str(scratch1, FieldMemOperand(string, String::kLengthOffset));
1852 Str(scratch2, FieldMemOperand(string, String::kHashFieldOffset));
1853 }
1854
1855
1856 int MacroAssembler::ActivationFrameAlignment() {
1857 #if V8_HOST_ARCH_A64
1858 // Running on the real platform. Use the alignment as mandated by the local
1859 // environment.
1860 // Note: This will break if we ever start generating snapshots on one ARM
1861 // platform for another ARM platform with a different alignment.
1862 return OS::ActivationFrameAlignment();
1863 #else // V8_HOST_ARCH_A64
1864 // If we are using the simulator then we should always align to the expected
1865 // alignment. As the simulator is used to generate snapshots we do not know
1866 // if the target platform will need alignment, so this is controlled from a
1867 // flag.
1868 return FLAG_sim_stack_alignment;
1869 #endif // V8_HOST_ARCH_A64
1870 }
1871
1872
1873 void MacroAssembler::CallCFunction(ExternalReference function,
1874 int num_of_reg_args) {
1875 CallCFunction(function, num_of_reg_args, 0);
1876 }
1877
1878
1879 void MacroAssembler::CallCFunction(ExternalReference function,
1880 int num_of_reg_args,
1881 int num_of_double_args) {
1882 UseScratchRegisterScope temps(this);
1883 Register temp = temps.AcquireX();
1884 Mov(temp, function);
1885 CallCFunction(temp, num_of_reg_args, num_of_double_args);
1886 }
1887
1888
1889 void MacroAssembler::CallCFunction(Register function,
1890 int num_of_reg_args,
1891 int num_of_double_args) {
1892 ASSERT(has_frame());
1893 // We can pass 8 integer arguments in registers. If we need to pass more than
1894 // that, we'll need to implement support for passing them on the stack.
1895 ASSERT(num_of_reg_args <= 8);
1896
1897 // If we're passing doubles, we're limited to the following prototypes
1898 // (defined by ExternalReference::Type):
1899 // BUILTIN_COMPARE_CALL: int f(double, double)
1900 // BUILTIN_FP_FP_CALL: double f(double, double)
1901 // BUILTIN_FP_CALL: double f(double)
1902 // BUILTIN_FP_INT_CALL: double f(double, int)
1903 if (num_of_double_args > 0) {
1904 ASSERT(num_of_reg_args <= 1);
1905 ASSERT((num_of_double_args + num_of_reg_args) <= 2);
1906 }
1907
1908
1909 // If the stack pointer is not csp, we need to derive an aligned csp from the
1910 // current stack pointer.
1911 const Register old_stack_pointer = StackPointer();
1912 if (!csp.Is(old_stack_pointer)) {
1913 AssertStackConsistency();
1914
1915 int sp_alignment = ActivationFrameAlignment();
1916 // The ABI mandates at least 16-byte alignment.
1917 ASSERT(sp_alignment >= 16);
1918 ASSERT(IsPowerOf2(sp_alignment));
1919
1920 // The current stack pointer is a callee saved register, and is preserved
1921 // across the call.
1922 ASSERT(kCalleeSaved.IncludesAliasOf(old_stack_pointer));
1923
1924 // Align and synchronize the system stack pointer with jssp.
1925 Bic(csp, old_stack_pointer, sp_alignment - 1);
1926 SetStackPointer(csp);
1927 }
1928
1929 // Call directly. The function called cannot cause a GC, or allow preemption,
1930 // so the return address in the link register stays correct.
1931 Call(function);
1932
1933 if (!csp.Is(old_stack_pointer)) {
1934 if (emit_debug_code()) {
1935 // Because the stack pointer must be aligned on a 16-byte boundary, the
1936 // aligned csp can be up to 12 bytes below the jssp. This is the case
1937 // where we only pushed one W register on top of an aligned jssp.
1938 UseScratchRegisterScope temps(this);
1939 Register temp = temps.AcquireX();
1940 ASSERT(ActivationFrameAlignment() == 16);
1941 Sub(temp, csp, old_stack_pointer);
1942 // We want temp <= 0 && temp >= -12.
1943 Cmp(temp, 0);
1944 Ccmp(temp, -12, NFlag, le);
1945 Check(ge, kTheStackWasCorruptedByMacroAssemblerCall);
1946 }
1947 SetStackPointer(old_stack_pointer);
1948 }
1949 }
1950
1951
1952 void MacroAssembler::Jump(Register target) {
1953 Br(target);
1954 }
1955
1956
1957 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode) {
1958 UseScratchRegisterScope temps(this);
1959 Register temp = temps.AcquireX();
1960 Mov(temp, Operand(target, rmode));
1961 Br(temp);
1962 }
1963
1964
1965 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode) {
1966 ASSERT(!RelocInfo::IsCodeTarget(rmode));
1967 Jump(reinterpret_cast<intptr_t>(target), rmode);
1968 }
1969
1970
1971 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode) {
1972 ASSERT(RelocInfo::IsCodeTarget(rmode));
1973 AllowDeferredHandleDereference embedding_raw_address;
1974 Jump(reinterpret_cast<intptr_t>(code.location()), rmode);
1975 }
1976
1977
1978 void MacroAssembler::Call(Register target) {
1979 BlockPoolsScope scope(this);
1980 #ifdef DEBUG
1981 Label start_call;
1982 Bind(&start_call);
1983 #endif
1984
1985 Blr(target);
1986
1987 #ifdef DEBUG
1988 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target));
1989 #endif
1990 }
1991
1992
1993 void MacroAssembler::Call(Label* target) {
1994 BlockPoolsScope scope(this);
1995 #ifdef DEBUG
1996 Label start_call;
1997 Bind(&start_call);
1998 #endif
1999
2000 Bl(target);
2001
2002 #ifdef DEBUG
2003 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target));
2004 #endif
2005 }
2006
2007
2008 // MacroAssembler::CallSize is sensitive to changes in this function, as it
2009 // requires to know how many instructions are used to branch to the target.
2010 void MacroAssembler::Call(Address target, RelocInfo::Mode rmode) {
2011 BlockPoolsScope scope(this);
2012 #ifdef DEBUG
2013 Label start_call;
2014 Bind(&start_call);
2015 #endif
2016 // Statement positions are expected to be recorded when the target
2017 // address is loaded.
2018 positions_recorder()->WriteRecordedPositions();
2019
2020 // Addresses always have 64 bits, so we shouldn't encounter NONE32.
2021 ASSERT(rmode != RelocInfo::NONE32);
2022
2023 UseScratchRegisterScope temps(this);
2024 Register temp = temps.AcquireX();
2025
2026 if (rmode == RelocInfo::NONE64) {
2027 uint64_t imm = reinterpret_cast<uint64_t>(target);
2028 movz(temp, (imm >> 0) & 0xffff, 0);
2029 movk(temp, (imm >> 16) & 0xffff, 16);
2030 movk(temp, (imm >> 32) & 0xffff, 32);
2031 movk(temp, (imm >> 48) & 0xffff, 48);
2032 } else {
2033 LoadRelocated(temp, Operand(reinterpret_cast<intptr_t>(target), rmode));
2034 }
2035 Blr(temp);
2036 #ifdef DEBUG
2037 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target, rmode));
2038 #endif
2039 }
2040
2041
2042 void MacroAssembler::Call(Handle<Code> code,
2043 RelocInfo::Mode rmode,
2044 TypeFeedbackId ast_id) {
2045 #ifdef DEBUG
2046 Label start_call;
2047 Bind(&start_call);
2048 #endif
2049
2050 if ((rmode == RelocInfo::CODE_TARGET) && (!ast_id.IsNone())) {
2051 SetRecordedAstId(ast_id);
2052 rmode = RelocInfo::CODE_TARGET_WITH_ID;
2053 }
2054
2055 AllowDeferredHandleDereference embedding_raw_address;
2056 Call(reinterpret_cast<Address>(code.location()), rmode);
2057
2058 #ifdef DEBUG
2059 // Check the size of the code generated.
2060 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(code, rmode, ast_id));
2061 #endif
2062 }
2063
2064
2065 int MacroAssembler::CallSize(Register target) {
2066 USE(target);
2067 return kInstructionSize;
2068 }
2069
2070
2071 int MacroAssembler::CallSize(Label* target) {
2072 USE(target);
2073 return kInstructionSize;
2074 }
2075
2076
2077 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode) {
2078 USE(target);
2079
2080 // Addresses always have 64 bits, so we shouldn't encounter NONE32.
2081 ASSERT(rmode != RelocInfo::NONE32);
2082
2083 if (rmode == RelocInfo::NONE64) {
2084 return kCallSizeWithoutRelocation;
2085 } else {
2086 return kCallSizeWithRelocation;
2087 }
2088 }
2089
2090
2091 int MacroAssembler::CallSize(Handle<Code> code,
2092 RelocInfo::Mode rmode,
2093 TypeFeedbackId ast_id) {
2094 USE(code);
2095 USE(ast_id);
2096
2097 // Addresses always have 64 bits, so we shouldn't encounter NONE32.
2098 ASSERT(rmode != RelocInfo::NONE32);
2099
2100 if (rmode == RelocInfo::NONE64) {
2101 return kCallSizeWithoutRelocation;
2102 } else {
2103 return kCallSizeWithRelocation;
2104 }
2105 }
2106
2107
2108
2109
2110
2111 void MacroAssembler::JumpForHeapNumber(Register object,
2112 Register heap_number_map,
2113 Label* on_heap_number,
2114 Label* on_not_heap_number) {
2115 ASSERT(on_heap_number || on_not_heap_number);
2116 AssertNotSmi(object);
2117
2118 UseScratchRegisterScope temps(this);
2119 Register temp = temps.AcquireX();
2120
2121 // Load the HeapNumber map if it is not passed.
2122 if (heap_number_map.Is(NoReg)) {
2123 heap_number_map = temps.AcquireX();
2124 LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2125 } else {
2126 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2127 }
2128
2129 ASSERT(!AreAliased(temp, heap_number_map));
2130
2131 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
2132 Cmp(temp, heap_number_map);
2133
2134 if (on_heap_number) {
2135 B(eq, on_heap_number);
2136 }
2137 if (on_not_heap_number) {
2138 B(ne, on_not_heap_number);
2139 }
2140 }
2141
2142
2143 void MacroAssembler::JumpIfHeapNumber(Register object,
2144 Label* on_heap_number,
2145 Register heap_number_map) {
2146 JumpForHeapNumber(object,
2147 heap_number_map,
2148 on_heap_number,
2149 NULL);
2150 }
2151
2152
2153 void MacroAssembler::JumpIfNotHeapNumber(Register object,
2154 Label* on_not_heap_number,
2155 Register heap_number_map) {
2156 JumpForHeapNumber(object,
2157 heap_number_map,
2158 NULL,
2159 on_not_heap_number);
2160 }
2161
2162
2163 void MacroAssembler::LookupNumberStringCache(Register object,
2164 Register result,
2165 Register scratch1,
2166 Register scratch2,
2167 Register scratch3,
2168 Label* not_found) {
2169 ASSERT(!AreAliased(object, result, scratch1, scratch2, scratch3));
2170
2171 // Use of registers. Register result is used as a temporary.
2172 Register number_string_cache = result;
2173 Register mask = scratch3;
2174
2175 // Load the number string cache.
2176 LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
2177
2178 // Make the hash mask from the length of the number string cache. It
2179 // contains two elements (number and string) for each cache entry.
2180 Ldrsw(mask, UntagSmiFieldMemOperand(number_string_cache,
2181 FixedArray::kLengthOffset));
2182 Asr(mask, mask, 1); // Divide length by two.
2183 Sub(mask, mask, 1); // Make mask.
2184
2185 // Calculate the entry in the number string cache. The hash value in the
2186 // number string cache for smis is just the smi value, and the hash for
2187 // doubles is the xor of the upper and lower words. See
2188 // Heap::GetNumberStringCache.
2189 Label is_smi;
2190 Label load_result_from_cache;
2191
2192 JumpIfSmi(object, &is_smi);
2193 CheckMap(object, scratch1, Heap::kHeapNumberMapRootIndex, not_found,
2194 DONT_DO_SMI_CHECK);
2195
2196 STATIC_ASSERT(kDoubleSize == (kWRegSize * 2));
2197 Add(scratch1, object, HeapNumber::kValueOffset - kHeapObjectTag);
2198 Ldp(scratch1.W(), scratch2.W(), MemOperand(scratch1));
2199 Eor(scratch1, scratch1, scratch2);
2200 And(scratch1, scratch1, mask);
2201
2202 // Calculate address of entry in string cache: each entry consists of two
2203 // pointer sized fields.
2204 Add(scratch1, number_string_cache,
2205 Operand(scratch1, LSL, kPointerSizeLog2 + 1));
2206
2207 Register probe = mask;
2208 Ldr(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
2209 JumpIfSmi(probe, not_found);
2210 Ldr(d0, FieldMemOperand(object, HeapNumber::kValueOffset));
2211 Ldr(d1, FieldMemOperand(probe, HeapNumber::kValueOffset));
2212 Fcmp(d0, d1);
2213 B(ne, not_found);
2214 B(&load_result_from_cache);
2215
2216 Bind(&is_smi);
2217 Register scratch = scratch1;
2218 And(scratch, mask, Operand::UntagSmi(object));
2219 // Calculate address of entry in string cache: each entry consists
2220 // of two pointer sized fields.
2221 Add(scratch, number_string_cache,
2222 Operand(scratch, LSL, kPointerSizeLog2 + 1));
2223
2224 // Check if the entry is the smi we are looking for.
2225 Ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
2226 Cmp(object, probe);
2227 B(ne, not_found);
2228
2229 // Get the result from the cache.
2230 Bind(&load_result_from_cache);
2231 Ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
2232 IncrementCounter(isolate()->counters()->number_to_string_native(), 1,
2233 scratch1, scratch2);
2234 }
2235
2236
2237 void MacroAssembler::TryConvertDoubleToInt(Register as_int,
2238 FPRegister value,
2239 FPRegister scratch_d,
2240 Label* on_successful_conversion,
2241 Label* on_failed_conversion) {
2242 // Convert to an int and back again, then compare with the original value.
2243 Fcvtzs(as_int, value);
2244 Scvtf(scratch_d, as_int);
2245 Fcmp(value, scratch_d);
2246
2247 if (on_successful_conversion) {
2248 B(on_successful_conversion, eq);
2249 }
2250 if (on_failed_conversion) {
2251 B(on_failed_conversion, ne);
2252 }
2253 }
2254
2255
2256 void MacroAssembler::TestForMinusZero(DoubleRegister input) {
2257 UseScratchRegisterScope temps(this);
2258 Register temp = temps.AcquireX();
2259 // Floating point -0.0 is kMinInt as an integer, so subtracting 1 (cmp) will
2260 // cause overflow.
2261 Fmov(temp, input);
2262 Cmp(temp, 1);
2263 }
2264
2265
2266 void MacroAssembler::JumpIfMinusZero(DoubleRegister input,
2267 Label* on_negative_zero) {
2268 TestForMinusZero(input);
2269 B(vs, on_negative_zero);
2270 }
2271
2272
2273 void MacroAssembler::ClampInt32ToUint8(Register output, Register input) {
2274 // Clamp the value to [0..255].
2275 Cmp(input.W(), Operand(input.W(), UXTB));
2276 // If input < input & 0xff, it must be < 0, so saturate to 0.
2277 Csel(output.W(), wzr, input.W(), lt);
2278 // If input <= input & 0xff, it must be <= 255. Otherwise, saturate to 255.
2279 Csel(output.W(), output.W(), 255, le);
2280 }
2281
2282
2283 void MacroAssembler::ClampInt32ToUint8(Register in_out) {
2284 ClampInt32ToUint8(in_out, in_out);
2285 }
2286
2287
2288 void MacroAssembler::ClampDoubleToUint8(Register output,
2289 DoubleRegister input,
2290 DoubleRegister dbl_scratch) {
2291 // This conversion follows the WebIDL "[Clamp]" rules for PIXEL types:
2292 // - Inputs lower than 0 (including -infinity) produce 0.
2293 // - Inputs higher than 255 (including +infinity) produce 255.
2294 // Also, it seems that PIXEL types use round-to-nearest rather than
2295 // round-towards-zero.
2296
2297 // Squash +infinity before the conversion, since Fcvtnu will normally
2298 // convert it to 0.
2299 Fmov(dbl_scratch, 255);
2300 Fmin(dbl_scratch, dbl_scratch, input);
2301
2302 // Convert double to unsigned integer. Values less than zero become zero.
2303 // Values greater than 255 have already been clamped to 255.
2304 Fcvtnu(output, dbl_scratch);
2305 }
2306
2307
2308 void MacroAssembler::CopyFieldsLoopPairsHelper(Register dst,
2309 Register src,
2310 unsigned count,
2311 Register scratch1,
2312 Register scratch2,
2313 Register scratch3,
2314 Register scratch4,
2315 Register scratch5) {
2316 // Untag src and dst into scratch registers.
2317 // Copy src->dst in a tight loop.
2318 ASSERT(!AreAliased(dst, src,
2319 scratch1, scratch2, scratch3, scratch4, scratch5));
2320 ASSERT(count >= 2);
2321
2322 const Register& remaining = scratch3;
2323 Mov(remaining, count / 2);
2324
2325 const Register& dst_untagged = scratch1;
2326 const Register& src_untagged = scratch2;
2327 Sub(dst_untagged, dst, kHeapObjectTag);
2328 Sub(src_untagged, src, kHeapObjectTag);
2329
2330 // Copy fields in pairs.
2331 Label loop;
2332 Bind(&loop);
2333 Ldp(scratch4, scratch5,
2334 MemOperand(src_untagged, kXRegSize* 2, PostIndex));
2335 Stp(scratch4, scratch5,
2336 MemOperand(dst_untagged, kXRegSize* 2, PostIndex));
2337 Sub(remaining, remaining, 1);
2338 Cbnz(remaining, &loop);
2339
2340 // Handle the leftovers.
2341 if (count & 1) {
2342 Ldr(scratch4, MemOperand(src_untagged));
2343 Str(scratch4, MemOperand(dst_untagged));
2344 }
2345 }
2346
2347
2348 void MacroAssembler::CopyFieldsUnrolledPairsHelper(Register dst,
2349 Register src,
2350 unsigned count,
2351 Register scratch1,
2352 Register scratch2,
2353 Register scratch3,
2354 Register scratch4) {
2355 // Untag src and dst into scratch registers.
2356 // Copy src->dst in an unrolled loop.
2357 ASSERT(!AreAliased(dst, src, scratch1, scratch2, scratch3, scratch4));
2358
2359 const Register& dst_untagged = scratch1;
2360 const Register& src_untagged = scratch2;
2361 sub(dst_untagged, dst, kHeapObjectTag);
2362 sub(src_untagged, src, kHeapObjectTag);
2363
2364 // Copy fields in pairs.
2365 for (unsigned i = 0; i < count / 2; i++) {
2366 Ldp(scratch3, scratch4, MemOperand(src_untagged, kXRegSize * 2, PostIndex));
2367 Stp(scratch3, scratch4, MemOperand(dst_untagged, kXRegSize * 2, PostIndex));
2368 }
2369
2370 // Handle the leftovers.
2371 if (count & 1) {
2372 Ldr(scratch3, MemOperand(src_untagged));
2373 Str(scratch3, MemOperand(dst_untagged));
2374 }
2375 }
2376
2377
2378 void MacroAssembler::CopyFieldsUnrolledHelper(Register dst,
2379 Register src,
2380 unsigned count,
2381 Register scratch1,
2382 Register scratch2,
2383 Register scratch3) {
2384 // Untag src and dst into scratch registers.
2385 // Copy src->dst in an unrolled loop.
2386 ASSERT(!AreAliased(dst, src, scratch1, scratch2, scratch3));
2387
2388 const Register& dst_untagged = scratch1;
2389 const Register& src_untagged = scratch2;
2390 Sub(dst_untagged, dst, kHeapObjectTag);
2391 Sub(src_untagged, src, kHeapObjectTag);
2392
2393 // Copy fields one by one.
2394 for (unsigned i = 0; i < count; i++) {
2395 Ldr(scratch3, MemOperand(src_untagged, kXRegSize, PostIndex));
2396 Str(scratch3, MemOperand(dst_untagged, kXRegSize, PostIndex));
2397 }
2398 }
2399
2400
2401 void MacroAssembler::CopyFields(Register dst, Register src, CPURegList temps,
2402 unsigned count) {
2403 // One of two methods is used:
2404 //
2405 // For high 'count' values where many scratch registers are available:
2406 // Untag src and dst into scratch registers.
2407 // Copy src->dst in a tight loop.
2408 //
2409 // For low 'count' values or where few scratch registers are available:
2410 // Untag src and dst into scratch registers.
2411 // Copy src->dst in an unrolled loop.
2412 //
2413 // In both cases, fields are copied in pairs if possible, and left-overs are
2414 // handled separately.
2415 ASSERT(!AreAliased(dst, src));
2416 ASSERT(!temps.IncludesAliasOf(dst));
2417 ASSERT(!temps.IncludesAliasOf(src));
2418 ASSERT(!temps.IncludesAliasOf(xzr));
2419
2420 if (emit_debug_code()) {
2421 Cmp(dst, src);
2422 Check(ne, kTheSourceAndDestinationAreTheSame);
2423 }
2424
2425 // The value of 'count' at which a loop will be generated (if there are
2426 // enough scratch registers).
2427 static const unsigned kLoopThreshold = 8;
2428
2429 UseScratchRegisterScope masm_temps(this);
2430 if ((temps.Count() >= 3) && (count >= kLoopThreshold)) {
2431 CopyFieldsLoopPairsHelper(dst, src, count,
2432 Register(temps.PopLowestIndex()),
2433 Register(temps.PopLowestIndex()),
2434 Register(temps.PopLowestIndex()),
2435 masm_temps.AcquireX(),
2436 masm_temps.AcquireX());
2437 } else if (temps.Count() >= 2) {
2438 CopyFieldsUnrolledPairsHelper(dst, src, count,
2439 Register(temps.PopLowestIndex()),
2440 Register(temps.PopLowestIndex()),
2441 masm_temps.AcquireX(),
2442 masm_temps.AcquireX());
2443 } else if (temps.Count() == 1) {
2444 CopyFieldsUnrolledHelper(dst, src, count,
2445 Register(temps.PopLowestIndex()),
2446 masm_temps.AcquireX(),
2447 masm_temps.AcquireX());
2448 } else {
2449 UNREACHABLE();
2450 }
2451 }
2452
2453
2454 void MacroAssembler::CopyBytes(Register dst,
2455 Register src,
2456 Register length,
2457 Register scratch,
2458 CopyHint hint) {
2459 UseScratchRegisterScope temps(this);
2460 Register tmp1 = temps.AcquireX();
2461 Register tmp2 = temps.AcquireX();
2462 ASSERT(!AreAliased(src, dst, length, scratch, tmp1, tmp2));
2463 ASSERT(!AreAliased(src, dst, csp));
2464
2465 if (emit_debug_code()) {
2466 // Check copy length.
2467 Cmp(length, 0);
2468 Assert(ge, kUnexpectedNegativeValue);
2469
2470 // Check src and dst buffers don't overlap.
2471 Add(scratch, src, length); // Calculate end of src buffer.
2472 Cmp(scratch, dst);
2473 Add(scratch, dst, length); // Calculate end of dst buffer.
2474 Ccmp(scratch, src, ZFlag, gt);
2475 Assert(le, kCopyBuffersOverlap);
2476 }
2477
2478 Label short_copy, short_loop, bulk_loop, done;
2479
2480 if ((hint == kCopyLong || hint == kCopyUnknown) && !FLAG_optimize_for_size) {
2481 Register bulk_length = scratch;
2482 int pair_size = 2 * kXRegSize;
2483 int pair_mask = pair_size - 1;
2484
2485 Bic(bulk_length, length, pair_mask);
2486 Cbz(bulk_length, &short_copy);
2487 Bind(&bulk_loop);
2488 Sub(bulk_length, bulk_length, pair_size);
2489 Ldp(tmp1, tmp2, MemOperand(src, pair_size, PostIndex));
2490 Stp(tmp1, tmp2, MemOperand(dst, pair_size, PostIndex));
2491 Cbnz(bulk_length, &bulk_loop);
2492
2493 And(length, length, pair_mask);
2494 }
2495
2496 Bind(&short_copy);
2497 Cbz(length, &done);
2498 Bind(&short_loop);
2499 Sub(length, length, 1);
2500 Ldrb(tmp1, MemOperand(src, 1, PostIndex));
2501 Strb(tmp1, MemOperand(dst, 1, PostIndex));
2502 Cbnz(length, &short_loop);
2503
2504
2505 Bind(&done);
2506 }
2507
2508
2509 void MacroAssembler::FillFields(Register dst,
2510 Register field_count,
2511 Register filler) {
2512 ASSERT(!dst.Is(csp));
2513 UseScratchRegisterScope temps(this);
2514 Register field_ptr = temps.AcquireX();
2515 Register counter = temps.AcquireX();
2516 Label done;
2517
2518 // Decrement count. If the result < zero, count was zero, and there's nothing
2519 // to do. If count was one, flags are set to fail the gt condition at the end
2520 // of the pairs loop.
2521 Subs(counter, field_count, 1);
2522 B(lt, &done);
2523
2524 // There's at least one field to fill, so do this unconditionally.
2525 Str(filler, MemOperand(dst, kPointerSize, PostIndex));
2526
2527 // If the bottom bit of counter is set, there are an even number of fields to
2528 // fill, so pull the start pointer back by one field, allowing the pairs loop
2529 // to overwrite the field that was stored above.
2530 And(field_ptr, counter, 1);
2531 Sub(field_ptr, dst, Operand(field_ptr, LSL, kPointerSizeLog2));
2532
2533 // Store filler to memory in pairs.
2534 Label entry, loop;
2535 B(&entry);
2536 Bind(&loop);
2537 Stp(filler, filler, MemOperand(field_ptr, 2 * kPointerSize, PostIndex));
2538 Subs(counter, counter, 2);
2539 Bind(&entry);
2540 B(gt, &loop);
2541
2542 Bind(&done);
2543 }
2544
2545
2546 void MacroAssembler::JumpIfEitherIsNotSequentialAsciiStrings(
2547 Register first,
2548 Register second,
2549 Register scratch1,
2550 Register scratch2,
2551 Label* failure,
2552 SmiCheckType smi_check) {
2553
2554 if (smi_check == DO_SMI_CHECK) {
2555 JumpIfEitherSmi(first, second, failure);
2556 } else if (emit_debug_code()) {
2557 ASSERT(smi_check == DONT_DO_SMI_CHECK);
2558 Label not_smi;
2559 JumpIfEitherSmi(first, second, NULL, &not_smi);
2560
2561 // At least one input is a smi, but the flags indicated a smi check wasn't
2562 // needed.
2563 Abort(kUnexpectedSmi);
2564
2565 Bind(&not_smi);
2566 }
2567
2568 // Test that both first and second are sequential ASCII strings.
2569 Ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
2570 Ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
2571 Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
2572 Ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
2573
2574 JumpIfEitherInstanceTypeIsNotSequentialAscii(scratch1,
2575 scratch2,
2576 scratch1,
2577 scratch2,
2578 failure);
2579 }
2580
2581
2582 void MacroAssembler::JumpIfEitherInstanceTypeIsNotSequentialAscii(
2583 Register first,
2584 Register second,
2585 Register scratch1,
2586 Register scratch2,
2587 Label* failure) {
2588 ASSERT(!AreAliased(scratch1, second));
2589 ASSERT(!AreAliased(scratch1, scratch2));
2590 static const int kFlatAsciiStringMask =
2591 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2592 static const int kFlatAsciiStringTag = ASCII_STRING_TYPE;
2593 And(scratch1, first, kFlatAsciiStringMask);
2594 And(scratch2, second, kFlatAsciiStringMask);
2595 Cmp(scratch1, kFlatAsciiStringTag);
2596 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq);
2597 B(ne, failure);
2598 }
2599
2600
2601 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialAscii(Register type,
2602 Register scratch,
2603 Label* failure) {
2604 const int kFlatAsciiStringMask =
2605 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2606 const int kFlatAsciiStringTag =
2607 kStringTag | kOneByteStringTag | kSeqStringTag;
2608 And(scratch, type, kFlatAsciiStringMask);
2609 Cmp(scratch, kFlatAsciiStringTag);
2610 B(ne, failure);
2611 }
2612
2613
2614 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii(
2615 Register first,
2616 Register second,
2617 Register scratch1,
2618 Register scratch2,
2619 Label* failure) {
2620 ASSERT(!AreAliased(first, second, scratch1, scratch2));
2621 const int kFlatAsciiStringMask =
2622 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2623 const int kFlatAsciiStringTag =
2624 kStringTag | kOneByteStringTag | kSeqStringTag;
2625 And(scratch1, first, kFlatAsciiStringMask);
2626 And(scratch2, second, kFlatAsciiStringMask);
2627 Cmp(scratch1, kFlatAsciiStringTag);
2628 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq);
2629 B(ne, failure);
2630 }
2631
2632
2633 void MacroAssembler::JumpIfNotUniqueName(Register type,
2634 Label* not_unique_name) {
2635 STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
2636 // if ((type is string && type is internalized) || type == SYMBOL_TYPE) {
2637 // continue
2638 // } else {
2639 // goto not_unique_name
2640 // }
2641 Tst(type, kIsNotStringMask | kIsNotInternalizedMask);
2642 Ccmp(type, SYMBOL_TYPE, ZFlag, ne);
2643 B(ne, not_unique_name);
2644 }
2645
2646
2647 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
2648 const ParameterCount& actual,
2649 Handle<Code> code_constant,
2650 Register code_reg,
2651 Label* done,
2652 InvokeFlag flag,
2653 bool* definitely_mismatches,
2654 const CallWrapper& call_wrapper) {
2655 bool definitely_matches = false;
2656 *definitely_mismatches = false;
2657 Label regular_invoke;
2658
2659 // Check whether the expected and actual arguments count match. If not,
2660 // setup registers according to contract with ArgumentsAdaptorTrampoline:
2661 // x0: actual arguments count.
2662 // x1: function (passed through to callee).
2663 // x2: expected arguments count.
2664
2665 // The code below is made a lot easier because the calling code already sets
2666 // up actual and expected registers according to the contract if values are
2667 // passed in registers.
2668 ASSERT(actual.is_immediate() || actual.reg().is(x0));
2669 ASSERT(expected.is_immediate() || expected.reg().is(x2));
2670 ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(x3));
2671
2672 if (expected.is_immediate()) {
2673 ASSERT(actual.is_immediate());
2674 if (expected.immediate() == actual.immediate()) {
2675 definitely_matches = true;
2676
2677 } else {
2678 Mov(x0, actual.immediate());
2679 if (expected.immediate() ==
2680 SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
2681 // Don't worry about adapting arguments for builtins that
2682 // don't want that done. Skip adaption code by making it look
2683 // like we have a match between expected and actual number of
2684 // arguments.
2685 definitely_matches = true;
2686 } else {
2687 *definitely_mismatches = true;
2688 // Set up x2 for the argument adaptor.
2689 Mov(x2, expected.immediate());
2690 }
2691 }
2692
2693 } else { // expected is a register.
2694 Operand actual_op = actual.is_immediate() ? Operand(actual.immediate())
2695 : Operand(actual.reg());
2696 // If actual == expected perform a regular invocation.
2697 Cmp(expected.reg(), actual_op);
2698 B(eq, &regular_invoke);
2699 // Otherwise set up x0 for the argument adaptor.
2700 Mov(x0, actual_op);
2701 }
2702
2703 // If the argument counts may mismatch, generate a call to the argument
2704 // adaptor.
2705 if (!definitely_matches) {
2706 if (!code_constant.is_null()) {
2707 Mov(x3, Operand(code_constant));
2708 Add(x3, x3, Code::kHeaderSize - kHeapObjectTag);
2709 }
2710
2711 Handle<Code> adaptor =
2712 isolate()->builtins()->ArgumentsAdaptorTrampoline();
2713 if (flag == CALL_FUNCTION) {
2714 call_wrapper.BeforeCall(CallSize(adaptor));
2715 Call(adaptor);
2716 call_wrapper.AfterCall();
2717 if (!*definitely_mismatches) {
2718 // If the arg counts don't match, no extra code is emitted by
2719 // MAsm::InvokeCode and we can just fall through.
2720 B(done);
2721 }
2722 } else {
2723 Jump(adaptor, RelocInfo::CODE_TARGET);
2724 }
2725 }
2726 Bind(&regular_invoke);
2727 }
2728
2729
2730 void MacroAssembler::InvokeCode(Register code,
2731 const ParameterCount& expected,
2732 const ParameterCount& actual,
2733 InvokeFlag flag,
2734 const CallWrapper& call_wrapper) {
2735 // You can't call a function without a valid frame.
2736 ASSERT(flag == JUMP_FUNCTION || has_frame());
2737
2738 Label done;
2739
2740 bool definitely_mismatches = false;
2741 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
2742 &definitely_mismatches, call_wrapper);
2743
2744 // If we are certain that actual != expected, then we know InvokePrologue will
2745 // have handled the call through the argument adaptor mechanism.
2746 // The called function expects the call kind in x5.
2747 if (!definitely_mismatches) {
2748 if (flag == CALL_FUNCTION) {
2749 call_wrapper.BeforeCall(CallSize(code));
2750 Call(code);
2751 call_wrapper.AfterCall();
2752 } else {
2753 ASSERT(flag == JUMP_FUNCTION);
2754 Jump(code);
2755 }
2756 }
2757
2758 // Continue here if InvokePrologue does handle the invocation due to
2759 // mismatched parameter counts.
2760 Bind(&done);
2761 }
2762
2763
2764 void MacroAssembler::InvokeFunction(Register function,
2765 const ParameterCount& actual,
2766 InvokeFlag flag,
2767 const CallWrapper& call_wrapper) {
2768 // You can't call a function without a valid frame.
2769 ASSERT(flag == JUMP_FUNCTION || has_frame());
2770
2771 // Contract with called JS functions requires that function is passed in x1.
2772 // (See FullCodeGenerator::Generate().)
2773 ASSERT(function.is(x1));
2774
2775 Register expected_reg = x2;
2776 Register code_reg = x3;
2777
2778 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
2779 // The number of arguments is stored as an int32_t, and -1 is a marker
2780 // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign
2781 // extension to correctly handle it.
2782 Ldr(expected_reg, FieldMemOperand(function,
2783 JSFunction::kSharedFunctionInfoOffset));
2784 Ldrsw(expected_reg,
2785 FieldMemOperand(expected_reg,
2786 SharedFunctionInfo::kFormalParameterCountOffset));
2787 Ldr(code_reg,
2788 FieldMemOperand(function, JSFunction::kCodeEntryOffset));
2789
2790 ParameterCount expected(expected_reg);
2791 InvokeCode(code_reg, expected, actual, flag, call_wrapper);
2792 }
2793
2794
2795 void MacroAssembler::InvokeFunction(Register function,
2796 const ParameterCount& expected,
2797 const ParameterCount& actual,
2798 InvokeFlag flag,
2799 const CallWrapper& call_wrapper) {
2800 // You can't call a function without a valid frame.
2801 ASSERT(flag == JUMP_FUNCTION || has_frame());
2802
2803 // Contract with called JS functions requires that function is passed in x1.
2804 // (See FullCodeGenerator::Generate().)
2805 ASSERT(function.Is(x1));
2806
2807 Register code_reg = x3;
2808
2809 // Set up the context.
2810 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
2811
2812 // We call indirectly through the code field in the function to
2813 // allow recompilation to take effect without changing any of the
2814 // call sites.
2815 Ldr(code_reg, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
2816 InvokeCode(code_reg, expected, actual, flag, call_wrapper);
2817 }
2818
2819
2820 void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
2821 const ParameterCount& expected,
2822 const ParameterCount& actual,
2823 InvokeFlag flag,
2824 const CallWrapper& call_wrapper) {
2825 // Contract with called JS functions requires that function is passed in x1.
2826 // (See FullCodeGenerator::Generate().)
2827 __ LoadObject(x1, function);
2828 InvokeFunction(x1, expected, actual, flag, call_wrapper);
2829 }
2830
2831
2832 void MacroAssembler::TryConvertDoubleToInt64(Register result,
2833 DoubleRegister double_input,
2834 Label* done) {
2835 // Try to convert with an FPU convert instruction. It's trivial to compute
2836 // the modulo operation on an integer register so we convert to a 64-bit
2837 // integer.
2838 //
2839 // Fcvtzs will saturate to INT64_MIN (0x800...00) or INT64_MAX (0x7ff...ff)
2840 // when the double is out of range. NaNs and infinities will be converted to 0
2841 // (as ECMA-262 requires).
2842 Fcvtzs(result.X(), double_input);
2843
2844 // The values INT64_MIN (0x800...00) or INT64_MAX (0x7ff...ff) are not
2845 // representable using a double, so if the result is one of those then we know
2846 // that saturation occured, and we need to manually handle the conversion.
2847 //
2848 // It is easy to detect INT64_MIN and INT64_MAX because adding or subtracting
2849 // 1 will cause signed overflow.
2850 Cmp(result.X(), 1);
2851 Ccmp(result.X(), -1, VFlag, vc);
2852
2853 B(vc, done);
2854 }
2855
2856
2857 void MacroAssembler::TruncateDoubleToI(Register result,
2858 DoubleRegister double_input) {
2859 Label done;
2860 ASSERT(jssp.Is(StackPointer()));
2861
2862 // Try to convert the double to an int64. If successful, the bottom 32 bits
2863 // contain our truncated int32 result.
2864 TryConvertDoubleToInt64(result, double_input, &done);
2865
2866 // If we fell through then inline version didn't succeed - call stub instead.
2867 Push(lr);
2868 Push(double_input); // Put input on stack.
2869
2870 DoubleToIStub stub(jssp,
2871 result,
2872 0,
2873 true, // is_truncating
2874 true); // skip_fastpath
2875 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber
2876
2877 Drop(1, kDoubleSize); // Drop the double input on the stack.
2878 Pop(lr);
2879
2880 Bind(&done);
2881 }
2882
2883
2884 void MacroAssembler::TruncateHeapNumberToI(Register result,
2885 Register object) {
2886 Label done;
2887 ASSERT(!result.is(object));
2888 ASSERT(jssp.Is(StackPointer()));
2889
2890 Ldr(fp_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
2891
2892 // Try to convert the double to an int64. If successful, the bottom 32 bits
2893 // contain our truncated int32 result.
2894 TryConvertDoubleToInt64(result, fp_scratch, &done);
2895
2896 // If we fell through then inline version didn't succeed - call stub instead.
2897 Push(lr);
2898 DoubleToIStub stub(object,
2899 result,
2900 HeapNumber::kValueOffset - kHeapObjectTag,
2901 true, // is_truncating
2902 true); // skip_fastpath
2903 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber
2904 Pop(lr);
2905
2906 Bind(&done);
2907 }
2908
2909
2910 void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
2911 if (frame_mode == BUILD_STUB_FRAME) {
2912 ASSERT(StackPointer().Is(jssp));
2913 UseScratchRegisterScope temps(this);
2914 Register temp = temps.AcquireX();
2915 __ Mov(temp, Smi::FromInt(StackFrame::STUB));
2916 // Compiled stubs don't age, and so they don't need the predictable code
2917 // ageing sequence.
2918 __ Push(lr, fp, cp, temp);
2919 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
2920 } else {
2921 if (isolate()->IsCodePreAgingActive()) {
2922 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
2923 __ EmitCodeAgeSequence(stub);
2924 } else {
2925 __ EmitFrameSetupForCodeAgePatching();
2926 }
2927 }
2928 }
2929
2930
2931 void MacroAssembler::EnterFrame(StackFrame::Type type) {
2932 ASSERT(jssp.Is(StackPointer()));
2933 UseScratchRegisterScope temps(this);
2934 Register type_reg = temps.AcquireX();
2935 Register code_reg = temps.AcquireX();
2936
2937 Push(lr, fp, cp);
2938 Mov(type_reg, Smi::FromInt(type));
2939 Mov(code_reg, Operand(CodeObject()));
2940 Push(type_reg, code_reg);
2941 // jssp[4] : lr
2942 // jssp[3] : fp
2943 // jssp[2] : cp
2944 // jssp[1] : type
2945 // jssp[0] : code object
2946
2947 // Adjust FP to point to saved FP.
2948 Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
2949 }
2950
2951
2952 void MacroAssembler::LeaveFrame(StackFrame::Type type) {
2953 ASSERT(jssp.Is(StackPointer()));
2954 // Drop the execution stack down to the frame pointer and restore
2955 // the caller frame pointer and return address.
2956 Mov(jssp, fp);
2957 AssertStackConsistency();
2958 Pop(fp, lr);
2959 }
2960
2961
2962 void MacroAssembler::ExitFramePreserveFPRegs() {
2963 PushCPURegList(kCallerSavedFP);
2964 }
2965
2966
2967 void MacroAssembler::ExitFrameRestoreFPRegs() {
2968 // Read the registers from the stack without popping them. The stack pointer
2969 // will be reset as part of the unwinding process.
2970 CPURegList saved_fp_regs = kCallerSavedFP;
2971 ASSERT(saved_fp_regs.Count() % 2 == 0);
2972
2973 int offset = ExitFrameConstants::kLastExitFrameField;
2974 while (!saved_fp_regs.IsEmpty()) {
2975 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex();
2976 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex();
2977 offset -= 2 * kDRegSize;
2978 Ldp(dst1, dst0, MemOperand(fp, offset));
2979 }
2980 }
2981
2982
2983 void MacroAssembler::EnterExitFrame(bool save_doubles,
2984 const Register& scratch,
2985 int extra_space) {
2986 ASSERT(jssp.Is(StackPointer()));
2987
2988 // Set up the new stack frame.
2989 Mov(scratch, Operand(CodeObject()));
2990 Push(lr, fp);
2991 Mov(fp, StackPointer());
2992 Push(xzr, scratch);
2993 // fp[8]: CallerPC (lr)
2994 // fp -> fp[0]: CallerFP (old fp)
2995 // fp[-8]: Space reserved for SPOffset.
2996 // jssp -> fp[-16]: CodeObject()
2997 STATIC_ASSERT((2 * kPointerSize) ==
2998 ExitFrameConstants::kCallerSPDisplacement);
2999 STATIC_ASSERT((1 * kPointerSize) == ExitFrameConstants::kCallerPCOffset);
3000 STATIC_ASSERT((0 * kPointerSize) == ExitFrameConstants::kCallerFPOffset);
3001 STATIC_ASSERT((-1 * kPointerSize) == ExitFrameConstants::kSPOffset);
3002 STATIC_ASSERT((-2 * kPointerSize) == ExitFrameConstants::kCodeOffset);
3003
3004 // Save the frame pointer and context pointer in the top frame.
3005 Mov(scratch, Operand(ExternalReference(Isolate::kCEntryFPAddress,
3006 isolate())));
3007 Str(fp, MemOperand(scratch));
3008 Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
3009 isolate())));
3010 Str(cp, MemOperand(scratch));
3011
3012 STATIC_ASSERT((-2 * kPointerSize) ==
3013 ExitFrameConstants::kLastExitFrameField);
3014 if (save_doubles) {
3015 ExitFramePreserveFPRegs();
3016 }
3017
3018 // Reserve space for the return address and for user requested memory.
3019 // We do this before aligning to make sure that we end up correctly
3020 // aligned with the minimum of wasted space.
3021 Claim(extra_space + 1, kXRegSize);
3022 // fp[8]: CallerPC (lr)
3023 // fp -> fp[0]: CallerFP (old fp)
3024 // fp[-8]: Space reserved for SPOffset.
3025 // fp[-16]: CodeObject()
3026 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true).
3027 // jssp[8]: Extra space reserved for caller (if extra_space != 0).
3028 // jssp -> jssp[0]: Space reserved for the return address.
3029
3030 // Align and synchronize the system stack pointer with jssp.
3031 AlignAndSetCSPForFrame();
3032 ASSERT(csp.Is(StackPointer()));
3033
3034 // fp[8]: CallerPC (lr)
3035 // fp -> fp[0]: CallerFP (old fp)
3036 // fp[-8]: Space reserved for SPOffset.
3037 // fp[-16]: CodeObject()
3038 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true).
3039 // csp[8]: Memory reserved for the caller if extra_space != 0.
3040 // Alignment padding, if necessary.
3041 // csp -> csp[0]: Space reserved for the return address.
3042
3043 // ExitFrame::GetStateForFramePointer expects to find the return address at
3044 // the memory address immediately below the pointer stored in SPOffset.
3045 // It is not safe to derive much else from SPOffset, because the size of the
3046 // padding can vary.
3047 Add(scratch, csp, kXRegSize);
3048 Str(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset));
3049 }
3050
3051
3052 // Leave the current exit frame.
3053 void MacroAssembler::LeaveExitFrame(bool restore_doubles,
3054 const Register& scratch,
3055 bool restore_context) {
3056 ASSERT(csp.Is(StackPointer()));
3057
3058 if (restore_doubles) {
3059 ExitFrameRestoreFPRegs();
3060 }
3061
3062 // Restore the context pointer from the top frame.
3063 if (restore_context) {
3064 Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
3065 isolate())));
3066 Ldr(cp, MemOperand(scratch));
3067 }
3068
3069 if (emit_debug_code()) {
3070 // Also emit debug code to clear the cp in the top frame.
3071 Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
3072 isolate())));
3073 Str(xzr, MemOperand(scratch));
3074 }
3075 // Clear the frame pointer from the top frame.
3076 Mov(scratch, Operand(ExternalReference(Isolate::kCEntryFPAddress,
3077 isolate())));
3078 Str(xzr, MemOperand(scratch));
3079
3080 // Pop the exit frame.
3081 // fp[8]: CallerPC (lr)
3082 // fp -> fp[0]: CallerFP (old fp)
3083 // fp[...]: The rest of the frame.
3084 Mov(jssp, fp);
3085 SetStackPointer(jssp);
3086 AssertStackConsistency();
3087 Pop(fp, lr);
3088 }
3089
3090
3091 void MacroAssembler::SetCounter(StatsCounter* counter, int value,
3092 Register scratch1, Register scratch2) {
3093 if (FLAG_native_code_counters && counter->Enabled()) {
3094 Mov(scratch1, value);
3095 Mov(scratch2, ExternalReference(counter));
3096 Str(scratch1, MemOperand(scratch2));
3097 }
3098 }
3099
3100
3101 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
3102 Register scratch1, Register scratch2) {
3103 ASSERT(value != 0);
3104 if (FLAG_native_code_counters && counter->Enabled()) {
3105 Mov(scratch2, ExternalReference(counter));
3106 Ldr(scratch1, MemOperand(scratch2));
3107 Add(scratch1, scratch1, value);
3108 Str(scratch1, MemOperand(scratch2));
3109 }
3110 }
3111
3112
3113 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
3114 Register scratch1, Register scratch2) {
3115 IncrementCounter(counter, -value, scratch1, scratch2);
3116 }
3117
3118
3119 void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
3120 if (context_chain_length > 0) {
3121 // Move up the chain of contexts to the context containing the slot.
3122 Ldr(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
3123 for (int i = 1; i < context_chain_length; i++) {
3124 Ldr(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
3125 }
3126 } else {
3127 // Slot is in the current function context. Move it into the
3128 // destination register in case we store into it (the write barrier
3129 // cannot be allowed to destroy the context in cp).
3130 Mov(dst, cp);
3131 }
3132 }
3133
3134
3135 #ifdef ENABLE_DEBUGGER_SUPPORT
3136 void MacroAssembler::DebugBreak() {
3137 Mov(x0, 0);
3138 Mov(x1, ExternalReference(Runtime::kDebugBreak, isolate()));
3139 CEntryStub ces(1);
3140 ASSERT(AllowThisStubCall(&ces));
3141 Call(ces.GetCode(isolate()), RelocInfo::DEBUG_BREAK);
3142 }
3143 #endif
3144
3145
3146 void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
3147 int handler_index) {
3148 ASSERT(jssp.Is(StackPointer()));
3149 // Adjust this code if the asserts don't hold.
3150 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
3151 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
3152 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
3153 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
3154 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
3155 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
3156
3157 // For the JSEntry handler, we must preserve the live registers x0-x4.
3158 // (See JSEntryStub::GenerateBody().)
3159
3160 unsigned state =
3161 StackHandler::IndexField::encode(handler_index) |
3162 StackHandler::KindField::encode(kind);
3163
3164 // Set up the code object and the state for pushing.
3165 Mov(x10, Operand(CodeObject()));
3166 Mov(x11, state);
3167
3168 // Push the frame pointer, context, state, and code object.
3169 if (kind == StackHandler::JS_ENTRY) {
3170 ASSERT(Smi::FromInt(0) == 0);
3171 Push(xzr, xzr, x11, x10);
3172 } else {
3173 Push(fp, cp, x11, x10);
3174 }
3175
3176 // Link the current handler as the next handler.
3177 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
3178 Ldr(x10, MemOperand(x11));
3179 Push(x10);
3180 // Set this new handler as the current one.
3181 Str(jssp, MemOperand(x11));
3182 }
3183
3184
3185 void MacroAssembler::PopTryHandler() {
3186 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
3187 Pop(x10);
3188 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
3189 Drop(StackHandlerConstants::kSize - kXRegSize, kByteSizeInBytes);
3190 Str(x10, MemOperand(x11));
3191 }
3192
3193
3194 void MacroAssembler::Allocate(int object_size,
3195 Register result,
3196 Register scratch1,
3197 Register scratch2,
3198 Label* gc_required,
3199 AllocationFlags flags) {
3200 ASSERT(object_size <= Page::kMaxRegularHeapObjectSize);
3201 if (!FLAG_inline_new) {
3202 if (emit_debug_code()) {
3203 // Trash the registers to simulate an allocation failure.
3204 // We apply salt to the original zap value to easily spot the values.
3205 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L);
3206 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L);
3207 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L);
3208 }
3209 B(gc_required);
3210 return;
3211 }
3212
3213 UseScratchRegisterScope temps(this);
3214 Register scratch3 = temps.AcquireX();
3215
3216 ASSERT(!AreAliased(result, scratch1, scratch2, scratch3));
3217 ASSERT(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits());
3218
3219 // Make object size into bytes.
3220 if ((flags & SIZE_IN_WORDS) != 0) {
3221 object_size *= kPointerSize;
3222 }
3223 ASSERT(0 == (object_size & kObjectAlignmentMask));
3224
3225 // Check relative positions of allocation top and limit addresses.
3226 // The values must be adjacent in memory to allow the use of LDP.
3227 ExternalReference heap_allocation_top =
3228 AllocationUtils::GetAllocationTopReference(isolate(), flags);
3229 ExternalReference heap_allocation_limit =
3230 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
3231 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address());
3232 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address());
3233 ASSERT((limit - top) == kPointerSize);
3234
3235 // Set up allocation top address and object size registers.
3236 Register top_address = scratch1;
3237 Register allocation_limit = scratch2;
3238 Mov(top_address, Operand(heap_allocation_top));
3239
3240 if ((flags & RESULT_CONTAINS_TOP) == 0) {
3241 // Load allocation top into result and the allocation limit.
3242 Ldp(result, allocation_limit, MemOperand(top_address));
3243 } else {
3244 if (emit_debug_code()) {
3245 // Assert that result actually contains top on entry.
3246 Ldr(scratch3, MemOperand(top_address));
3247 Cmp(result, scratch3);
3248 Check(eq, kUnexpectedAllocationTop);
3249 }
3250 // Load the allocation limit. 'result' already contains the allocation top.
3251 Ldr(allocation_limit, MemOperand(top_address, limit - top));
3252 }
3253
3254 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
3255 // the same alignment on A64.
3256 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
3257
3258 // Calculate new top and bail out if new space is exhausted.
3259 Adds(scratch3, result, object_size);
3260 B(vs, gc_required);
3261 Cmp(scratch3, allocation_limit);
3262 B(hi, gc_required);
3263 Str(scratch3, MemOperand(top_address));
3264
3265 // Tag the object if requested.
3266 if ((flags & TAG_OBJECT) != 0) {
3267 Orr(result, result, kHeapObjectTag);
3268 }
3269 }
3270
3271
3272 void MacroAssembler::Allocate(Register object_size,
3273 Register result,
3274 Register scratch1,
3275 Register scratch2,
3276 Label* gc_required,
3277 AllocationFlags flags) {
3278 if (!FLAG_inline_new) {
3279 if (emit_debug_code()) {
3280 // Trash the registers to simulate an allocation failure.
3281 // We apply salt to the original zap value to easily spot the values.
3282 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L);
3283 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L);
3284 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L);
3285 }
3286 B(gc_required);
3287 return;
3288 }
3289
3290 UseScratchRegisterScope temps(this);
3291 Register scratch3 = temps.AcquireX();
3292
3293 ASSERT(!AreAliased(object_size, result, scratch1, scratch2, scratch3));
3294 ASSERT(object_size.Is64Bits() && result.Is64Bits() &&
3295 scratch1.Is64Bits() && scratch2.Is64Bits());
3296
3297 // Check relative positions of allocation top and limit addresses.
3298 // The values must be adjacent in memory to allow the use of LDP.
3299 ExternalReference heap_allocation_top =
3300 AllocationUtils::GetAllocationTopReference(isolate(), flags);
3301 ExternalReference heap_allocation_limit =
3302 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
3303 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address());
3304 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address());
3305 ASSERT((limit - top) == kPointerSize);
3306
3307 // Set up allocation top address and object size registers.
3308 Register top_address = scratch1;
3309 Register allocation_limit = scratch2;
3310 Mov(top_address, heap_allocation_top);
3311
3312 if ((flags & RESULT_CONTAINS_TOP) == 0) {
3313 // Load allocation top into result and the allocation limit.
3314 Ldp(result, allocation_limit, MemOperand(top_address));
3315 } else {
3316 if (emit_debug_code()) {
3317 // Assert that result actually contains top on entry.
3318 Ldr(scratch3, MemOperand(top_address));
3319 Cmp(result, scratch3);
3320 Check(eq, kUnexpectedAllocationTop);
3321 }
3322 // Load the allocation limit. 'result' already contains the allocation top.
3323 Ldr(allocation_limit, MemOperand(top_address, limit - top));
3324 }
3325
3326 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
3327 // the same alignment on A64.
3328 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
3329
3330 // Calculate new top and bail out if new space is exhausted
3331 if ((flags & SIZE_IN_WORDS) != 0) {
3332 Adds(scratch3, result, Operand(object_size, LSL, kPointerSizeLog2));
3333 } else {
3334 Adds(scratch3, result, object_size);
3335 }
3336
3337 if (emit_debug_code()) {
3338 Tst(scratch3, kObjectAlignmentMask);
3339 Check(eq, kUnalignedAllocationInNewSpace);
3340 }
3341
3342 B(vs, gc_required);
3343 Cmp(scratch3, allocation_limit);
3344 B(hi, gc_required);
3345 Str(scratch3, MemOperand(top_address));
3346
3347 // Tag the object if requested.
3348 if ((flags & TAG_OBJECT) != 0) {
3349 Orr(result, result, kHeapObjectTag);
3350 }
3351 }
3352
3353
3354 void MacroAssembler::UndoAllocationInNewSpace(Register object,
3355 Register scratch) {
3356 ExternalReference new_space_allocation_top =
3357 ExternalReference::new_space_allocation_top_address(isolate());
3358
3359 // Make sure the object has no tag before resetting top.
3360 Bic(object, object, kHeapObjectTagMask);
3361 #ifdef DEBUG
3362 // Check that the object un-allocated is below the current top.
3363 Mov(scratch, new_space_allocation_top);
3364 Ldr(scratch, MemOperand(scratch));
3365 Cmp(object, scratch);
3366 Check(lt, kUndoAllocationOfNonAllocatedMemory);
3367 #endif
3368 // Write the address of the object to un-allocate as the current top.
3369 Mov(scratch, new_space_allocation_top);
3370 Str(object, MemOperand(scratch));
3371 }
3372
3373
3374 void MacroAssembler::AllocateTwoByteString(Register result,
3375 Register length,
3376 Register scratch1,
3377 Register scratch2,
3378 Register scratch3,
3379 Label* gc_required) {
3380 ASSERT(!AreAliased(result, length, scratch1, scratch2, scratch3));
3381 // Calculate the number of bytes needed for the characters in the string while
3382 // observing object alignment.
3383 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
3384 Add(scratch1, length, length); // Length in bytes, not chars.
3385 Add(scratch1, scratch1, kObjectAlignmentMask + SeqTwoByteString::kHeaderSize);
3386 Bic(scratch1, scratch1, kObjectAlignmentMask);
3387
3388 // Allocate two-byte string in new space.
3389 Allocate(scratch1,
3390 result,
3391 scratch2,
3392 scratch3,
3393 gc_required,
3394 TAG_OBJECT);
3395
3396 // Set the map, length and hash field.
3397 InitializeNewString(result,
3398 length,
3399 Heap::kStringMapRootIndex,
3400 scratch1,
3401 scratch2);
3402 }
3403
3404
3405 void MacroAssembler::AllocateAsciiString(Register result,
3406 Register length,
3407 Register scratch1,
3408 Register scratch2,
3409 Register scratch3,
3410 Label* gc_required) {
3411 ASSERT(!AreAliased(result, length, scratch1, scratch2, scratch3));
3412 // Calculate the number of bytes needed for the characters in the string while
3413 // observing object alignment.
3414 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
3415 STATIC_ASSERT(kCharSize == 1);
3416 Add(scratch1, length, kObjectAlignmentMask + SeqOneByteString::kHeaderSize);
3417 Bic(scratch1, scratch1, kObjectAlignmentMask);
3418
3419 // Allocate ASCII string in new space.
3420 Allocate(scratch1,
3421 result,
3422 scratch2,
3423 scratch3,
3424 gc_required,
3425 TAG_OBJECT);
3426
3427 // Set the map, length and hash field.
3428 InitializeNewString(result,
3429 length,
3430 Heap::kAsciiStringMapRootIndex,
3431 scratch1,
3432 scratch2);
3433 }
3434
3435
3436 void MacroAssembler::AllocateTwoByteConsString(Register result,
3437 Register length,
3438 Register scratch1,
3439 Register scratch2,
3440 Label* gc_required) {
3441 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
3442 TAG_OBJECT);
3443
3444 InitializeNewString(result,
3445 length,
3446 Heap::kConsStringMapRootIndex,
3447 scratch1,
3448 scratch2);
3449 }
3450
3451
3452 void MacroAssembler::AllocateAsciiConsString(Register result,
3453 Register length,
3454 Register scratch1,
3455 Register scratch2,
3456 Label* gc_required) {
3457 Label allocate_new_space, install_map;
3458 AllocationFlags flags = TAG_OBJECT;
3459
3460 ExternalReference high_promotion_mode = ExternalReference::
3461 new_space_high_promotion_mode_active_address(isolate());
3462 Mov(scratch1, high_promotion_mode);
3463 Ldr(scratch1, MemOperand(scratch1));
3464 Cbz(scratch1, &allocate_new_space);
3465
3466 Allocate(ConsString::kSize,
3467 result,
3468 scratch1,
3469 scratch2,
3470 gc_required,
3471 static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE));
3472
3473 B(&install_map);
3474
3475 Bind(&allocate_new_space);
3476 Allocate(ConsString::kSize,
3477 result,
3478 scratch1,
3479 scratch2,
3480 gc_required,
3481 flags);
3482
3483 Bind(&install_map);
3484
3485 InitializeNewString(result,
3486 length,
3487 Heap::kConsAsciiStringMapRootIndex,
3488 scratch1,
3489 scratch2);
3490 }
3491
3492
3493 void MacroAssembler::AllocateTwoByteSlicedString(Register result,
3494 Register length,
3495 Register scratch1,
3496 Register scratch2,
3497 Label* gc_required) {
3498 ASSERT(!AreAliased(result, length, scratch1, scratch2));
3499 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
3500 TAG_OBJECT);
3501
3502 InitializeNewString(result,
3503 length,
3504 Heap::kSlicedStringMapRootIndex,
3505 scratch1,
3506 scratch2);
3507 }
3508
3509
3510 void MacroAssembler::AllocateAsciiSlicedString(Register result,
3511 Register length,
3512 Register scratch1,
3513 Register scratch2,
3514 Label* gc_required) {
3515 ASSERT(!AreAliased(result, length, scratch1, scratch2));
3516 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
3517 TAG_OBJECT);
3518
3519 InitializeNewString(result,
3520 length,
3521 Heap::kSlicedAsciiStringMapRootIndex,
3522 scratch1,
3523 scratch2);
3524 }
3525
3526
3527 // Allocates a heap number or jumps to the need_gc label if the young space
3528 // is full and a scavenge is needed.
3529 void MacroAssembler::AllocateHeapNumber(Register result,
3530 Label* gc_required,
3531 Register scratch1,
3532 Register scratch2,
3533 Register heap_number_map) {
3534 // Allocate an object in the heap for the heap number and tag it as a heap
3535 // object.
3536 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
3537 TAG_OBJECT);
3538
3539 // Store heap number map in the allocated object.
3540 if (heap_number_map.Is(NoReg)) {
3541 heap_number_map = scratch1;
3542 LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
3543 }
3544 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
3545 Str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
3546 }
3547
3548
3549 void MacroAssembler::AllocateHeapNumberWithValue(Register result,
3550 DoubleRegister value,
3551 Label* gc_required,
3552 Register scratch1,
3553 Register scratch2,
3554 Register heap_number_map) {
3555 // TODO(all): Check if it would be more efficient to use STP to store both
3556 // the map and the value.
3557 AllocateHeapNumber(result, gc_required, scratch1, scratch2, heap_number_map);
3558 Str(value, FieldMemOperand(result, HeapNumber::kValueOffset));
3559 }
3560
3561
3562 void MacroAssembler::JumpIfObjectType(Register object,
3563 Register map,
3564 Register type_reg,
3565 InstanceType type,
3566 Label* if_cond_pass,
3567 Condition cond) {
3568 CompareObjectType(object, map, type_reg, type);
3569 B(cond, if_cond_pass);
3570 }
3571
3572
3573 void MacroAssembler::JumpIfNotObjectType(Register object,
3574 Register map,
3575 Register type_reg,
3576 InstanceType type,
3577 Label* if_not_object) {
3578 JumpIfObjectType(object, map, type_reg, type, if_not_object, ne);
3579 }
3580
3581
3582 // Sets condition flags based on comparison, and returns type in type_reg.
3583 void MacroAssembler::CompareObjectType(Register object,
3584 Register map,
3585 Register type_reg,
3586 InstanceType type) {
3587 Ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
3588 CompareInstanceType(map, type_reg, type);
3589 }
3590
3591
3592 // Sets condition flags based on comparison, and returns type in type_reg.
3593 void MacroAssembler::CompareInstanceType(Register map,
3594 Register type_reg,
3595 InstanceType type) {
3596 Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
3597 Cmp(type_reg, type);
3598 }
3599
3600
3601 void MacroAssembler::CompareMap(Register obj,
3602 Register scratch,
3603 Handle<Map> map) {
3604 Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3605 CompareMap(scratch, map);
3606 }
3607
3608
3609 void MacroAssembler::CompareMap(Register obj_map,
3610 Handle<Map> map) {
3611 Cmp(obj_map, Operand(map));
3612 }
3613
3614
3615 void MacroAssembler::CheckMap(Register obj,
3616 Register scratch,
3617 Handle<Map> map,
3618 Label* fail,
3619 SmiCheckType smi_check_type) {
3620 if (smi_check_type == DO_SMI_CHECK) {
3621 JumpIfSmi(obj, fail);
3622 }
3623
3624 CompareMap(obj, scratch, map);
3625 B(ne, fail);
3626 }
3627
3628
3629 void MacroAssembler::CheckMap(Register obj,
3630 Register scratch,
3631 Heap::RootListIndex index,
3632 Label* fail,
3633 SmiCheckType smi_check_type) {
3634 if (smi_check_type == DO_SMI_CHECK) {
3635 JumpIfSmi(obj, fail);
3636 }
3637 Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3638 JumpIfNotRoot(scratch, index, fail);
3639 }
3640
3641
3642 void MacroAssembler::CheckMap(Register obj_map,
3643 Handle<Map> map,
3644 Label* fail,
3645 SmiCheckType smi_check_type) {
3646 if (smi_check_type == DO_SMI_CHECK) {
3647 JumpIfSmi(obj_map, fail);
3648 }
3649
3650 CompareMap(obj_map, map);
3651 B(ne, fail);
3652 }
3653
3654
3655 void MacroAssembler::DispatchMap(Register obj,
3656 Register scratch,
3657 Handle<Map> map,
3658 Handle<Code> success,
3659 SmiCheckType smi_check_type) {
3660 Label fail;
3661 if (smi_check_type == DO_SMI_CHECK) {
3662 JumpIfSmi(obj, &fail);
3663 }
3664 Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3665 Cmp(scratch, Operand(map));
3666 B(ne, &fail);
3667 Jump(success, RelocInfo::CODE_TARGET);
3668 Bind(&fail);
3669 }
3670
3671
3672 void MacroAssembler::TestMapBitfield(Register object, uint64_t mask) {
3673 UseScratchRegisterScope temps(this);
3674 Register temp = temps.AcquireX();
3675 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
3676 Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
3677 Tst(temp, mask);
3678 }
3679
3680
3681 void MacroAssembler::LoadElementsKindFromMap(Register result, Register map) {
3682 // Load the map's "bit field 2".
3683 __ Ldrb(result, FieldMemOperand(map, Map::kBitField2Offset));
3684 // Retrieve elements_kind from bit field 2.
3685 __ Ubfx(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
3686 }
3687
3688
3689 void MacroAssembler::TryGetFunctionPrototype(Register function,
3690 Register result,
3691 Register scratch,
3692 Label* miss,
3693 BoundFunctionAction action) {
3694 ASSERT(!AreAliased(function, result, scratch));
3695
3696 // Check that the receiver isn't a smi.
3697 JumpIfSmi(function, miss);
3698
3699 // Check that the function really is a function. Load map into result reg.
3700 JumpIfNotObjectType(function, result, scratch, JS_FUNCTION_TYPE, miss);
3701
3702 if (action == kMissOnBoundFunction) {
3703 Register scratch_w = scratch.W();
3704 Ldr(scratch,
3705 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
3706 // On 64-bit platforms, compiler hints field is not a smi. See definition of
3707 // kCompilerHintsOffset in src/objects.h.
3708 Ldr(scratch_w,
3709 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
3710 Tbnz(scratch, SharedFunctionInfo::kBoundFunction, miss);
3711 }
3712
3713 // Make sure that the function has an instance prototype.
3714 Label non_instance;
3715 Ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
3716 Tbnz(scratch, Map::kHasNonInstancePrototype, &non_instance);
3717
3718 // Get the prototype or initial map from the function.
3719 Ldr(result,
3720 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3721
3722 // If the prototype or initial map is the hole, don't return it and simply
3723 // miss the cache instead. This will allow us to allocate a prototype object
3724 // on-demand in the runtime system.
3725 JumpIfRoot(result, Heap::kTheHoleValueRootIndex, miss);
3726
3727 // If the function does not have an initial map, we're done.
3728 Label done;
3729 JumpIfNotObjectType(result, scratch, scratch, MAP_TYPE, &done);
3730
3731 // Get the prototype from the initial map.
3732 Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
3733 B(&done);
3734
3735 // Non-instance prototype: fetch prototype from constructor field in initial
3736 // map.
3737 Bind(&non_instance);
3738 Ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
3739
3740 // All done.
3741 Bind(&done);
3742 }
3743
3744
3745 void MacroAssembler::CompareRoot(const Register& obj,
3746 Heap::RootListIndex index) {
3747 UseScratchRegisterScope temps(this);
3748 Register temp = temps.AcquireX();
3749 ASSERT(!AreAliased(obj, temp));
3750 LoadRoot(temp, index);
3751 Cmp(obj, temp);
3752 }
3753
3754
3755 void MacroAssembler::JumpIfRoot(const Register& obj,
3756 Heap::RootListIndex index,
3757 Label* if_equal) {
3758 CompareRoot(obj, index);
3759 B(eq, if_equal);
3760 }
3761
3762
3763 void MacroAssembler::JumpIfNotRoot(const Register& obj,
3764 Heap::RootListIndex index,
3765 Label* if_not_equal) {
3766 CompareRoot(obj, index);
3767 B(ne, if_not_equal);
3768 }
3769
3770
3771 void MacroAssembler::CompareAndSplit(const Register& lhs,
3772 const Operand& rhs,
3773 Condition cond,
3774 Label* if_true,
3775 Label* if_false,
3776 Label* fall_through) {
3777 if ((if_true == if_false) && (if_false == fall_through)) {
3778 // Fall through.
3779 } else if (if_true == if_false) {
3780 B(if_true);
3781 } else if (if_false == fall_through) {
3782 CompareAndBranch(lhs, rhs, cond, if_true);
3783 } else if (if_true == fall_through) {
3784 CompareAndBranch(lhs, rhs, InvertCondition(cond), if_false);
3785 } else {
3786 CompareAndBranch(lhs, rhs, cond, if_true);
3787 B(if_false);
3788 }
3789 }
3790
3791
3792 void MacroAssembler::TestAndSplit(const Register& reg,
3793 uint64_t bit_pattern,
3794 Label* if_all_clear,
3795 Label* if_any_set,
3796 Label* fall_through) {
3797 if ((if_all_clear == if_any_set) && (if_any_set == fall_through)) {
3798 // Fall through.
3799 } else if (if_all_clear == if_any_set) {
3800 B(if_all_clear);
3801 } else if (if_all_clear == fall_through) {
3802 TestAndBranchIfAnySet(reg, bit_pattern, if_any_set);
3803 } else if (if_any_set == fall_through) {
3804 TestAndBranchIfAllClear(reg, bit_pattern, if_all_clear);
3805 } else {
3806 TestAndBranchIfAnySet(reg, bit_pattern, if_any_set);
3807 B(if_all_clear);
3808 }
3809 }
3810
3811
3812 void MacroAssembler::CheckFastElements(Register map,
3813 Register scratch,
3814 Label* fail) {
3815 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
3816 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
3817 STATIC_ASSERT(FAST_ELEMENTS == 2);
3818 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
3819 Ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
3820 Cmp(scratch, Map::kMaximumBitField2FastHoleyElementValue);
3821 B(hi, fail);
3822 }
3823
3824
3825 void MacroAssembler::CheckFastObjectElements(Register map,
3826 Register scratch,
3827 Label* fail) {
3828 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
3829 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
3830 STATIC_ASSERT(FAST_ELEMENTS == 2);
3831 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
3832 Ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
3833 Cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
3834 // If cond==ls, set cond=hi, otherwise compare.
3835 Ccmp(scratch,
3836 Operand(Map::kMaximumBitField2FastHoleyElementValue), CFlag, hi);
3837 B(hi, fail);
3838 }
3839
3840
3841 // Note: The ARM version of this clobbers elements_reg, but this version does
3842 // not. Some uses of this in A64 assume that elements_reg will be preserved.
3843 void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
3844 Register key_reg,
3845 Register elements_reg,
3846 Register scratch1,
3847 FPRegister fpscratch1,
3848 FPRegister fpscratch2,
3849 Label* fail,
3850 int elements_offset) {
3851 ASSERT(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
3852 Label store_num;
3853
3854 // Speculatively convert the smi to a double - all smis can be exactly
3855 // represented as a double.
3856 SmiUntagToDouble(fpscratch1, value_reg, kSpeculativeUntag);
3857
3858 // If value_reg is a smi, we're done.
3859 JumpIfSmi(value_reg, &store_num);
3860
3861 // Ensure that the object is a heap number.
3862 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(),
3863 fail, DONT_DO_SMI_CHECK);
3864
3865 Ldr(fpscratch1, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
3866 Fmov(fpscratch2, FixedDoubleArray::canonical_not_the_hole_nan_as_double());
3867
3868 // Check for NaN by comparing the number to itself: NaN comparison will
3869 // report unordered, indicated by the overflow flag being set.
3870 Fcmp(fpscratch1, fpscratch1);
3871 Fcsel(fpscratch1, fpscratch2, fpscratch1, vs);
3872
3873 // Store the result.
3874 Bind(&store_num);
3875 Add(scratch1, elements_reg,
3876 Operand::UntagSmiAndScale(key_reg, kDoubleSizeLog2));
3877 Str(fpscratch1,
3878 FieldMemOperand(scratch1,
3879 FixedDoubleArray::kHeaderSize - elements_offset));
3880 }
3881
3882
3883 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
3884 return has_frame_ || !stub->SometimesSetsUpAFrame();
3885 }
3886
3887
3888 void MacroAssembler::IndexFromHash(Register hash, Register index) {
3889 // If the hash field contains an array index pick it out. The assert checks
3890 // that the constants for the maximum number of digits for an array index
3891 // cached in the hash field and the number of bits reserved for it does not
3892 // conflict.
3893 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
3894 (1 << String::kArrayIndexValueBits));
3895 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
3896 // the low kHashShift bits.
3897 STATIC_ASSERT(kSmiTag == 0);
3898 Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
3899 SmiTag(index, hash);
3900 }
3901
3902
3903 void MacroAssembler::EmitSeqStringSetCharCheck(
3904 Register string,
3905 Register index,
3906 SeqStringSetCharCheckIndexType index_type,
3907 Register scratch,
3908 uint32_t encoding_mask) {
3909 ASSERT(!AreAliased(string, index, scratch));
3910
3911 if (index_type == kIndexIsSmi) {
3912 AssertSmi(index);
3913 }
3914
3915 // Check that string is an object.
3916 AssertNotSmi(string, kNonObject);
3917
3918 // Check that string has an appropriate map.
3919 Ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
3920 Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
3921
3922 And(scratch, scratch, kStringRepresentationMask | kStringEncodingMask);
3923 Cmp(scratch, encoding_mask);
3924 Check(eq, kUnexpectedStringType);
3925
3926 Ldr(scratch, FieldMemOperand(string, String::kLengthOffset));
3927 Cmp(index, index_type == kIndexIsSmi ? scratch : Operand::UntagSmi(scratch));
3928 Check(lt, kIndexIsTooLarge);
3929
3930 ASSERT_EQ(0, Smi::FromInt(0));
3931 Cmp(index, 0);
3932 Check(ge, kIndexIsNegative);
3933 }
3934
3935
3936 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
3937 Register scratch1,
3938 Register scratch2,
3939 Label* miss) {
3940 ASSERT(!AreAliased(holder_reg, scratch1, scratch2));
3941 Label same_contexts;
3942
3943 // Load current lexical context from the stack frame.
3944 Ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
3945 // In debug mode, make sure the lexical context is set.
3946 #ifdef DEBUG
3947 Cmp(scratch1, 0);
3948 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
3949 #endif
3950
3951 // Load the native context of the current context.
3952 int offset =
3953 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
3954 Ldr(scratch1, FieldMemOperand(scratch1, offset));
3955 Ldr(scratch1, FieldMemOperand(scratch1, GlobalObject::kNativeContextOffset));
3956
3957 // Check the context is a native context.
3958 if (emit_debug_code()) {
3959 // Read the first word and compare to the global_context_map.
3960 Ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
3961 CompareRoot(scratch2, Heap::kNativeContextMapRootIndex);
3962 Check(eq, kExpectedNativeContext);
3963 }
3964
3965 // Check if both contexts are the same.
3966 Ldr(scratch2, FieldMemOperand(holder_reg,
3967 JSGlobalProxy::kNativeContextOffset));
3968 Cmp(scratch1, scratch2);
3969 B(&same_contexts, eq);
3970
3971 // Check the context is a native context.
3972 if (emit_debug_code()) {
3973 // We're short on scratch registers here, so use holder_reg as a scratch.
3974 Push(holder_reg);
3975 Register scratch3 = holder_reg;
3976
3977 CompareRoot(scratch2, Heap::kNullValueRootIndex);
3978 Check(ne, kExpectedNonNullContext);
3979
3980 Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset));
3981 CompareRoot(scratch3, Heap::kNativeContextMapRootIndex);
3982 Check(eq, kExpectedNativeContext);
3983 Pop(holder_reg);
3984 }
3985
3986 // Check that the security token in the calling global object is
3987 // compatible with the security token in the receiving global
3988 // object.
3989 int token_offset = Context::kHeaderSize +
3990 Context::SECURITY_TOKEN_INDEX * kPointerSize;
3991
3992 Ldr(scratch1, FieldMemOperand(scratch1, token_offset));
3993 Ldr(scratch2, FieldMemOperand(scratch2, token_offset));
3994 Cmp(scratch1, scratch2);
3995 B(miss, ne);
3996
3997 Bind(&same_contexts);
3998 }
3999
4000
4001 // Compute the hash code from the untagged key. This must be kept in sync with
4002 // ComputeIntegerHash in utils.h and KeyedLoadGenericElementStub in
4003 // code-stub-hydrogen.cc
4004 void MacroAssembler::GetNumberHash(Register key, Register scratch) {
4005 ASSERT(!AreAliased(key, scratch));
4006
4007 // Xor original key with a seed.
4008 LoadRoot(scratch, Heap::kHashSeedRootIndex);
4009 Eor(key, key, Operand::UntagSmi(scratch));
4010
4011 // The algorithm uses 32-bit integer values.
4012 key = key.W();
4013 scratch = scratch.W();
4014
4015 // Compute the hash code from the untagged key. This must be kept in sync
4016 // with ComputeIntegerHash in utils.h.
4017 //
4018 // hash = ~hash + (hash <<1 15);
4019 Mvn(scratch, key);
4020 Add(key, scratch, Operand(key, LSL, 15));
4021 // hash = hash ^ (hash >> 12);
4022 Eor(key, key, Operand(key, LSR, 12));
4023 // hash = hash + (hash << 2);
4024 Add(key, key, Operand(key, LSL, 2));
4025 // hash = hash ^ (hash >> 4);
4026 Eor(key, key, Operand(key, LSR, 4));
4027 // hash = hash * 2057;
4028 Mov(scratch, Operand(key, LSL, 11));
4029 Add(key, key, Operand(key, LSL, 3));
4030 Add(key, key, scratch);
4031 // hash = hash ^ (hash >> 16);
4032 Eor(key, key, Operand(key, LSR, 16));
4033 }
4034
4035
4036 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
4037 Register elements,
4038 Register key,
4039 Register result,
4040 Register scratch0,
4041 Register scratch1,
4042 Register scratch2,
4043 Register scratch3) {
4044 ASSERT(!AreAliased(elements, key, scratch0, scratch1, scratch2, scratch3));
4045
4046 Label done;
4047
4048 SmiUntag(scratch0, key);
4049 GetNumberHash(scratch0, scratch1);
4050
4051 // Compute the capacity mask.
4052 Ldrsw(scratch1,
4053 UntagSmiFieldMemOperand(elements,
4054 SeededNumberDictionary::kCapacityOffset));
4055 Sub(scratch1, scratch1, 1);
4056
4057 // Generate an unrolled loop that performs a few probes before giving up.
4058 for (int i = 0; i < kNumberDictionaryProbes; i++) {
4059 // Compute the masked index: (hash + i + i * i) & mask.
4060 if (i > 0) {
4061 Add(scratch2, scratch0, SeededNumberDictionary::GetProbeOffset(i));
4062 } else {
4063 Mov(scratch2, scratch0);
4064 }
4065 And(scratch2, scratch2, scratch1);
4066
4067 // Scale the index by multiplying by the element size.
4068 ASSERT(SeededNumberDictionary::kEntrySize == 3);
4069 Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
4070
4071 // Check if the key is identical to the name.
4072 Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
4073 Ldr(scratch3,
4074 FieldMemOperand(scratch2,
4075 SeededNumberDictionary::kElementsStartOffset));
4076 Cmp(key, scratch3);
4077 if (i != (kNumberDictionaryProbes - 1)) {
4078 B(eq, &done);
4079 } else {
4080 B(ne, miss);
4081 }
4082 }
4083
4084 Bind(&done);
4085 // Check that the value is a normal property.
4086 const int kDetailsOffset =
4087 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
4088 Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
4089 TestAndBranchIfAnySet(scratch1, PropertyDetails::TypeField::kMask, miss);
4090
4091 // Get the value at the masked, scaled index and return.
4092 const int kValueOffset =
4093 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
4094 Ldr(result, FieldMemOperand(scratch2, kValueOffset));
4095 }
4096
4097
4098 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
4099 Register address,
4100 Register scratch1,
4101 SaveFPRegsMode fp_mode,
4102 RememberedSetFinalAction and_then) {
4103 ASSERT(!AreAliased(object, address, scratch1));
4104 Label done, store_buffer_overflow;
4105 if (emit_debug_code()) {
4106 Label ok;
4107 JumpIfNotInNewSpace(object, &ok);
4108 Abort(kRememberedSetPointerInNewSpace);
4109 bind(&ok);
4110 }
4111 UseScratchRegisterScope temps(this);
4112 Register scratch2 = temps.AcquireX();
4113
4114 // Load store buffer top.
4115 Mov(scratch2, ExternalReference::store_buffer_top(isolate()));
4116 Ldr(scratch1, MemOperand(scratch2));
4117 // Store pointer to buffer and increment buffer top.
4118 Str(address, MemOperand(scratch1, kPointerSize, PostIndex));
4119 // Write back new top of buffer.
4120 Str(scratch1, MemOperand(scratch2));
4121 // Call stub on end of buffer.
4122 // Check for end of buffer.
4123 ASSERT(StoreBuffer::kStoreBufferOverflowBit ==
4124 (1 << (14 + kPointerSizeLog2)));
4125 if (and_then == kFallThroughAtEnd) {
4126 Tbz(scratch1, (14 + kPointerSizeLog2), &done);
4127 } else {
4128 ASSERT(and_then == kReturnAtEnd);
4129 Tbnz(scratch1, (14 + kPointerSizeLog2), &store_buffer_overflow);
4130 Ret();
4131 }
4132
4133 Bind(&store_buffer_overflow);
4134 Push(lr);
4135 StoreBufferOverflowStub store_buffer_overflow_stub =
4136 StoreBufferOverflowStub(fp_mode);
4137 CallStub(&store_buffer_overflow_stub);
4138 Pop(lr);
4139
4140 Bind(&done);
4141 if (and_then == kReturnAtEnd) {
4142 Ret();
4143 }
4144 }
4145
4146
4147 void MacroAssembler::PopSafepointRegisters() {
4148 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
4149 PopXRegList(kSafepointSavedRegisters);
4150 Drop(num_unsaved);
4151 }
4152
4153
4154 void MacroAssembler::PushSafepointRegisters() {
4155 // Safepoints expect a block of kNumSafepointRegisters values on the stack, so
4156 // adjust the stack for unsaved registers.
4157 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
4158 ASSERT(num_unsaved >= 0);
4159 Claim(num_unsaved);
4160 PushXRegList(kSafepointSavedRegisters);
4161 }
4162
4163
4164 void MacroAssembler::PushSafepointFPRegisters() {
4165 PushCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
4166 FPRegister::kAllocatableFPRegisters));
4167 }
4168
4169
4170 void MacroAssembler::PopSafepointFPRegisters() {
4171 PopCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
4172 FPRegister::kAllocatableFPRegisters));
4173 }
4174
4175
4176 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
4177 // Make sure the safepoint registers list is what we expect.
4178 ASSERT(CPURegList::GetSafepointSavedRegisters().list() == 0x6ffcffff);
4179
4180 // Safepoint registers are stored contiguously on the stack, but not all the
4181 // registers are saved. The following registers are excluded:
4182 // - x16 and x17 (ip0 and ip1) because they shouldn't be preserved outside of
4183 // the macro assembler.
4184 // - x28 (jssp) because JS stack pointer doesn't need to be included in
4185 // safepoint registers.
4186 // - x31 (csp) because the system stack pointer doesn't need to be included
4187 // in safepoint registers.
4188 //
4189 // This function implements the mapping of register code to index into the
4190 // safepoint register slots.
4191 if ((reg_code >= 0) && (reg_code <= 15)) {
4192 return reg_code;
4193 } else if ((reg_code >= 18) && (reg_code <= 27)) {
4194 // Skip ip0 and ip1.
4195 return reg_code - 2;
4196 } else if ((reg_code == 29) || (reg_code == 30)) {
4197 // Also skip jssp.
4198 return reg_code - 3;
4199 } else {
4200 // This register has no safepoint register slot.
4201 UNREACHABLE();
4202 return -1;
4203 }
4204 }
4205
4206
4207 void MacroAssembler::CheckPageFlagSet(const Register& object,
4208 const Register& scratch,
4209 int mask,
4210 Label* if_any_set) {
4211 And(scratch, object, ~Page::kPageAlignmentMask);
4212 Ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
4213 TestAndBranchIfAnySet(scratch, mask, if_any_set);
4214 }
4215
4216
4217 void MacroAssembler::CheckPageFlagClear(const Register& object,
4218 const Register& scratch,
4219 int mask,
4220 Label* if_all_clear) {
4221 And(scratch, object, ~Page::kPageAlignmentMask);
4222 Ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
4223 TestAndBranchIfAllClear(scratch, mask, if_all_clear);
4224 }
4225
4226
4227 void MacroAssembler::RecordWriteField(
4228 Register object,
4229 int offset,
4230 Register value,
4231 Register scratch,
4232 LinkRegisterStatus lr_status,
4233 SaveFPRegsMode save_fp,
4234 RememberedSetAction remembered_set_action,
4235 SmiCheck smi_check) {
4236 // First, check if a write barrier is even needed. The tests below
4237 // catch stores of Smis.
4238 Label done;
4239
4240 // Skip the barrier if writing a smi.
4241 if (smi_check == INLINE_SMI_CHECK) {
4242 JumpIfSmi(value, &done);
4243 }
4244
4245 // Although the object register is tagged, the offset is relative to the start
4246 // of the object, so offset must be a multiple of kPointerSize.
4247 ASSERT(IsAligned(offset, kPointerSize));
4248
4249 Add(scratch, object, offset - kHeapObjectTag);
4250 if (emit_debug_code()) {
4251 Label ok;
4252 Tst(scratch, (1 << kPointerSizeLog2) - 1);
4253 B(eq, &ok);
4254 Abort(kUnalignedCellInWriteBarrier);
4255 Bind(&ok);
4256 }
4257
4258 RecordWrite(object,
4259 scratch,
4260 value,
4261 lr_status,
4262 save_fp,
4263 remembered_set_action,
4264 OMIT_SMI_CHECK);
4265
4266 Bind(&done);
4267
4268 // Clobber clobbered input registers when running with the debug-code flag
4269 // turned on to provoke errors.
4270 if (emit_debug_code()) {
4271 Mov(value, Operand(BitCast<int64_t>(kZapValue + 4)));
4272 Mov(scratch, Operand(BitCast<int64_t>(kZapValue + 8)));
4273 }
4274 }
4275
4276
4277 // Will clobber: object, address, value.
4278 // If lr_status is kLRHasBeenSaved, lr will also be clobbered.
4279 //
4280 // The register 'object' contains a heap object pointer. The heap object tag is
4281 // shifted away.
4282 void MacroAssembler::RecordWrite(Register object,
4283 Register address,
4284 Register value,
4285 LinkRegisterStatus lr_status,
4286 SaveFPRegsMode fp_mode,
4287 RememberedSetAction remembered_set_action,
4288 SmiCheck smi_check) {
4289 ASM_LOCATION("MacroAssembler::RecordWrite");
4290 ASSERT(!AreAliased(object, value));
4291
4292 if (emit_debug_code()) {
4293 UseScratchRegisterScope temps(this);
4294 Register temp = temps.AcquireX();
4295
4296 Ldr(temp, MemOperand(address));
4297 Cmp(temp, value);
4298 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
4299 }
4300
4301 // Count number of write barriers in generated code.
4302 isolate()->counters()->write_barriers_static()->Increment();
4303 // TODO(mstarzinger): Dynamic counter missing.
4304
4305 // First, check if a write barrier is even needed. The tests below
4306 // catch stores of smis and stores into the young generation.
4307 Label done;
4308
4309 if (smi_check == INLINE_SMI_CHECK) {
4310 ASSERT_EQ(0, kSmiTag);
4311 JumpIfSmi(value, &done);
4312 }
4313
4314 CheckPageFlagClear(value,
4315 value, // Used as scratch.
4316 MemoryChunk::kPointersToHereAreInterestingMask,
4317 &done);
4318 CheckPageFlagClear(object,
4319 value, // Used as scratch.
4320 MemoryChunk::kPointersFromHereAreInterestingMask,
4321 &done);
4322
4323 // Record the actual write.
4324 if (lr_status == kLRHasNotBeenSaved) {
4325 Push(lr);
4326 }
4327 RecordWriteStub stub(object, value, address, remembered_set_action, fp_mode);
4328 CallStub(&stub);
4329 if (lr_status == kLRHasNotBeenSaved) {
4330 Pop(lr);
4331 }
4332
4333 Bind(&done);
4334
4335 // Clobber clobbered registers when running with the debug-code flag
4336 // turned on to provoke errors.
4337 if (emit_debug_code()) {
4338 Mov(address, Operand(BitCast<int64_t>(kZapValue + 12)));
4339 Mov(value, Operand(BitCast<int64_t>(kZapValue + 16)));
4340 }
4341 }
4342
4343
4344 void MacroAssembler::AssertHasValidColor(const Register& reg) {
4345 if (emit_debug_code()) {
4346 // The bit sequence is backward. The first character in the string
4347 // represents the least significant bit.
4348 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
4349
4350 Label color_is_valid;
4351 Tbnz(reg, 0, &color_is_valid);
4352 Tbz(reg, 1, &color_is_valid);
4353 Abort(kUnexpectedColorFound);
4354 Bind(&color_is_valid);
4355 }
4356 }
4357
4358
4359 void MacroAssembler::GetMarkBits(Register addr_reg,
4360 Register bitmap_reg,
4361 Register shift_reg) {
4362 ASSERT(!AreAliased(addr_reg, bitmap_reg, shift_reg));
4363 ASSERT(addr_reg.Is64Bits() && bitmap_reg.Is64Bits() && shift_reg.Is64Bits());
4364 // addr_reg is divided into fields:
4365 // |63 page base 20|19 high 8|7 shift 3|2 0|
4366 // 'high' gives the index of the cell holding color bits for the object.
4367 // 'shift' gives the offset in the cell for this object's color.
4368 const int kShiftBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
4369 UseScratchRegisterScope temps(this);
4370 Register temp = temps.AcquireX();
4371 Ubfx(temp, addr_reg, kShiftBits, kPageSizeBits - kShiftBits);
4372 Bic(bitmap_reg, addr_reg, Page::kPageAlignmentMask);
4373 Add(bitmap_reg, bitmap_reg, Operand(temp, LSL, Bitmap::kBytesPerCellLog2));
4374 // bitmap_reg:
4375 // |63 page base 20|19 zeros 15|14 high 3|2 0|
4376 Ubfx(shift_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2);
4377 }
4378
4379
4380 void MacroAssembler::HasColor(Register object,
4381 Register bitmap_scratch,
4382 Register shift_scratch,
4383 Label* has_color,
4384 int first_bit,
4385 int second_bit) {
4386 // See mark-compact.h for color definitions.
4387 ASSERT(!AreAliased(object, bitmap_scratch, shift_scratch));
4388
4389 GetMarkBits(object, bitmap_scratch, shift_scratch);
4390 Ldr(bitmap_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
4391 // Shift the bitmap down to get the color of the object in bits [1:0].
4392 Lsr(bitmap_scratch, bitmap_scratch, shift_scratch);
4393
4394 AssertHasValidColor(bitmap_scratch);
4395
4396 // These bit sequences are backwards. The first character in the string
4397 // represents the least significant bit.
4398 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0);
4399 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
4400 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0);
4401
4402 // Check for the color.
4403 if (first_bit == 0) {
4404 // Checking for white.
4405 ASSERT(second_bit == 0);
4406 // We only need to test the first bit.
4407 Tbz(bitmap_scratch, 0, has_color);
4408 } else {
4409 Label other_color;
4410 // Checking for grey or black.
4411 Tbz(bitmap_scratch, 0, &other_color);
4412 if (second_bit == 0) {
4413 Tbz(bitmap_scratch, 1, has_color);
4414 } else {
4415 Tbnz(bitmap_scratch, 1, has_color);
4416 }
4417 Bind(&other_color);
4418 }
4419
4420 // Fall through if it does not have the right color.
4421 }
4422
4423
4424 void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
4425 Register scratch,
4426 Label* if_deprecated) {
4427 if (map->CanBeDeprecated()) {
4428 Mov(scratch, Operand(map));
4429 Ldrsw(scratch, UntagSmiFieldMemOperand(scratch, Map::kBitField3Offset));
4430 TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, if_deprecated);
4431 }
4432 }
4433
4434
4435 void MacroAssembler::JumpIfBlack(Register object,
4436 Register scratch0,
4437 Register scratch1,
4438 Label* on_black) {
4439 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
4440 HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern.
4441 }
4442
4443
4444 void MacroAssembler::JumpIfDictionaryInPrototypeChain(
4445 Register object,
4446 Register scratch0,
4447 Register scratch1,
4448 Label* found) {
4449 ASSERT(!AreAliased(object, scratch0, scratch1));
4450 Factory* factory = isolate()->factory();
4451 Register current = scratch0;
4452 Label loop_again;
4453
4454 // Scratch contains elements pointer.
4455 Mov(current, object);
4456
4457 // Loop based on the map going up the prototype chain.
4458 Bind(&loop_again);
4459 Ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
4460 Ldrb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
4461 Ubfx(scratch1, scratch1, Map::kElementsKindShift, Map::kElementsKindBitCount);
4462 CompareAndBranch(scratch1, DICTIONARY_ELEMENTS, eq, found);
4463 Ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
4464 CompareAndBranch(current, Operand(factory->null_value()), ne, &loop_again);
4465 }
4466
4467
4468 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
4469 Register result) {
4470 ASSERT(!result.Is(ldr_location));
4471 const uint32_t kLdrLitOffset_lsb = 5;
4472 const uint32_t kLdrLitOffset_width = 19;
4473 Ldr(result, MemOperand(ldr_location));
4474 if (emit_debug_code()) {
4475 And(result, result, LoadLiteralFMask);
4476 Cmp(result, LoadLiteralFixed);
4477 Check(eq, kTheInstructionToPatchShouldBeAnLdrLiteral);
4478 // The instruction was clobbered. Reload it.
4479 Ldr(result, MemOperand(ldr_location));
4480 }
4481 Sbfx(result, result, kLdrLitOffset_lsb, kLdrLitOffset_width);
4482 Add(result, ldr_location, Operand(result, LSL, kWordSizeInBytesLog2));
4483 }
4484
4485
4486 void MacroAssembler::EnsureNotWhite(
4487 Register value,
4488 Register bitmap_scratch,
4489 Register shift_scratch,
4490 Register load_scratch,
4491 Register length_scratch,
4492 Label* value_is_white_and_not_data) {
4493 ASSERT(!AreAliased(
4494 value, bitmap_scratch, shift_scratch, load_scratch, length_scratch));
4495
4496 // These bit sequences are backwards. The first character in the string
4497 // represents the least significant bit.
4498 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0);
4499 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0);
4500 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0);
4501
4502 GetMarkBits(value, bitmap_scratch, shift_scratch);
4503 Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
4504 Lsr(load_scratch, load_scratch, shift_scratch);
4505
4506 AssertHasValidColor(load_scratch);
4507
4508 // If the value is black or grey we don't need to do anything.
4509 // Since both black and grey have a 1 in the first position and white does
4510 // not have a 1 there we only need to check one bit.
4511 Label done;
4512 Tbnz(load_scratch, 0, &done);
4513
4514 // Value is white. We check whether it is data that doesn't need scanning.
4515 Register map = load_scratch; // Holds map while checking type.
4516 Label is_data_object;
4517
4518 // Check for heap-number.
4519 Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
4520 Mov(length_scratch, HeapNumber::kSize);
4521 JumpIfRoot(map, Heap::kHeapNumberMapRootIndex, &is_data_object);
4522
4523 // Check for strings.
4524 ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
4525 ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
4526 // If it's a string and it's not a cons string then it's an object containing
4527 // no GC pointers.
4528 Register instance_type = load_scratch;
4529 Ldrb(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
4530 TestAndBranchIfAnySet(instance_type,
4531 kIsIndirectStringMask | kIsNotStringMask,
4532 value_is_white_and_not_data);
4533
4534 // It's a non-indirect (non-cons and non-slice) string.
4535 // If it's external, the length is just ExternalString::kSize.
4536 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
4537 // External strings are the only ones with the kExternalStringTag bit
4538 // set.
4539 ASSERT_EQ(0, kSeqStringTag & kExternalStringTag);
4540 ASSERT_EQ(0, kConsStringTag & kExternalStringTag);
4541 Mov(length_scratch, ExternalString::kSize);
4542 TestAndBranchIfAnySet(instance_type, kExternalStringTag, &is_data_object);
4543
4544 // Sequential string, either ASCII or UC16.
4545 // For ASCII (char-size of 1) we shift the smi tag away to get the length.
4546 // For UC16 (char-size of 2) we just leave the smi tag in place, thereby
4547 // getting the length multiplied by 2.
4548 ASSERT(kOneByteStringTag == 4 && kStringEncodingMask == 4);
4549 Ldrsw(length_scratch, UntagSmiFieldMemOperand(value,
4550 String::kLengthOffset));
4551 Tst(instance_type, kStringEncodingMask);
4552 Cset(load_scratch, eq);
4553 Lsl(length_scratch, length_scratch, load_scratch);
4554 Add(length_scratch,
4555 length_scratch,
4556 SeqString::kHeaderSize + kObjectAlignmentMask);
4557 Bic(length_scratch, length_scratch, kObjectAlignmentMask);
4558
4559 Bind(&is_data_object);
4560 // Value is a data object, and it is white. Mark it black. Since we know
4561 // that the object is white we can make it black by flipping one bit.
4562 Register mask = shift_scratch;
4563 Mov(load_scratch, 1);
4564 Lsl(mask, load_scratch, shift_scratch);
4565
4566 Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
4567 Orr(load_scratch, load_scratch, mask);
4568 Str(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
4569
4570 Bic(bitmap_scratch, bitmap_scratch, Page::kPageAlignmentMask);
4571 Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
4572 Add(load_scratch, load_scratch, length_scratch);
4573 Str(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
4574
4575 Bind(&done);
4576 }
4577
4578
4579 void MacroAssembler::Assert(Condition cond, BailoutReason reason) {
4580 if (emit_debug_code()) {
4581 Check(cond, reason);
4582 }
4583 }
4584
4585
4586
4587 void MacroAssembler::AssertRegisterIsClear(Register reg, BailoutReason reason) {
4588 if (emit_debug_code()) {
4589 CheckRegisterIsClear(reg, reason);
4590 }
4591 }
4592
4593
4594 void MacroAssembler::AssertRegisterIsRoot(Register reg,
4595 Heap::RootListIndex index,
4596 BailoutReason reason) {
4597 if (emit_debug_code()) {
4598 CompareRoot(reg, index);
4599 Check(eq, reason);
4600 }
4601 }
4602
4603
4604 void MacroAssembler::AssertFastElements(Register elements) {
4605 if (emit_debug_code()) {
4606 UseScratchRegisterScope temps(this);
4607 Register temp = temps.AcquireX();
4608 Label ok;
4609 Ldr(temp, FieldMemOperand(elements, HeapObject::kMapOffset));
4610 JumpIfRoot(temp, Heap::kFixedArrayMapRootIndex, &ok);
4611 JumpIfRoot(temp, Heap::kFixedDoubleArrayMapRootIndex, &ok);
4612 JumpIfRoot(temp, Heap::kFixedCOWArrayMapRootIndex, &ok);
4613 Abort(kJSObjectWithFastElementsMapHasSlowElements);
4614 Bind(&ok);
4615 }
4616 }
4617
4618
4619 void MacroAssembler::AssertIsString(const Register& object) {
4620 if (emit_debug_code()) {
4621 UseScratchRegisterScope temps(this);
4622 Register temp = temps.AcquireX();
4623 STATIC_ASSERT(kSmiTag == 0);
4624 Tst(object, kSmiTagMask);
4625 Check(ne, kOperandIsNotAString);
4626 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
4627 CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE);
4628 Check(lo, kOperandIsNotAString);
4629 }
4630 }
4631
4632
4633 void MacroAssembler::Check(Condition cond, BailoutReason reason) {
4634 Label ok;
4635 B(cond, &ok);
4636 Abort(reason);
4637 // Will not return here.
4638 Bind(&ok);
4639 }
4640
4641
4642 void MacroAssembler::CheckRegisterIsClear(Register reg, BailoutReason reason) {
4643 Label ok;
4644 Cbz(reg, &ok);
4645 Abort(reason);
4646 // Will not return here.
4647 Bind(&ok);
4648 }
4649
4650
4651 void MacroAssembler::Abort(BailoutReason reason) {
4652 #ifdef DEBUG
4653 RecordComment("Abort message: ");
4654 RecordComment(GetBailoutReason(reason));
4655
4656 if (FLAG_trap_on_abort) {
4657 Brk(0);
4658 return;
4659 }
4660 #endif
4661
4662 // Abort is used in some contexts where csp is the stack pointer. In order to
4663 // simplify the CallRuntime code, make sure that jssp is the stack pointer.
4664 // There is no risk of register corruption here because Abort doesn't return.
4665 Register old_stack_pointer = StackPointer();
4666 SetStackPointer(jssp);
4667 Mov(jssp, old_stack_pointer);
4668
4669 // We need some scratch registers for the MacroAssembler, so make sure we have
4670 // some. This is safe here because Abort never returns.
4671 RegList old_tmp_list = TmpList()->list();
4672 TmpList()->Combine(ip0);
4673 TmpList()->Combine(ip1);
4674
4675 if (use_real_aborts()) {
4676 // Avoid infinite recursion; Push contains some assertions that use Abort.
4677 NoUseRealAbortsScope no_real_aborts(this);
4678
4679 Mov(x0, Smi::FromInt(reason));
4680 Push(x0);
4681
4682 if (!has_frame_) {
4683 // We don't actually want to generate a pile of code for this, so just
4684 // claim there is a stack frame, without generating one.
4685 FrameScope scope(this, StackFrame::NONE);
4686 CallRuntime(Runtime::kAbort, 1);
4687 } else {
4688 CallRuntime(Runtime::kAbort, 1);
4689 }
4690 } else {
4691 // Load the string to pass to Printf.
4692 Label msg_address;
4693 Adr(x0, &msg_address);
4694
4695 // Call Printf directly to report the error.
4696 CallPrintf();
4697
4698 // We need a way to stop execution on both the simulator and real hardware,
4699 // and Unreachable() is the best option.
4700 Unreachable();
4701
4702 // Emit the message string directly in the instruction stream.
4703 {
4704 BlockPoolsScope scope(this);
4705 Bind(&msg_address);
4706 EmitStringData(GetBailoutReason(reason));
4707 }
4708 }
4709
4710 SetStackPointer(old_stack_pointer);
4711 TmpList()->set_list(old_tmp_list);
4712 }
4713
4714
4715 void MacroAssembler::LoadTransitionedArrayMapConditional(
4716 ElementsKind expected_kind,
4717 ElementsKind transitioned_kind,
4718 Register map_in_out,
4719 Register scratch1,
4720 Register scratch2,
4721 Label* no_map_match) {
4722 // Load the global or builtins object from the current context.
4723 Ldr(scratch1, GlobalObjectMemOperand());
4724 Ldr(scratch1, FieldMemOperand(scratch1, GlobalObject::kNativeContextOffset));
4725
4726 // Check that the function's map is the same as the expected cached map.
4727 Ldr(scratch1, ContextMemOperand(scratch1, Context::JS_ARRAY_MAPS_INDEX));
4728 size_t offset = (expected_kind * kPointerSize) + FixedArrayBase::kHeaderSize;
4729 Ldr(scratch2, FieldMemOperand(scratch1, offset));
4730 Cmp(map_in_out, scratch2);
4731 B(ne, no_map_match);
4732
4733 // Use the transitioned cached map.
4734 offset = (transitioned_kind * kPointerSize) + FixedArrayBase::kHeaderSize;
4735 Ldr(map_in_out, FieldMemOperand(scratch1, offset));
4736 }
4737
4738
4739 void MacroAssembler::LoadGlobalFunction(int index, Register function) {
4740 // Load the global or builtins object from the current context.
4741 Ldr(function, GlobalObjectMemOperand());
4742 // Load the native context from the global or builtins object.
4743 Ldr(function, FieldMemOperand(function,
4744 GlobalObject::kNativeContextOffset));
4745 // Load the function from the native context.
4746 Ldr(function, ContextMemOperand(function, index));
4747 }
4748
4749
4750 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
4751 Register map,
4752 Register scratch) {
4753 // Load the initial map. The global functions all have initial maps.
4754 Ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
4755 if (emit_debug_code()) {
4756 Label ok, fail;
4757 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
4758 B(&ok);
4759 Bind(&fail);
4760 Abort(kGlobalFunctionsMustHaveInitialMap);
4761 Bind(&ok);
4762 }
4763 }
4764
4765
4766 // This is the main Printf implementation. All other Printf variants call
4767 // PrintfNoPreserve after setting up one or more PreserveRegisterScopes.
4768 void MacroAssembler::PrintfNoPreserve(const char * format,
4769 const CPURegister& arg0,
4770 const CPURegister& arg1,
4771 const CPURegister& arg2,
4772 const CPURegister& arg3) {
4773 // We cannot handle a caller-saved stack pointer. It doesn't make much sense
4774 // in most cases anyway, so this restriction shouldn't be too serious.
4775 ASSERT(!kCallerSaved.IncludesAliasOf(__ StackPointer()));
4776
4777 // Make sure that the macro assembler doesn't try to use any of our arguments
4778 // as scratch registers.
4779 ASSERT(!TmpList()->IncludesAliasOf(arg0, arg1, arg2, arg3));
4780 ASSERT(!FPTmpList()->IncludesAliasOf(arg0, arg1, arg2, arg3));
4781
4782 // We cannot print the stack pointer because it is typically used to preserve
4783 // caller-saved registers (using other Printf variants which depend on this
4784 // helper).
4785 ASSERT(!AreAliased(arg0, StackPointer()));
4786 ASSERT(!AreAliased(arg1, StackPointer()));
4787 ASSERT(!AreAliased(arg2, StackPointer()));
4788 ASSERT(!AreAliased(arg3, StackPointer()));
4789
4790 static const int kMaxArgCount = 4;
4791 // Assume that we have the maximum number of arguments until we know
4792 // otherwise.
4793 int arg_count = kMaxArgCount;
4794
4795 // The provided arguments.
4796 CPURegister args[kMaxArgCount] = {arg0, arg1, arg2, arg3};
4797
4798 // The PCS registers where the arguments need to end up.
4799 CPURegister pcs[kMaxArgCount] = {NoCPUReg, NoCPUReg, NoCPUReg, NoCPUReg};
4800
4801 // Promote FP arguments to doubles, and integer arguments to X registers.
4802 // Note that FP and integer arguments cannot be mixed, but we'll check
4803 // AreSameSizeAndType once we've processed these promotions.
4804 for (int i = 0; i < kMaxArgCount; i++) {
4805 if (args[i].IsRegister()) {
4806 // Note that we use x1 onwards, because x0 will hold the format string.
4807 pcs[i] = Register::XRegFromCode(i + 1);
4808 // For simplicity, we handle all integer arguments as X registers. An X
4809 // register argument takes the same space as a W register argument in the
4810 // PCS anyway. The only limitation is that we must explicitly clear the
4811 // top word for W register arguments as the callee will expect it to be
4812 // clear.
4813 if (!args[i].Is64Bits()) {
4814 const Register& as_x = args[i].X();
4815 And(as_x, as_x, 0x00000000ffffffff);
4816 args[i] = as_x;
4817 }
4818 } else if (args[i].IsFPRegister()) {
4819 pcs[i] = FPRegister::DRegFromCode(i);
4820 // C and C++ varargs functions (such as printf) implicitly promote float
4821 // arguments to doubles.
4822 if (!args[i].Is64Bits()) {
4823 FPRegister s(args[i]);
4824 const FPRegister& as_d = args[i].D();
4825 Fcvt(as_d, s);
4826 args[i] = as_d;
4827 }
4828 } else {
4829 // This is the first empty (NoCPUReg) argument, so use it to set the
4830 // argument count and bail out.
4831 arg_count = i;
4832 break;
4833 }
4834 }
4835 ASSERT((arg_count >= 0) && (arg_count <= kMaxArgCount));
4836 // Check that every remaining argument is NoCPUReg.
4837 for (int i = arg_count; i < kMaxArgCount; i++) {
4838 ASSERT(args[i].IsNone());
4839 }
4840 ASSERT((arg_count == 0) || AreSameSizeAndType(args[0], args[1],
4841 args[2], args[3],
4842 pcs[0], pcs[1],
4843 pcs[2], pcs[3]));
4844
4845 // Move the arguments into the appropriate PCS registers.
4846 //
4847 // Arranging an arbitrary list of registers into x1-x4 (or d0-d3) is
4848 // surprisingly complicated.
4849 //
4850 // * For even numbers of registers, we push the arguments and then pop them
4851 // into their final registers. This maintains 16-byte stack alignment in
4852 // case csp is the stack pointer, since we're only handling X or D
4853 // registers at this point.
4854 //
4855 // * For odd numbers of registers, we push and pop all but one register in
4856 // the same way, but the left-over register is moved directly, since we
4857 // can always safely move one register without clobbering any source.
4858 if (arg_count >= 4) {
4859 Push(args[3], args[2], args[1], args[0]);
4860 } else if (arg_count >= 2) {
4861 Push(args[1], args[0]);
4862 }
4863
4864 if ((arg_count % 2) != 0) {
4865 // Move the left-over register directly.
4866 const CPURegister& leftover_arg = args[arg_count - 1];
4867 const CPURegister& leftover_pcs = pcs[arg_count - 1];
4868 if (leftover_arg.IsRegister()) {
4869 Mov(Register(leftover_pcs), Register(leftover_arg));
4870 } else {
4871 Fmov(FPRegister(leftover_pcs), FPRegister(leftover_arg));
4872 }
4873 }
4874
4875 if (arg_count >= 4) {
4876 Pop(pcs[0], pcs[1], pcs[2], pcs[3]);
4877 } else if (arg_count >= 2) {
4878 Pop(pcs[0], pcs[1]);
4879 }
4880
4881 // Load the format string into x0, as per the procedure-call standard.
4882 //
4883 // To make the code as portable as possible, the format string is encoded
4884 // directly in the instruction stream. It might be cleaner to encode it in a
4885 // literal pool, but since Printf is usually used for debugging, it is
4886 // beneficial for it to be minimally dependent on other features.
4887 Label format_address;
4888 Adr(x0, &format_address);
4889
4890 // Emit the format string directly in the instruction stream.
4891 { BlockPoolsScope scope(this);
4892 Label after_data;
4893 B(&after_data);
4894 Bind(&format_address);
4895 EmitStringData(format);
4896 Unreachable();
4897 Bind(&after_data);
4898 }
4899
4900 // We don't pass any arguments on the stack, but we still need to align the C
4901 // stack pointer to a 16-byte boundary for PCS compliance.
4902 if (!csp.Is(StackPointer())) {
4903 Bic(csp, StackPointer(), 0xf);
4904 }
4905
4906 CallPrintf(pcs[0].type());
4907 }
4908
4909
4910 void MacroAssembler::CallPrintf(CPURegister::RegisterType type) {
4911 // A call to printf needs special handling for the simulator, since the system
4912 // printf function will use a different instruction set and the procedure-call
4913 // standard will not be compatible.
4914 #ifdef USE_SIMULATOR
4915 { InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
4916 hlt(kImmExceptionIsPrintf);
4917 dc32(type);
4918 }
4919 #else
4920 Call(FUNCTION_ADDR(printf), RelocInfo::EXTERNAL_REFERENCE);
4921 #endif
4922 }
4923
4924
4925 void MacroAssembler::Printf(const char * format,
4926 const CPURegister& arg0,
4927 const CPURegister& arg1,
4928 const CPURegister& arg2,
4929 const CPURegister& arg3) {
4930 // Printf is expected to preserve all registers, so make sure that none are
4931 // available as scratch registers until we've preserved them.
4932 RegList old_tmp_list = TmpList()->list();
4933 RegList old_fp_tmp_list = FPTmpList()->list();
4934 TmpList()->set_list(0);
4935 FPTmpList()->set_list(0);
4936
4937 // Preserve all caller-saved registers as well as NZCV.
4938 // If csp is the stack pointer, PushCPURegList asserts that the size of each
4939 // list is a multiple of 16 bytes.
4940 PushCPURegList(kCallerSaved);
4941 PushCPURegList(kCallerSavedFP);
4942
4943 // We can use caller-saved registers as scratch values (except for argN).
4944 CPURegList tmp_list = kCallerSaved;
4945 CPURegList fp_tmp_list = kCallerSavedFP;
4946 tmp_list.Remove(arg0, arg1, arg2, arg3);
4947 fp_tmp_list.Remove(arg0, arg1, arg2, arg3);
4948 TmpList()->set_list(tmp_list.list());
4949 FPTmpList()->set_list(fp_tmp_list.list());
4950
4951 // Preserve NZCV.
4952 { UseScratchRegisterScope temps(this);
4953 Register tmp = temps.AcquireX();
4954 Mrs(tmp, NZCV);
4955 Push(tmp, xzr);
4956 }
4957
4958 PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
4959
4960 { UseScratchRegisterScope temps(this);
4961 Register tmp = temps.AcquireX();
4962 Pop(xzr, tmp);
4963 Msr(NZCV, tmp);
4964 }
4965
4966 PopCPURegList(kCallerSavedFP);
4967 PopCPURegList(kCallerSaved);
4968
4969 TmpList()->set_list(old_tmp_list);
4970 FPTmpList()->set_list(old_fp_tmp_list);
4971 }
4972
4973
4974 void MacroAssembler::EmitFrameSetupForCodeAgePatching() {
4975 // TODO(jbramley): Other architectures use the internal memcpy to copy the
4976 // sequence. If this is a performance bottleneck, we should consider caching
4977 // the sequence and copying it in the same way.
4978 InstructionAccurateScope scope(this, kCodeAgeSequenceSize / kInstructionSize);
4979 ASSERT(jssp.Is(StackPointer()));
4980 EmitFrameSetupForCodeAgePatching(this);
4981 }
4982
4983
4984
4985 void MacroAssembler::EmitCodeAgeSequence(Code* stub) {
4986 InstructionAccurateScope scope(this, kCodeAgeSequenceSize / kInstructionSize);
4987 ASSERT(jssp.Is(StackPointer()));
4988 EmitCodeAgeSequence(this, stub);
4989 }
4990
4991
4992 #undef __
4993 #define __ assm->
4994
4995
4996 void MacroAssembler::EmitFrameSetupForCodeAgePatching(Assembler * assm) {
4997 Label start;
4998 __ bind(&start);
4999
5000 // We can do this sequence using four instructions, but the code ageing
5001 // sequence that patches it needs five, so we use the extra space to try to
5002 // simplify some addressing modes and remove some dependencies (compared to
5003 // using two stp instructions with write-back).
5004 __ sub(jssp, jssp, 4 * kXRegSize);
5005 __ sub(csp, csp, 4 * kXRegSize);
5006 __ stp(x1, cp, MemOperand(jssp, 0 * kXRegSize));
5007 __ stp(fp, lr, MemOperand(jssp, 2 * kXRegSize));
5008 __ add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
5009
5010 __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeSequenceSize);
5011 }
5012
5013
5014 void MacroAssembler::EmitCodeAgeSequence(Assembler * assm,
5015 Code * stub) {
5016 Label start;
5017 __ bind(&start);
5018 // When the stub is called, the sequence is replaced with the young sequence
5019 // (as in EmitFrameSetupForCodeAgePatching). After the code is replaced, the
5020 // stub jumps to &start, stored in x0. The young sequence does not call the
5021 // stub so there is no infinite loop here.
5022 //
5023 // A branch (br) is used rather than a call (blr) because this code replaces
5024 // the frame setup code that would normally preserve lr.
5025 __ LoadLiteral(ip0, kCodeAgeStubEntryOffset);
5026 __ adr(x0, &start);
5027 __ br(ip0);
5028 // IsCodeAgeSequence in codegen-a64.cc assumes that the code generated up
5029 // until now (kCodeAgeStubEntryOffset) is the same for all code age sequences.
5030 __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeStubEntryOffset);
5031 if (stub) {
5032 __ dc64(reinterpret_cast<uint64_t>(stub->instruction_start()));
5033 __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeSequenceSize);
5034 }
5035 }
5036
5037
5038 bool MacroAssembler::IsYoungSequence(byte* sequence) {
5039 // Generate a young sequence to compare with.
5040 const int length = kCodeAgeSequenceSize / kInstructionSize;
5041 static bool initialized = false;
5042 static byte young[kCodeAgeSequenceSize];
5043 if (!initialized) {
5044 PatchingAssembler patcher(young, length);
5045 // The young sequence is the frame setup code for FUNCTION code types. It is
5046 // generated by FullCodeGenerator::Generate.
5047 MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher);
5048 initialized = true;
5049 }
5050
5051 bool is_young = (memcmp(sequence, young, kCodeAgeSequenceSize) == 0);
5052 ASSERT(is_young || IsCodeAgeSequence(sequence));
5053 return is_young;
5054 }
5055
5056
5057 #ifdef DEBUG
5058 bool MacroAssembler::IsCodeAgeSequence(byte* sequence) {
5059 // The old sequence varies depending on the code age. However, the code up
5060 // until kCodeAgeStubEntryOffset does not change, so we can check that part to
5061 // get a reasonable level of verification.
5062 const int length = kCodeAgeStubEntryOffset / kInstructionSize;
5063 static bool initialized = false;
5064 static byte old[kCodeAgeStubEntryOffset];
5065 if (!initialized) {
5066 PatchingAssembler patcher(old, length);
5067 MacroAssembler::EmitCodeAgeSequence(&patcher, NULL);
5068 initialized = true;
5069 }
5070 return memcmp(sequence, old, kCodeAgeStubEntryOffset) == 0;
5071 }
5072 #endif
5073
5074
5075 void MacroAssembler::TruncatingDiv(Register result,
5076 Register dividend,
5077 int32_t divisor) {
5078 ASSERT(!AreAliased(result, dividend));
5079 ASSERT(result.Is32Bits() && dividend.Is32Bits());
5080 MultiplierAndShift ms(divisor);
5081 Mov(result, ms.multiplier());
5082 Smull(result.X(), dividend, result);
5083 Asr(result.X(), result.X(), 32);
5084 if (divisor > 0 && ms.multiplier() < 0) Add(result, result, dividend);
5085 if (divisor < 0 && ms.multiplier() > 0) Sub(result, result, dividend);
5086 if (ms.shift() > 0) Asr(result, result, ms.shift());
5087 Add(result, result, Operand(dividend, LSR, 31));
5088 }
5089
5090
5091 #undef __
5092
5093
5094 UseScratchRegisterScope::~UseScratchRegisterScope() {
5095 available_->set_list(old_available_);
5096 availablefp_->set_list(old_availablefp_);
5097 }
5098
5099
5100 Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
5101 int code = AcquireNextAvailable(available_).code();
5102 return Register::Create(code, reg.SizeInBits());
5103 }
5104
5105
5106 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
5107 int code = AcquireNextAvailable(availablefp_).code();
5108 return FPRegister::Create(code, reg.SizeInBits());
5109 }
5110
5111
5112 CPURegister UseScratchRegisterScope::AcquireNextAvailable(
5113 CPURegList* available) {
5114 CHECK(!available->IsEmpty());
5115 CPURegister result = available->PopLowestIndex();
5116 ASSERT(!AreAliased(result, xzr, csp));
5117 return result;
5118 }
5119
5120
5121 #define __ masm->
5122
5123
5124 void InlineSmiCheckInfo::Emit(MacroAssembler* masm, const Register& reg,
5125 const Label* smi_check) {
5126 Assembler::BlockPoolsScope scope(masm);
5127 if (reg.IsValid()) {
5128 ASSERT(smi_check->is_bound());
5129 ASSERT(reg.Is64Bits());
5130
5131 // Encode the register (x0-x30) in the lowest 5 bits, then the offset to
5132 // 'check' in the other bits. The possible offset is limited in that we
5133 // use BitField to pack the data, and the underlying data type is a
5134 // uint32_t.
5135 uint32_t delta = __ InstructionsGeneratedSince(smi_check);
5136 __ InlineData(RegisterBits::encode(reg.code()) | DeltaBits::encode(delta));
5137 } else {
5138 ASSERT(!smi_check->is_bound());
5139
5140 // An offset of 0 indicates that there is no patch site.
5141 __ InlineData(0);
5142 }
5143 }
5144
5145
5146 InlineSmiCheckInfo::InlineSmiCheckInfo(Address info)
5147 : reg_(NoReg), smi_check_(NULL) {
5148 InstructionSequence* inline_data = InstructionSequence::At(info);
5149 ASSERT(inline_data->IsInlineData());
5150 if (inline_data->IsInlineData()) {
5151 uint64_t payload = inline_data->InlineData();
5152 // We use BitField to decode the payload, and BitField can only handle
5153 // 32-bit values.
5154 ASSERT(is_uint32(payload));
5155 if (payload != 0) {
5156 int reg_code = RegisterBits::decode(payload);
5157 reg_ = Register::XRegFromCode(reg_code);
5158 uint64_t smi_check_delta = DeltaBits::decode(payload);
5159 ASSERT(smi_check_delta != 0);
5160 smi_check_ = inline_data->preceding(smi_check_delta);
5161 }
5162 }
5163 }
5164
5165
5166 #undef __
5167
5168
5169 } } // namespace v8::internal
5170
5171 #endif // V8_TARGET_ARCH_A64
OLDNEW
« no previous file with comments | « src/a64/macro-assembler-a64.h ('k') | src/a64/macro-assembler-a64-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698