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