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 #ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
6 #define V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
7
8 #include <vector>
9
10 #include "src/globals.h"
11
12 #include "src/arm64/assembler-arm64-inl.h"
13
14 namespace v8 {
15 namespace internal {
16
17 #define LS_MACRO_LIST(V) \
18 V(Ldrb, Register&, rt, LDRB_w) \
19 V(Strb, Register&, rt, STRB_w) \
20 V(Ldrsb, Register&, rt, rt.Is64Bits() ? LDRSB_x : LDRSB_w) \
21 V(Ldrh, Register&, rt, LDRH_w) \
22 V(Strh, Register&, rt, STRH_w) \
23 V(Ldrsh, Register&, rt, rt.Is64Bits() ? LDRSH_x : LDRSH_w) \
24 V(Ldr, CPURegister&, rt, LoadOpFor(rt)) \
25 V(Str, CPURegister&, rt, StoreOpFor(rt)) \
26 V(Ldrsw, Register&, rt, LDRSW_x)
27
28
29 // ----------------------------------------------------------------------------
30 // Static helper functions
31
32 // Generate a MemOperand for loading a field from an object.
33 inline MemOperand FieldMemOperand(Register object, int offset);
34 inline MemOperand UntagSmiFieldMemOperand(Register object, int offset);
35
36 // Generate a MemOperand for loading a SMI from memory.
37 inline MemOperand UntagSmiMemOperand(Register object, int offset);
38
39
40 // ----------------------------------------------------------------------------
41 // MacroAssembler
42
43 enum BranchType {
44 // Copies of architectural conditions.
45 // The associated conditions can be used in place of those, the code will
46 // take care of reinterpreting them with the correct type.
47 integer_eq = eq,
48 integer_ne = ne,
49 integer_hs = hs,
50 integer_lo = lo,
51 integer_mi = mi,
52 integer_pl = pl,
53 integer_vs = vs,
54 integer_vc = vc,
55 integer_hi = hi,
56 integer_ls = ls,
57 integer_ge = ge,
58 integer_lt = lt,
59 integer_gt = gt,
60 integer_le = le,
61 integer_al = al,
62 integer_nv = nv,
63
64 // These two are *different* from the architectural codes al and nv.
65 // 'always' is used to generate unconditional branches.
66 // 'never' is used to not generate a branch (generally as the inverse
67 // branch type of 'always).
68 always, never,
69 // cbz and cbnz
70 reg_zero, reg_not_zero,
71 // tbz and tbnz
72 reg_bit_clear, reg_bit_set,
73
74 // Aliases.
75 kBranchTypeFirstCondition = eq,
76 kBranchTypeLastCondition = nv,
77 kBranchTypeFirstUsingReg = reg_zero,
78 kBranchTypeFirstUsingBit = reg_bit_clear
79 };
80
InvertBranchType(BranchType type)81 inline BranchType InvertBranchType(BranchType type) {
82 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
83 return static_cast<BranchType>(
84 NegateCondition(static_cast<Condition>(type)));
85 } else {
86 return static_cast<BranchType>(type ^ 1);
87 }
88 }
89
90 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
91 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
92 enum PointersToHereCheck {
93 kPointersToHereMaybeInteresting,
94 kPointersToHereAreAlwaysInteresting
95 };
96 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
97 enum TargetAddressStorageMode {
98 CAN_INLINE_TARGET_ADDRESS,
99 NEVER_INLINE_TARGET_ADDRESS
100 };
101 enum UntagMode { kNotSpeculativeUntag, kSpeculativeUntag };
102 enum ArrayHasHoles { kArrayCantHaveHoles, kArrayCanHaveHoles };
103 enum CopyHint { kCopyUnknown, kCopyShort, kCopyLong };
104 enum DiscardMoveMode { kDontDiscardForSameWReg, kDiscardForSameWReg };
105 enum SeqStringSetCharCheckIndexType { kIndexIsSmi, kIndexIsInteger32 };
106
107 class MacroAssembler : public Assembler {
108 public:
109 MacroAssembler(Isolate* isolate, byte * buffer, unsigned buffer_size);
110
111 inline Handle<Object> CodeObject();
112
113 // Instruction set functions ------------------------------------------------
114 // Logical macros.
115 inline void And(const Register& rd,
116 const Register& rn,
117 const Operand& operand);
118 inline void Ands(const Register& rd,
119 const Register& rn,
120 const Operand& operand);
121 inline void Bic(const Register& rd,
122 const Register& rn,
123 const Operand& operand);
124 inline void Bics(const Register& rd,
125 const Register& rn,
126 const Operand& operand);
127 inline void Orr(const Register& rd,
128 const Register& rn,
129 const Operand& operand);
130 inline void Orn(const Register& rd,
131 const Register& rn,
132 const Operand& operand);
133 inline void Eor(const Register& rd,
134 const Register& rn,
135 const Operand& operand);
136 inline void Eon(const Register& rd,
137 const Register& rn,
138 const Operand& operand);
139 inline void Tst(const Register& rn, const Operand& operand);
140 void LogicalMacro(const Register& rd,
141 const Register& rn,
142 const Operand& operand,
143 LogicalOp op);
144
145 // Add and sub macros.
146 inline void Add(const Register& rd,
147 const Register& rn,
148 const Operand& operand);
149 inline void Adds(const Register& rd,
150 const Register& rn,
151 const Operand& operand);
152 inline void Sub(const Register& rd,
153 const Register& rn,
154 const Operand& operand);
155 inline void Subs(const Register& rd,
156 const Register& rn,
157 const Operand& operand);
158 inline void Cmn(const Register& rn, const Operand& operand);
159 inline void Cmp(const Register& rn, const Operand& operand);
160 inline void Neg(const Register& rd,
161 const Operand& operand);
162 inline void Negs(const Register& rd,
163 const Operand& operand);
164
165 void AddSubMacro(const Register& rd,
166 const Register& rn,
167 const Operand& operand,
168 FlagsUpdate S,
169 AddSubOp op);
170
171 // Add/sub with carry macros.
172 inline void Adc(const Register& rd,
173 const Register& rn,
174 const Operand& operand);
175 inline void Adcs(const Register& rd,
176 const Register& rn,
177 const Operand& operand);
178 inline void Sbc(const Register& rd,
179 const Register& rn,
180 const Operand& operand);
181 inline void Sbcs(const Register& rd,
182 const Register& rn,
183 const Operand& operand);
184 inline void Ngc(const Register& rd,
185 const Operand& operand);
186 inline void Ngcs(const Register& rd,
187 const Operand& operand);
188 void AddSubWithCarryMacro(const Register& rd,
189 const Register& rn,
190 const Operand& operand,
191 FlagsUpdate S,
192 AddSubWithCarryOp op);
193
194 // Move macros.
195 void Mov(const Register& rd,
196 const Operand& operand,
197 DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
198 void Mov(const Register& rd, uint64_t imm);
199 inline void Mvn(const Register& rd, uint64_t imm);
200 void Mvn(const Register& rd, const Operand& operand);
201 static bool IsImmMovn(uint64_t imm, unsigned reg_size);
202 static bool IsImmMovz(uint64_t imm, unsigned reg_size);
203 static unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size);
204
205 // Conditional macros.
206 inline void Ccmp(const Register& rn,
207 const Operand& operand,
208 StatusFlags nzcv,
209 Condition cond);
210 inline void Ccmn(const Register& rn,
211 const Operand& operand,
212 StatusFlags nzcv,
213 Condition cond);
214 void ConditionalCompareMacro(const Register& rn,
215 const Operand& operand,
216 StatusFlags nzcv,
217 Condition cond,
218 ConditionalCompareOp op);
219 void Csel(const Register& rd,
220 const Register& rn,
221 const Operand& operand,
222 Condition cond);
223
224 // Load/store macros.
225 #define DECLARE_FUNCTION(FN, REGTYPE, REG, OP) \
226 inline void FN(const REGTYPE REG, const MemOperand& addr);
227 LS_MACRO_LIST(DECLARE_FUNCTION)
228 #undef DECLARE_FUNCTION
229
230 void LoadStoreMacro(const CPURegister& rt,
231 const MemOperand& addr,
232 LoadStoreOp op);
233
234 // V8-specific load/store helpers.
235 void Load(const Register& rt, const MemOperand& addr, Representation r);
236 void Store(const Register& rt, const MemOperand& addr, Representation r);
237
238 enum AdrHint {
239 // The target must be within the immediate range of adr.
240 kAdrNear,
241 // The target may be outside of the immediate range of adr. Additional
242 // instructions may be emitted.
243 kAdrFar
244 };
245 void Adr(const Register& rd, Label* label, AdrHint = kAdrNear);
246
247 // Remaining instructions are simple pass-through calls to the assembler.
248 inline void Asr(const Register& rd, const Register& rn, unsigned shift);
249 inline void Asr(const Register& rd, const Register& rn, const Register& rm);
250
251 // Branch type inversion relies on these relations.
252 STATIC_ASSERT((reg_zero == (reg_not_zero ^ 1)) &&
253 (reg_bit_clear == (reg_bit_set ^ 1)) &&
254 (always == (never ^ 1)));
255
256 void B(Label* label, BranchType type, Register reg = NoReg, int bit = -1);
257
258 inline void B(Label* label);
259 inline void B(Condition cond, Label* label);
260 void B(Label* label, Condition cond);
261 inline void Bfi(const Register& rd,
262 const Register& rn,
263 unsigned lsb,
264 unsigned width);
265 inline void Bfxil(const Register& rd,
266 const Register& rn,
267 unsigned lsb,
268 unsigned width);
269 inline void Bind(Label* label);
270 inline void Bl(Label* label);
271 inline void Blr(const Register& xn);
272 inline void Br(const Register& xn);
273 inline void Brk(int code);
274 void Cbnz(const Register& rt, Label* label);
275 void Cbz(const Register& rt, Label* label);
276 inline void Cinc(const Register& rd, const Register& rn, Condition cond);
277 inline void Cinv(const Register& rd, const Register& rn, Condition cond);
278 inline void Cls(const Register& rd, const Register& rn);
279 inline void Clz(const Register& rd, const Register& rn);
280 inline void Cneg(const Register& rd, const Register& rn, Condition cond);
281 inline void CzeroX(const Register& rd, Condition cond);
282 inline void CmovX(const Register& rd, const Register& rn, Condition cond);
283 inline void Cset(const Register& rd, Condition cond);
284 inline void Csetm(const Register& rd, Condition cond);
285 inline void Csinc(const Register& rd,
286 const Register& rn,
287 const Register& rm,
288 Condition cond);
289 inline void Csinv(const Register& rd,
290 const Register& rn,
291 const Register& rm,
292 Condition cond);
293 inline void Csneg(const Register& rd,
294 const Register& rn,
295 const Register& rm,
296 Condition cond);
297 inline void Dmb(BarrierDomain domain, BarrierType type);
298 inline void Dsb(BarrierDomain domain, BarrierType type);
299 inline void Debug(const char* message, uint32_t code, Instr params = BREAK);
300 inline void Extr(const Register& rd,
301 const Register& rn,
302 const Register& rm,
303 unsigned lsb);
304 inline void Fabs(const FPRegister& fd, const FPRegister& fn);
305 inline void Fadd(const FPRegister& fd,
306 const FPRegister& fn,
307 const FPRegister& fm);
308 inline void Fccmp(const FPRegister& fn,
309 const FPRegister& fm,
310 StatusFlags nzcv,
311 Condition cond);
312 inline void Fcmp(const FPRegister& fn, const FPRegister& fm);
313 inline void Fcmp(const FPRegister& fn, double value);
314 inline void Fcsel(const FPRegister& fd,
315 const FPRegister& fn,
316 const FPRegister& fm,
317 Condition cond);
318 inline void Fcvt(const FPRegister& fd, const FPRegister& fn);
319 inline void Fcvtas(const Register& rd, const FPRegister& fn);
320 inline void Fcvtau(const Register& rd, const FPRegister& fn);
321 inline void Fcvtms(const Register& rd, const FPRegister& fn);
322 inline void Fcvtmu(const Register& rd, const FPRegister& fn);
323 inline void Fcvtns(const Register& rd, const FPRegister& fn);
324 inline void Fcvtnu(const Register& rd, const FPRegister& fn);
325 inline void Fcvtzs(const Register& rd, const FPRegister& fn);
326 inline void Fcvtzu(const Register& rd, const FPRegister& fn);
327 inline void Fdiv(const FPRegister& fd,
328 const FPRegister& fn,
329 const FPRegister& fm);
330 inline void Fmadd(const FPRegister& fd,
331 const FPRegister& fn,
332 const FPRegister& fm,
333 const FPRegister& fa);
334 inline void Fmax(const FPRegister& fd,
335 const FPRegister& fn,
336 const FPRegister& fm);
337 inline void Fmaxnm(const FPRegister& fd,
338 const FPRegister& fn,
339 const FPRegister& fm);
340 inline void Fmin(const FPRegister& fd,
341 const FPRegister& fn,
342 const FPRegister& fm);
343 inline void Fminnm(const FPRegister& fd,
344 const FPRegister& fn,
345 const FPRegister& fm);
346 inline void Fmov(FPRegister fd, FPRegister fn);
347 inline void Fmov(FPRegister fd, Register rn);
348 // Provide explicit double and float interfaces for FP immediate moves, rather
349 // than relying on implicit C++ casts. This allows signalling NaNs to be
350 // preserved when the immediate matches the format of fd. Most systems convert
351 // signalling NaNs to quiet NaNs when converting between float and double.
352 inline void Fmov(FPRegister fd, double imm);
353 inline void Fmov(FPRegister fd, float imm);
354 // Provide a template to allow other types to be converted automatically.
355 template<typename T>
Fmov(FPRegister fd,T imm)356 void Fmov(FPRegister fd, T imm) {
357 ASSERT(allow_macro_instructions_);
358 Fmov(fd, static_cast<double>(imm));
359 }
360 inline void Fmov(Register rd, FPRegister fn);
361 inline void Fmsub(const FPRegister& fd,
362 const FPRegister& fn,
363 const FPRegister& fm,
364 const FPRegister& fa);
365 inline void Fmul(const FPRegister& fd,
366 const FPRegister& fn,
367 const FPRegister& fm);
368 inline void Fneg(const FPRegister& fd, const FPRegister& fn);
369 inline void Fnmadd(const FPRegister& fd,
370 const FPRegister& fn,
371 const FPRegister& fm,
372 const FPRegister& fa);
373 inline void Fnmsub(const FPRegister& fd,
374 const FPRegister& fn,
375 const FPRegister& fm,
376 const FPRegister& fa);
377 inline void Frinta(const FPRegister& fd, const FPRegister& fn);
378 inline void Frintm(const FPRegister& fd, const FPRegister& fn);
379 inline void Frintn(const FPRegister& fd, const FPRegister& fn);
380 inline void Frintz(const FPRegister& fd, const FPRegister& fn);
381 inline void Fsqrt(const FPRegister& fd, const FPRegister& fn);
382 inline void Fsub(const FPRegister& fd,
383 const FPRegister& fn,
384 const FPRegister& fm);
385 inline void Hint(SystemHint code);
386 inline void Hlt(int code);
387 inline void Isb();
388 inline void Ldnp(const CPURegister& rt,
389 const CPURegister& rt2,
390 const MemOperand& src);
391 inline void Ldp(const CPURegister& rt,
392 const CPURegister& rt2,
393 const MemOperand& src);
394 inline void Ldpsw(const Register& rt,
395 const Register& rt2,
396 const MemOperand& src);
397 // Load a literal from the inline constant pool.
398 inline void Ldr(const CPURegister& rt, const Immediate& imm);
399 // Helper function for double immediate.
400 inline void Ldr(const CPURegister& rt, double imm);
401 inline void Lsl(const Register& rd, const Register& rn, unsigned shift);
402 inline void Lsl(const Register& rd, const Register& rn, const Register& rm);
403 inline void Lsr(const Register& rd, const Register& rn, unsigned shift);
404 inline void Lsr(const Register& rd, const Register& rn, const Register& rm);
405 inline void Madd(const Register& rd,
406 const Register& rn,
407 const Register& rm,
408 const Register& ra);
409 inline void Mneg(const Register& rd, const Register& rn, const Register& rm);
410 inline void Mov(const Register& rd, const Register& rm);
411 inline void Movk(const Register& rd, uint64_t imm, int shift = -1);
412 inline void Mrs(const Register& rt, SystemRegister sysreg);
413 inline void Msr(SystemRegister sysreg, const Register& rt);
414 inline void Msub(const Register& rd,
415 const Register& rn,
416 const Register& rm,
417 const Register& ra);
418 inline void Mul(const Register& rd, const Register& rn, const Register& rm);
Nop()419 inline void Nop() { nop(); }
420 inline void Rbit(const Register& rd, const Register& rn);
421 inline void Ret(const Register& xn = lr);
422 inline void Rev(const Register& rd, const Register& rn);
423 inline void Rev16(const Register& rd, const Register& rn);
424 inline void Rev32(const Register& rd, const Register& rn);
425 inline void Ror(const Register& rd, const Register& rs, unsigned shift);
426 inline void Ror(const Register& rd, const Register& rn, const Register& rm);
427 inline void Sbfiz(const Register& rd,
428 const Register& rn,
429 unsigned lsb,
430 unsigned width);
431 inline void Sbfx(const Register& rd,
432 const Register& rn,
433 unsigned lsb,
434 unsigned width);
435 inline void Scvtf(const FPRegister& fd,
436 const Register& rn,
437 unsigned fbits = 0);
438 inline void Sdiv(const Register& rd, const Register& rn, const Register& rm);
439 inline void Smaddl(const Register& rd,
440 const Register& rn,
441 const Register& rm,
442 const Register& ra);
443 inline void Smsubl(const Register& rd,
444 const Register& rn,
445 const Register& rm,
446 const Register& ra);
447 inline void Smull(const Register& rd,
448 const Register& rn,
449 const Register& rm);
450 inline void Smulh(const Register& rd,
451 const Register& rn,
452 const Register& rm);
453 inline void Stnp(const CPURegister& rt,
454 const CPURegister& rt2,
455 const MemOperand& dst);
456 inline void Stp(const CPURegister& rt,
457 const CPURegister& rt2,
458 const MemOperand& dst);
459 inline void Sxtb(const Register& rd, const Register& rn);
460 inline void Sxth(const Register& rd, const Register& rn);
461 inline void Sxtw(const Register& rd, const Register& rn);
462 void Tbnz(const Register& rt, unsigned bit_pos, Label* label);
463 void Tbz(const Register& rt, unsigned bit_pos, Label* label);
464 inline void Ubfiz(const Register& rd,
465 const Register& rn,
466 unsigned lsb,
467 unsigned width);
468 inline void Ubfx(const Register& rd,
469 const Register& rn,
470 unsigned lsb,
471 unsigned width);
472 inline void Ucvtf(const FPRegister& fd,
473 const Register& rn,
474 unsigned fbits = 0);
475 inline void Udiv(const Register& rd, const Register& rn, const Register& rm);
476 inline void Umaddl(const Register& rd,
477 const Register& rn,
478 const Register& rm,
479 const Register& ra);
480 inline void Umsubl(const Register& rd,
481 const Register& rn,
482 const Register& rm,
483 const Register& ra);
484 inline void Uxtb(const Register& rd, const Register& rn);
485 inline void Uxth(const Register& rd, const Register& rn);
486 inline void Uxtw(const Register& rd, const Register& rn);
487
488 // Pseudo-instructions ------------------------------------------------------
489
490 // Compute rd = abs(rm).
491 // This function clobbers the condition flags. On output the overflow flag is
492 // set iff the negation overflowed.
493 //
494 // If rm is the minimum representable value, the result is not representable.
495 // Handlers for each case can be specified using the relevant labels.
496 void Abs(const Register& rd, const Register& rm,
497 Label * is_not_representable = NULL,
498 Label * is_representable = NULL);
499
500 // Push or pop up to 4 registers of the same width to or from the stack,
501 // using the current stack pointer as set by SetStackPointer.
502 //
503 // If an argument register is 'NoReg', all further arguments are also assumed
504 // to be 'NoReg', and are thus not pushed or popped.
505 //
506 // Arguments are ordered such that "Push(a, b);" is functionally equivalent
507 // to "Push(a); Push(b);".
508 //
509 // It is valid to push the same register more than once, and there is no
510 // restriction on the order in which registers are specified.
511 //
512 // It is not valid to pop into the same register more than once in one
513 // operation, not even into the zero register.
514 //
515 // If the current stack pointer (as set by SetStackPointer) is csp, then it
516 // must be aligned to 16 bytes on entry and the total size of the specified
517 // registers must also be a multiple of 16 bytes.
518 //
519 // Even if the current stack pointer is not the system stack pointer (csp),
520 // Push (and derived methods) will still modify the system stack pointer in
521 // order to comply with ABI rules about accessing memory below the system
522 // stack pointer.
523 //
524 // Other than the registers passed into Pop, the stack pointer and (possibly)
525 // the system stack pointer, these methods do not modify any other registers.
526 void Push(const CPURegister& src0, const CPURegister& src1 = NoReg,
527 const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg);
528 void Push(const CPURegister& src0, const CPURegister& src1,
529 const CPURegister& src2, const CPURegister& src3,
530 const CPURegister& src4, const CPURegister& src5 = NoReg,
531 const CPURegister& src6 = NoReg, const CPURegister& src7 = NoReg);
532 void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg,
533 const CPURegister& dst2 = NoReg, const CPURegister& dst3 = NoReg);
534
535 // Alternative forms of Push and Pop, taking a RegList or CPURegList that
536 // specifies the registers that are to be pushed or popped. Higher-numbered
537 // registers are associated with higher memory addresses (as in the A32 push
538 // and pop instructions).
539 //
540 // (Push|Pop)SizeRegList allow you to specify the register size as a
541 // parameter. Only kXRegSizeInBits, kWRegSizeInBits, kDRegSizeInBits and
542 // kSRegSizeInBits are supported.
543 //
544 // Otherwise, (Push|Pop)(CPU|X|W|D|S)RegList is preferred.
545 void PushCPURegList(CPURegList registers);
546 void PopCPURegList(CPURegList registers);
547
548 inline void PushSizeRegList(RegList registers, unsigned reg_size,
549 CPURegister::RegisterType type = CPURegister::kRegister) {
550 PushCPURegList(CPURegList(type, reg_size, registers));
551 }
552 inline void PopSizeRegList(RegList registers, unsigned reg_size,
553 CPURegister::RegisterType type = CPURegister::kRegister) {
554 PopCPURegList(CPURegList(type, reg_size, registers));
555 }
PushXRegList(RegList regs)556 inline void PushXRegList(RegList regs) {
557 PushSizeRegList(regs, kXRegSizeInBits);
558 }
PopXRegList(RegList regs)559 inline void PopXRegList(RegList regs) {
560 PopSizeRegList(regs, kXRegSizeInBits);
561 }
PushWRegList(RegList regs)562 inline void PushWRegList(RegList regs) {
563 PushSizeRegList(regs, kWRegSizeInBits);
564 }
PopWRegList(RegList regs)565 inline void PopWRegList(RegList regs) {
566 PopSizeRegList(regs, kWRegSizeInBits);
567 }
PushDRegList(RegList regs)568 inline void PushDRegList(RegList regs) {
569 PushSizeRegList(regs, kDRegSizeInBits, CPURegister::kFPRegister);
570 }
PopDRegList(RegList regs)571 inline void PopDRegList(RegList regs) {
572 PopSizeRegList(regs, kDRegSizeInBits, CPURegister::kFPRegister);
573 }
PushSRegList(RegList regs)574 inline void PushSRegList(RegList regs) {
575 PushSizeRegList(regs, kSRegSizeInBits, CPURegister::kFPRegister);
576 }
PopSRegList(RegList regs)577 inline void PopSRegList(RegList regs) {
578 PopSizeRegList(regs, kSRegSizeInBits, CPURegister::kFPRegister);
579 }
580
581 // Push the specified register 'count' times.
582 void PushMultipleTimes(CPURegister src, Register count);
583 void PushMultipleTimes(CPURegister src, int count);
584
585 // This is a convenience method for pushing a single Handle<Object>.
586 inline void Push(Handle<Object> handle);
Push(Smi * smi)587 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
588
589 // Aliases of Push and Pop, required for V8 compatibility.
push(Register src)590 inline void push(Register src) {
591 Push(src);
592 }
pop(Register dst)593 inline void pop(Register dst) {
594 Pop(dst);
595 }
596
597 // Sometimes callers need to push or pop multiple registers in a way that is
598 // difficult to structure efficiently for fixed Push or Pop calls. This scope
599 // allows push requests to be queued up, then flushed at once. The
600 // MacroAssembler will try to generate the most efficient sequence required.
601 //
602 // Unlike the other Push and Pop macros, PushPopQueue can handle mixed sets of
603 // register sizes and types.
604 class PushPopQueue {
605 public:
PushPopQueue(MacroAssembler * masm)606 explicit PushPopQueue(MacroAssembler* masm) : masm_(masm), size_(0) { }
607
~PushPopQueue()608 ~PushPopQueue() {
609 ASSERT(queued_.empty());
610 }
611
Queue(const CPURegister & rt)612 void Queue(const CPURegister& rt) {
613 size_ += rt.SizeInBytes();
614 queued_.push_back(rt);
615 }
616
617 enum PreambleDirective {
618 WITH_PREAMBLE,
619 SKIP_PREAMBLE
620 };
621 void PushQueued(PreambleDirective preamble_directive = WITH_PREAMBLE);
622 void PopQueued();
623
624 private:
625 MacroAssembler* masm_;
626 int size_;
627 std::vector<CPURegister> queued_;
628 };
629
630 // Poke 'src' onto the stack. The offset is in bytes.
631 //
632 // If the current stack pointer (according to StackPointer()) is csp, then
633 // csp must be aligned to 16 bytes.
634 void Poke(const CPURegister& src, const Operand& offset);
635
636 // Peek at a value on the stack, and put it in 'dst'. The offset is in bytes.
637 //
638 // If the current stack pointer (according to StackPointer()) is csp, then
639 // csp must be aligned to 16 bytes.
640 void Peek(const CPURegister& dst, const Operand& offset);
641
642 // Poke 'src1' and 'src2' onto the stack. The values written will be adjacent
643 // with 'src2' at a higher address than 'src1'. The offset is in bytes.
644 //
645 // If the current stack pointer (according to StackPointer()) is csp, then
646 // csp must be aligned to 16 bytes.
647 void PokePair(const CPURegister& src1, const CPURegister& src2, int offset);
648
649 // Peek at two values on the stack, and put them in 'dst1' and 'dst2'. The
650 // values peeked will be adjacent, with the value in 'dst2' being from a
651 // higher address than 'dst1'. The offset is in bytes.
652 //
653 // If the current stack pointer (according to StackPointer()) is csp, then
654 // csp must be aligned to 16 bytes.
655 void PeekPair(const CPURegister& dst1, const CPURegister& dst2, int offset);
656
657 // Claim or drop stack space without actually accessing memory.
658 //
659 // In debug mode, both of these will write invalid data into the claimed or
660 // dropped space.
661 //
662 // If the current stack pointer (according to StackPointer()) is csp, then it
663 // must be aligned to 16 bytes and the size claimed or dropped must be a
664 // multiple of 16 bytes.
665 //
666 // Note that unit_size must be specified in bytes. For variants which take a
667 // Register count, the unit size must be a power of two.
668 inline void Claim(uint64_t count, uint64_t unit_size = kXRegSize);
669 inline void Claim(const Register& count,
670 uint64_t unit_size = kXRegSize);
671 inline void Drop(uint64_t count, uint64_t unit_size = kXRegSize);
672 inline void Drop(const Register& count,
673 uint64_t unit_size = kXRegSize);
674
675 // Variants of Claim and Drop, where the 'count' parameter is a SMI held in a
676 // register.
677 inline void ClaimBySMI(const Register& count_smi,
678 uint64_t unit_size = kXRegSize);
679 inline void DropBySMI(const Register& count_smi,
680 uint64_t unit_size = kXRegSize);
681
682 // Compare a register with an operand, and branch to label depending on the
683 // condition. May corrupt the status flags.
684 inline void CompareAndBranch(const Register& lhs,
685 const Operand& rhs,
686 Condition cond,
687 Label* label);
688
689 // Test the bits of register defined by bit_pattern, and branch if ANY of
690 // those bits are set. May corrupt the status flags.
691 inline void TestAndBranchIfAnySet(const Register& reg,
692 const uint64_t bit_pattern,
693 Label* label);
694
695 // Test the bits of register defined by bit_pattern, and branch if ALL of
696 // those bits are clear (ie. not set.) May corrupt the status flags.
697 inline void TestAndBranchIfAllClear(const Register& reg,
698 const uint64_t bit_pattern,
699 Label* label);
700
701 // Insert one or more instructions into the instruction stream that encode
702 // some caller-defined data. The instructions used will be executable with no
703 // side effects.
704 inline void InlineData(uint64_t data);
705
706 // Insert an instrumentation enable marker into the instruction stream.
707 inline void EnableInstrumentation();
708
709 // Insert an instrumentation disable marker into the instruction stream.
710 inline void DisableInstrumentation();
711
712 // Insert an instrumentation event marker into the instruction stream. These
713 // will be picked up by the instrumentation system to annotate an instruction
714 // profile. The argument marker_name must be a printable two character string;
715 // it will be encoded in the event marker.
716 inline void AnnotateInstrumentation(const char* marker_name);
717
718 // If emit_debug_code() is true, emit a run-time check to ensure that
719 // StackPointer() does not point below the system stack pointer.
720 //
721 // Whilst it is architecturally legal for StackPointer() to point below csp,
722 // it can be evidence of a potential bug because the ABI forbids accesses
723 // below csp.
724 //
725 // If StackPointer() is the system stack pointer (csp) or ALWAYS_ALIGN_CSP is
726 // enabled, then csp will be dereferenced to cause the processor
727 // (or simulator) to abort if it is not properly aligned.
728 //
729 // If emit_debug_code() is false, this emits no code.
730 void AssertStackConsistency();
731
732 // Preserve the callee-saved registers (as defined by AAPCS64).
733 //
734 // Higher-numbered registers are pushed before lower-numbered registers, and
735 // thus get higher addresses.
736 // Floating-point registers are pushed before general-purpose registers, and
737 // thus get higher addresses.
738 //
739 // Note that registers are not checked for invalid values. Use this method
740 // only if you know that the GC won't try to examine the values on the stack.
741 //
742 // This method must not be called unless the current stack pointer (as set by
743 // SetStackPointer) is the system stack pointer (csp), and is aligned to
744 // ActivationFrameAlignment().
745 void PushCalleeSavedRegisters();
746
747 // Restore the callee-saved registers (as defined by AAPCS64).
748 //
749 // Higher-numbered registers are popped after lower-numbered registers, and
750 // thus come from higher addresses.
751 // Floating-point registers are popped after general-purpose registers, and
752 // thus come from higher addresses.
753 //
754 // This method must not be called unless the current stack pointer (as set by
755 // SetStackPointer) is the system stack pointer (csp), and is aligned to
756 // ActivationFrameAlignment().
757 void PopCalleeSavedRegisters();
758
759 // Set the current stack pointer, but don't generate any code.
SetStackPointer(const Register & stack_pointer)760 inline void SetStackPointer(const Register& stack_pointer) {
761 ASSERT(!TmpList()->IncludesAliasOf(stack_pointer));
762 sp_ = stack_pointer;
763 }
764
765 // Return the current stack pointer, as set by SetStackPointer.
StackPointer()766 inline const Register& StackPointer() const {
767 return sp_;
768 }
769
770 // Align csp for a frame, as per ActivationFrameAlignment, and make it the
771 // current stack pointer.
AlignAndSetCSPForFrame()772 inline void AlignAndSetCSPForFrame() {
773 int sp_alignment = ActivationFrameAlignment();
774 // AAPCS64 mandates at least 16-byte alignment.
775 ASSERT(sp_alignment >= 16);
776 ASSERT(IsPowerOf2(sp_alignment));
777 Bic(csp, StackPointer(), sp_alignment - 1);
778 SetStackPointer(csp);
779 }
780
781 // Push the system stack pointer (csp) down to allow the same to be done to
782 // the current stack pointer (according to StackPointer()). This must be
783 // called _before_ accessing the memory.
784 //
785 // This is necessary when pushing or otherwise adding things to the stack, to
786 // satisfy the AAPCS64 constraint that the memory below the system stack
787 // pointer is not accessed. The amount pushed will be increased as necessary
788 // to ensure csp remains aligned to 16 bytes.
789 //
790 // This method asserts that StackPointer() is not csp, since the call does
791 // not make sense in that context.
792 inline void BumpSystemStackPointer(const Operand& space);
793
794 // Re-synchronizes the system stack pointer (csp) with the current stack
795 // pointer (according to StackPointer()). This function will ensure the
796 // new value of the system stack pointer is remains aligned to 16 bytes, and
797 // is lower than or equal to the value of the current stack pointer.
798 //
799 // This method asserts that StackPointer() is not csp, since the call does
800 // not make sense in that context.
801 inline void SyncSystemStackPointer();
802
803 // Helpers ------------------------------------------------------------------
804 // Root register.
805 inline void InitializeRootRegister();
806
807 void AssertFPCRState(Register fpcr = NoReg);
808 void ConfigureFPCR();
809 void CanonicalizeNaN(const FPRegister& dst, const FPRegister& src);
CanonicalizeNaN(const FPRegister & reg)810 void CanonicalizeNaN(const FPRegister& reg) {
811 CanonicalizeNaN(reg, reg);
812 }
813
814 // Load an object from the root table.
815 void LoadRoot(CPURegister destination,
816 Heap::RootListIndex index);
817 // Store an object to the root table.
818 void StoreRoot(Register source,
819 Heap::RootListIndex index);
820
821 // Load both TrueValue and FalseValue roots.
822 void LoadTrueFalseRoots(Register true_root, Register false_root);
823
824 void LoadHeapObject(Register dst, Handle<HeapObject> object);
825
LoadObject(Register result,Handle<Object> object)826 void LoadObject(Register result, Handle<Object> object) {
827 AllowDeferredHandleDereference heap_object_check;
828 if (object->IsHeapObject()) {
829 LoadHeapObject(result, Handle<HeapObject>::cast(object));
830 } else {
831 ASSERT(object->IsSmi());
832 Mov(result, Operand(object));
833 }
834 }
835
836 static int SafepointRegisterStackIndex(int reg_code);
837
838 // This is required for compatibility with architecture independant code.
839 // Remove if not needed.
Move(Register dst,Register src)840 inline void Move(Register dst, Register src) { Mov(dst, src); }
841
842 void LoadInstanceDescriptors(Register map,
843 Register descriptors);
844 void EnumLengthUntagged(Register dst, Register map);
845 void EnumLengthSmi(Register dst, Register map);
846 void NumberOfOwnDescriptors(Register dst, Register map);
847
848 template<typename Field>
DecodeField(Register dst,Register src)849 void DecodeField(Register dst, Register src) {
850 static const uint64_t shift = Field::kShift;
851 static const uint64_t setbits = CountSetBits(Field::kMask, 32);
852 Ubfx(dst, src, shift, setbits);
853 }
854
855 template<typename Field>
DecodeField(Register reg)856 void DecodeField(Register reg) {
857 DecodeField<Field>(reg, reg);
858 }
859
860 // ---- SMI and Number Utilities ----
861
862 inline void SmiTag(Register dst, Register src);
863 inline void SmiTag(Register smi);
864 inline void SmiUntag(Register dst, Register src);
865 inline void SmiUntag(Register smi);
866 inline void SmiUntagToDouble(FPRegister dst,
867 Register src,
868 UntagMode mode = kNotSpeculativeUntag);
869 inline void SmiUntagToFloat(FPRegister dst,
870 Register src,
871 UntagMode mode = kNotSpeculativeUntag);
872
873 // Tag and push in one step.
874 inline void SmiTagAndPush(Register src);
875 inline void SmiTagAndPush(Register src1, Register src2);
876
877 // Compute the absolute value of 'smi' and leave the result in 'smi'
878 // register. If 'smi' is the most negative SMI, the absolute value cannot
879 // be represented as a SMI and a jump to 'slow' is done.
880 void SmiAbs(const Register& smi, Label* slow);
881
882 inline void JumpIfSmi(Register value,
883 Label* smi_label,
884 Label* not_smi_label = NULL);
885 inline void JumpIfNotSmi(Register value, Label* not_smi_label);
886 inline void JumpIfBothSmi(Register value1,
887 Register value2,
888 Label* both_smi_label,
889 Label* not_smi_label = NULL);
890 inline void JumpIfEitherSmi(Register value1,
891 Register value2,
892 Label* either_smi_label,
893 Label* not_smi_label = NULL);
894 inline void JumpIfEitherNotSmi(Register value1,
895 Register value2,
896 Label* not_smi_label);
897 inline void JumpIfBothNotSmi(Register value1,
898 Register value2,
899 Label* not_smi_label);
900
901 // Abort execution if argument is a smi, enabled via --debug-code.
902 void AssertNotSmi(Register object, BailoutReason reason = kOperandIsASmi);
903 void AssertSmi(Register object, BailoutReason reason = kOperandIsNotASmi);
904
905 inline void ObjectTag(Register tagged_obj, Register obj);
906 inline void ObjectUntag(Register untagged_obj, Register obj);
907
908 // Abort execution if argument is not a name, enabled via --debug-code.
909 void AssertName(Register object);
910
911 // Abort execution if argument is not undefined or an AllocationSite, enabled
912 // via --debug-code.
913 void AssertUndefinedOrAllocationSite(Register object, Register scratch);
914
915 // Abort execution if argument is not a string, enabled via --debug-code.
916 void AssertString(Register object);
917
918 void JumpForHeapNumber(Register object,
919 Register heap_number_map,
920 Label* on_heap_number,
921 Label* on_not_heap_number = NULL);
922 void JumpIfHeapNumber(Register object,
923 Label* on_heap_number,
924 Register heap_number_map = NoReg);
925 void JumpIfNotHeapNumber(Register object,
926 Label* on_not_heap_number,
927 Register heap_number_map = NoReg);
928
929 // Sets the vs flag if the input is -0.0.
930 void TestForMinusZero(DoubleRegister input);
931
932 // Jump to label if the input double register contains -0.0.
933 void JumpIfMinusZero(DoubleRegister input, Label* on_negative_zero);
934
935 // Jump to label if the input integer register contains the double precision
936 // floating point representation of -0.0.
937 void JumpIfMinusZero(Register input, Label* on_negative_zero);
938
939 // Generate code to do a lookup in the number string cache. If the number in
940 // the register object is found in the cache the generated code falls through
941 // with the result in the result register. The object and the result register
942 // can be the same. If the number is not found in the cache the code jumps to
943 // the label not_found with only the content of register object unchanged.
944 void LookupNumberStringCache(Register object,
945 Register result,
946 Register scratch1,
947 Register scratch2,
948 Register scratch3,
949 Label* not_found);
950
951 // Saturate a signed 32-bit integer in input to an unsigned 8-bit integer in
952 // output.
953 void ClampInt32ToUint8(Register in_out);
954 void ClampInt32ToUint8(Register output, Register input);
955
956 // Saturate a double in input to an unsigned 8-bit integer in output.
957 void ClampDoubleToUint8(Register output,
958 DoubleRegister input,
959 DoubleRegister dbl_scratch);
960
961 // Try to represent a double as a signed 32-bit int.
962 // This succeeds if the result compares equal to the input, so inputs of -0.0
963 // are represented as 0 and handled as a success.
964 //
965 // On output the Z flag is set if the operation was successful.
966 void TryRepresentDoubleAsInt32(Register as_int,
967 FPRegister value,
968 FPRegister scratch_d,
969 Label* on_successful_conversion = NULL,
970 Label* on_failed_conversion = NULL) {
971 ASSERT(as_int.Is32Bits());
972 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion,
973 on_failed_conversion);
974 }
975
976 // Try to represent a double as a signed 64-bit int.
977 // This succeeds if the result compares equal to the input, so inputs of -0.0
978 // are represented as 0 and handled as a success.
979 //
980 // On output the Z flag is set if the operation was successful.
981 void TryRepresentDoubleAsInt64(Register as_int,
982 FPRegister value,
983 FPRegister scratch_d,
984 Label* on_successful_conversion = NULL,
985 Label* on_failed_conversion = NULL) {
986 ASSERT(as_int.Is64Bits());
987 TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion,
988 on_failed_conversion);
989 }
990
991 // ---- Object Utilities ----
992
993 // Copy fields from 'src' to 'dst', where both are tagged objects.
994 // The 'temps' list is a list of X registers which can be used for scratch
995 // values. The temps list must include at least one register.
996 //
997 // Currently, CopyFields cannot make use of more than three registers from
998 // the 'temps' list.
999 //
1000 // CopyFields expects to be able to take at least two registers from
1001 // MacroAssembler::TmpList().
1002 void CopyFields(Register dst, Register src, CPURegList temps, unsigned count);
1003
1004 // Starting at address in dst, initialize field_count 64-bit fields with
1005 // 64-bit value in register filler. Register dst is corrupted.
1006 void FillFields(Register dst,
1007 Register field_count,
1008 Register filler);
1009
1010 // Copies a number of bytes from src to dst. All passed registers are
1011 // clobbered. On exit src and dst will point to the place just after where the
1012 // last byte was read or written and length will be zero. Hint may be used to
1013 // determine which is the most efficient algorithm to use for copying.
1014 void CopyBytes(Register dst,
1015 Register src,
1016 Register length,
1017 Register scratch,
1018 CopyHint hint = kCopyUnknown);
1019
1020 // ---- String Utilities ----
1021
1022
1023 // Jump to label if either object is not a sequential ASCII string.
1024 // Optionally perform a smi check on the objects first.
1025 void JumpIfEitherIsNotSequentialAsciiStrings(
1026 Register first,
1027 Register second,
1028 Register scratch1,
1029 Register scratch2,
1030 Label* failure,
1031 SmiCheckType smi_check = DO_SMI_CHECK);
1032
1033 // Check if instance type is sequential ASCII string and jump to label if
1034 // it is not.
1035 void JumpIfInstanceTypeIsNotSequentialAscii(Register type,
1036 Register scratch,
1037 Label* failure);
1038
1039 // Checks if both instance types are sequential ASCII strings and jumps to
1040 // label if either is not.
1041 void JumpIfEitherInstanceTypeIsNotSequentialAscii(
1042 Register first_object_instance_type,
1043 Register second_object_instance_type,
1044 Register scratch1,
1045 Register scratch2,
1046 Label* failure);
1047
1048 // Checks if both instance types are sequential ASCII strings and jumps to
1049 // label if either is not.
1050 void JumpIfBothInstanceTypesAreNotSequentialAscii(
1051 Register first_object_instance_type,
1052 Register second_object_instance_type,
1053 Register scratch1,
1054 Register scratch2,
1055 Label* failure);
1056
1057 void JumpIfNotUniqueName(Register type, Label* not_unique_name);
1058
1059 // ---- Calling / Jumping helpers ----
1060
1061 // This is required for compatibility in architecture indepenedant code.
jmp(Label * L)1062 inline void jmp(Label* L) { B(L); }
1063
1064 // Passes thrown value to the handler of top of the try handler chain.
1065 // Register value must be x0.
1066 void Throw(Register value,
1067 Register scratch1,
1068 Register scratch2,
1069 Register scratch3,
1070 Register scratch4);
1071
1072 // Propagates an uncatchable exception to the top of the current JS stack's
1073 // handler chain. Register value must be x0.
1074 void ThrowUncatchable(Register value,
1075 Register scratch1,
1076 Register scratch2,
1077 Register scratch3,
1078 Register scratch4);
1079
1080 void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
1081 void TailCallStub(CodeStub* stub);
1082
1083 void CallRuntime(const Runtime::Function* f,
1084 int num_arguments,
1085 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
1086
1087 void CallRuntime(Runtime::FunctionId id,
1088 int num_arguments,
1089 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
1090 CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
1091 }
1092
CallRuntimeSaveDoubles(Runtime::FunctionId id)1093 void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
1094 const Runtime::Function* function = Runtime::FunctionForId(id);
1095 CallRuntime(function, function->nargs, kSaveFPRegs);
1096 }
1097
1098 void TailCallRuntime(Runtime::FunctionId fid,
1099 int num_arguments,
1100 int result_size);
1101
1102 int ActivationFrameAlignment();
1103
1104 // Calls a C function.
1105 // The called function is not allowed to trigger a
1106 // garbage collection, since that might move the code and invalidate the
1107 // return address (unless this is somehow accounted for by the called
1108 // function).
1109 void CallCFunction(ExternalReference function,
1110 int num_reg_arguments);
1111 void CallCFunction(ExternalReference function,
1112 int num_reg_arguments,
1113 int num_double_arguments);
1114 void CallCFunction(Register function,
1115 int num_reg_arguments,
1116 int num_double_arguments);
1117
1118 // Calls an API function. Allocates HandleScope, extracts returned value
1119 // from handle and propagates exceptions.
1120 // 'stack_space' is the space to be unwound on exit (includes the call JS
1121 // arguments space and the additional space allocated for the fast call).
1122 // 'spill_offset' is the offset from the stack pointer where
1123 // CallApiFunctionAndReturn can spill registers.
1124 void CallApiFunctionAndReturn(Register function_address,
1125 ExternalReference thunk_ref,
1126 int stack_space,
1127 int spill_offset,
1128 MemOperand return_value_operand,
1129 MemOperand* context_restore_operand);
1130
1131 // The number of register that CallApiFunctionAndReturn will need to save on
1132 // the stack. The space for these registers need to be allocated in the
1133 // ExitFrame before calling CallApiFunctionAndReturn.
1134 static const int kCallApiFunctionSpillSpace = 4;
1135
1136 // Jump to a runtime routine.
1137 void JumpToExternalReference(const ExternalReference& builtin);
1138 // Tail call of a runtime routine (jump).
1139 // Like JumpToExternalReference, but also takes care of passing the number
1140 // of parameters.
1141 void TailCallExternalReference(const ExternalReference& ext,
1142 int num_arguments,
1143 int result_size);
1144 void CallExternalReference(const ExternalReference& ext,
1145 int num_arguments);
1146
1147
1148 // Invoke specified builtin JavaScript function. Adds an entry to
1149 // the unresolved list if the name does not resolve.
1150 void InvokeBuiltin(Builtins::JavaScript id,
1151 InvokeFlag flag,
1152 const CallWrapper& call_wrapper = NullCallWrapper());
1153
1154 // Store the code object for the given builtin in the target register and
1155 // setup the function in the function register.
1156 void GetBuiltinEntry(Register target,
1157 Register function,
1158 Builtins::JavaScript id);
1159
1160 // Store the function for the given builtin in the target register.
1161 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
1162
1163 void Jump(Register target);
1164 void Jump(Address target, RelocInfo::Mode rmode);
1165 void Jump(Handle<Code> code, RelocInfo::Mode rmode);
1166 void Jump(intptr_t target, RelocInfo::Mode rmode);
1167
1168 void Call(Register target);
1169 void Call(Label* target);
1170 void Call(Address target, RelocInfo::Mode rmode);
1171 void Call(Handle<Code> code,
1172 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
1173 TypeFeedbackId ast_id = TypeFeedbackId::None());
1174
1175 // For every Call variant, there is a matching CallSize function that returns
1176 // the size (in bytes) of the call sequence.
1177 static int CallSize(Register target);
1178 static int CallSize(Label* target);
1179 static int CallSize(Address target, RelocInfo::Mode rmode);
1180 static int CallSize(Handle<Code> code,
1181 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
1182 TypeFeedbackId ast_id = TypeFeedbackId::None());
1183
1184 // Registers used through the invocation chain are hard-coded.
1185 // We force passing the parameters to ensure the contracts are correctly
1186 // honoured by the caller.
1187 // 'function' must be x1.
1188 // 'actual' must use an immediate or x0.
1189 // 'expected' must use an immediate or x2.
1190 // 'call_kind' must be x5.
1191 void InvokePrologue(const ParameterCount& expected,
1192 const ParameterCount& actual,
1193 Handle<Code> code_constant,
1194 Register code_reg,
1195 Label* done,
1196 InvokeFlag flag,
1197 bool* definitely_mismatches,
1198 const CallWrapper& call_wrapper);
1199 void InvokeCode(Register code,
1200 const ParameterCount& expected,
1201 const ParameterCount& actual,
1202 InvokeFlag flag,
1203 const CallWrapper& call_wrapper);
1204 // Invoke the JavaScript function in the given register.
1205 // Changes the current context to the context in the function before invoking.
1206 void InvokeFunction(Register function,
1207 const ParameterCount& actual,
1208 InvokeFlag flag,
1209 const CallWrapper& call_wrapper);
1210 void InvokeFunction(Register function,
1211 const ParameterCount& expected,
1212 const ParameterCount& actual,
1213 InvokeFlag flag,
1214 const CallWrapper& call_wrapper);
1215 void InvokeFunction(Handle<JSFunction> function,
1216 const ParameterCount& expected,
1217 const ParameterCount& actual,
1218 InvokeFlag flag,
1219 const CallWrapper& call_wrapper);
1220
1221
1222 // ---- Floating point helpers ----
1223
1224 // Perform a conversion from a double to a signed int64. If the input fits in
1225 // range of the 64-bit result, execution branches to done. Otherwise,
1226 // execution falls through, and the sign of the result can be used to
1227 // determine if overflow was towards positive or negative infinity.
1228 //
1229 // On successful conversion, the least significant 32 bits of the result are
1230 // equivalent to the ECMA-262 operation "ToInt32".
1231 //
1232 // Only public for the test code in test-code-stubs-arm64.cc.
1233 void TryConvertDoubleToInt64(Register result,
1234 DoubleRegister input,
1235 Label* done);
1236
1237 // Performs a truncating conversion of a floating point number as used by
1238 // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
1239 // Exits with 'result' holding the answer.
1240 void TruncateDoubleToI(Register result, DoubleRegister double_input);
1241
1242 // Performs a truncating conversion of a heap number as used by
1243 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
1244 // must be different registers. Exits with 'result' holding the answer.
1245 void TruncateHeapNumberToI(Register result, Register object);
1246
1247 // Converts the smi or heap number in object to an int32 using the rules
1248 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
1249 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
1250 // different registers.
1251 void TruncateNumberToI(Register object,
1252 Register result,
1253 Register heap_number_map,
1254 Label* not_int32);
1255
1256 // ---- Code generation helpers ----
1257
set_generating_stub(bool value)1258 void set_generating_stub(bool value) { generating_stub_ = value; }
generating_stub()1259 bool generating_stub() const { return generating_stub_; }
1260 #if DEBUG
set_allow_macro_instructions(bool value)1261 void set_allow_macro_instructions(bool value) {
1262 allow_macro_instructions_ = value;
1263 }
allow_macro_instructions()1264 bool allow_macro_instructions() const { return allow_macro_instructions_; }
1265 #endif
use_real_aborts()1266 bool use_real_aborts() const { return use_real_aborts_; }
set_has_frame(bool value)1267 void set_has_frame(bool value) { has_frame_ = value; }
has_frame()1268 bool has_frame() const { return has_frame_; }
1269 bool AllowThisStubCall(CodeStub* stub);
1270
1271 class NoUseRealAbortsScope {
1272 public:
NoUseRealAbortsScope(MacroAssembler * masm)1273 explicit NoUseRealAbortsScope(MacroAssembler* masm) :
1274 saved_(masm->use_real_aborts_), masm_(masm) {
1275 masm_->use_real_aborts_ = false;
1276 }
~NoUseRealAbortsScope()1277 ~NoUseRealAbortsScope() {
1278 masm_->use_real_aborts_ = saved_;
1279 }
1280 private:
1281 bool saved_;
1282 MacroAssembler* masm_;
1283 };
1284
1285 // ---------------------------------------------------------------------------
1286 // Debugger Support
1287
1288 void DebugBreak();
1289
1290 // ---------------------------------------------------------------------------
1291 // Exception handling
1292
1293 // Push a new try handler and link into try handler chain.
1294 void PushTryHandler(StackHandler::Kind kind, int handler_index);
1295
1296 // Unlink the stack handler on top of the stack from the try handler chain.
1297 // Must preserve the result register.
1298 void PopTryHandler();
1299
1300
1301 // ---------------------------------------------------------------------------
1302 // Allocation support
1303
1304 // Allocate an object in new space or old pointer space. The object_size is
1305 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
1306 // is passed. The allocated object is returned in result.
1307 //
1308 // If the new space is exhausted control continues at the gc_required label.
1309 // In this case, the result and scratch registers may still be clobbered.
1310 // If flags includes TAG_OBJECT, the result is tagged as as a heap object.
1311 void Allocate(Register object_size,
1312 Register result,
1313 Register scratch1,
1314 Register scratch2,
1315 Label* gc_required,
1316 AllocationFlags flags);
1317
1318 void Allocate(int object_size,
1319 Register result,
1320 Register scratch1,
1321 Register scratch2,
1322 Label* gc_required,
1323 AllocationFlags flags);
1324
1325 // Undo allocation in new space. The object passed and objects allocated after
1326 // it will no longer be allocated. The caller must make sure that no pointers
1327 // are left to the object(s) no longer allocated as they would be invalid when
1328 // allocation is undone.
1329 void UndoAllocationInNewSpace(Register object, Register scratch);
1330
1331 void AllocateTwoByteString(Register result,
1332 Register length,
1333 Register scratch1,
1334 Register scratch2,
1335 Register scratch3,
1336 Label* gc_required);
1337 void AllocateAsciiString(Register result,
1338 Register length,
1339 Register scratch1,
1340 Register scratch2,
1341 Register scratch3,
1342 Label* gc_required);
1343 void AllocateTwoByteConsString(Register result,
1344 Register length,
1345 Register scratch1,
1346 Register scratch2,
1347 Label* gc_required);
1348 void AllocateAsciiConsString(Register result,
1349 Register length,
1350 Register scratch1,
1351 Register scratch2,
1352 Label* gc_required);
1353 void AllocateTwoByteSlicedString(Register result,
1354 Register length,
1355 Register scratch1,
1356 Register scratch2,
1357 Label* gc_required);
1358 void AllocateAsciiSlicedString(Register result,
1359 Register length,
1360 Register scratch1,
1361 Register scratch2,
1362 Label* gc_required);
1363
1364 // Allocates a heap number or jumps to the gc_required label if the young
1365 // space is full and a scavenge is needed.
1366 // All registers are clobbered.
1367 // If no heap_number_map register is provided, the function will take care of
1368 // loading it.
1369 void AllocateHeapNumber(Register result,
1370 Label* gc_required,
1371 Register scratch1,
1372 Register scratch2,
1373 CPURegister value = NoFPReg,
1374 CPURegister heap_number_map = NoReg);
1375
1376 // ---------------------------------------------------------------------------
1377 // Support functions.
1378
1379 // Try to get function prototype of a function and puts the value in the
1380 // result register. Checks that the function really is a function and jumps
1381 // to the miss label if the fast checks fail. The function register will be
1382 // untouched; the other registers may be clobbered.
1383 enum BoundFunctionAction {
1384 kMissOnBoundFunction,
1385 kDontMissOnBoundFunction
1386 };
1387
1388 void TryGetFunctionPrototype(Register function,
1389 Register result,
1390 Register scratch,
1391 Label* miss,
1392 BoundFunctionAction action =
1393 kDontMissOnBoundFunction);
1394
1395 // Compare object type for heap object. heap_object contains a non-Smi
1396 // whose object type should be compared with the given type. This both
1397 // sets the flags and leaves the object type in the type_reg register.
1398 // It leaves the map in the map register (unless the type_reg and map register
1399 // are the same register). It leaves the heap object in the heap_object
1400 // register unless the heap_object register is the same register as one of the
1401 // other registers.
1402 void CompareObjectType(Register heap_object,
1403 Register map,
1404 Register type_reg,
1405 InstanceType type);
1406
1407
1408 // Compare object type for heap object, and branch if equal (or not.)
1409 // heap_object contains a non-Smi whose object type should be compared with
1410 // the given type. This both sets the flags and leaves the object type in
1411 // the type_reg register. It leaves the map in the map register (unless the
1412 // type_reg and map register are the same register). It leaves the heap
1413 // object in the heap_object register unless the heap_object register is the
1414 // same register as one of the other registers.
1415 void JumpIfObjectType(Register object,
1416 Register map,
1417 Register type_reg,
1418 InstanceType type,
1419 Label* if_cond_pass,
1420 Condition cond = eq);
1421
1422 void JumpIfNotObjectType(Register object,
1423 Register map,
1424 Register type_reg,
1425 InstanceType type,
1426 Label* if_not_object);
1427
1428 // Compare instance type in a map. map contains a valid map object whose
1429 // object type should be compared with the given type. This both
1430 // sets the flags and leaves the object type in the type_reg register.
1431 void CompareInstanceType(Register map,
1432 Register type_reg,
1433 InstanceType type);
1434
1435 // Compare an object's map with the specified map. Condition flags are set
1436 // with result of map compare.
1437 void CompareMap(Register obj,
1438 Register scratch,
1439 Handle<Map> map);
1440
1441 // As above, but the map of the object is already loaded into the register
1442 // which is preserved by the code generated.
1443 void CompareMap(Register obj_map,
1444 Handle<Map> map);
1445
1446 // Check if the map of an object is equal to a specified map and branch to
1447 // label if not. Skip the smi check if not required (object is known to be a
1448 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
1449 // against maps that are ElementsKind transition maps of the specified map.
1450 void CheckMap(Register obj,
1451 Register scratch,
1452 Handle<Map> map,
1453 Label* fail,
1454 SmiCheckType smi_check_type);
1455
1456
1457 void CheckMap(Register obj,
1458 Register scratch,
1459 Heap::RootListIndex index,
1460 Label* fail,
1461 SmiCheckType smi_check_type);
1462
1463 // As above, but the map of the object is already loaded into obj_map, and is
1464 // preserved.
1465 void CheckMap(Register obj_map,
1466 Handle<Map> map,
1467 Label* fail,
1468 SmiCheckType smi_check_type);
1469
1470 // Check if the map of an object is equal to a specified map and branch to a
1471 // specified target if equal. Skip the smi check if not required (object is
1472 // known to be a heap object)
1473 void DispatchMap(Register obj,
1474 Register scratch,
1475 Handle<Map> map,
1476 Handle<Code> success,
1477 SmiCheckType smi_check_type);
1478
1479 // Test the bitfield of the heap object map with mask and set the condition
1480 // flags. The object register is preserved.
1481 void TestMapBitfield(Register object, uint64_t mask);
1482
1483 // Load the elements kind field from a map, and return it in the result
1484 // register.
1485 void LoadElementsKindFromMap(Register result, Register map);
1486
1487 // Compare the object in a register to a value from the root list.
1488 void CompareRoot(const Register& obj, Heap::RootListIndex index);
1489
1490 // Compare the object in a register to a value and jump if they are equal.
1491 void JumpIfRoot(const Register& obj,
1492 Heap::RootListIndex index,
1493 Label* if_equal);
1494
1495 // Compare the object in a register to a value and jump if they are not equal.
1496 void JumpIfNotRoot(const Register& obj,
1497 Heap::RootListIndex index,
1498 Label* if_not_equal);
1499
1500 // Load and check the instance type of an object for being a unique name.
1501 // Loads the type into the second argument register.
1502 // The object and type arguments can be the same register; in that case it
1503 // will be overwritten with the type.
1504 // Fall-through if the object was a string and jump on fail otherwise.
1505 inline void IsObjectNameType(Register object, Register type, Label* fail);
1506
1507 inline void IsObjectJSObjectType(Register heap_object,
1508 Register map,
1509 Register scratch,
1510 Label* fail);
1511
1512 // Check the instance type in the given map to see if it corresponds to a
1513 // JS object type. Jump to the fail label if this is not the case and fall
1514 // through otherwise. However if fail label is NULL, no branch will be
1515 // performed and the flag will be updated. You can test the flag for "le"
1516 // condition to test if it is a valid JS object type.
1517 inline void IsInstanceJSObjectType(Register map,
1518 Register scratch,
1519 Label* fail);
1520
1521 // Load and check the instance type of an object for being a string.
1522 // Loads the type into the second argument register.
1523 // The object and type arguments can be the same register; in that case it
1524 // will be overwritten with the type.
1525 // Jumps to not_string or string appropriate. If the appropriate label is
1526 // NULL, fall through.
1527 inline void IsObjectJSStringType(Register object, Register type,
1528 Label* not_string, Label* string = NULL);
1529
1530 // Compare the contents of a register with an operand, and branch to true,
1531 // false or fall through, depending on condition.
1532 void CompareAndSplit(const Register& lhs,
1533 const Operand& rhs,
1534 Condition cond,
1535 Label* if_true,
1536 Label* if_false,
1537 Label* fall_through);
1538
1539 // Test the bits of register defined by bit_pattern, and branch to
1540 // if_any_set, if_all_clear or fall_through accordingly.
1541 void TestAndSplit(const Register& reg,
1542 uint64_t bit_pattern,
1543 Label* if_all_clear,
1544 Label* if_any_set,
1545 Label* fall_through);
1546
1547 // Check if a map for a JSObject indicates that the object has fast elements.
1548 // Jump to the specified label if it does not.
1549 void CheckFastElements(Register map, Register scratch, Label* fail);
1550
1551 // Check if a map for a JSObject indicates that the object can have both smi
1552 // and HeapObject elements. Jump to the specified label if it does not.
1553 void CheckFastObjectElements(Register map, Register scratch, Label* fail);
1554
1555 // Check to see if number can be stored as a double in FastDoubleElements.
1556 // If it can, store it at the index specified by key_reg in the array,
1557 // otherwise jump to fail.
1558 void StoreNumberToDoubleElements(Register value_reg,
1559 Register key_reg,
1560 Register elements_reg,
1561 Register scratch1,
1562 FPRegister fpscratch1,
1563 Label* fail,
1564 int elements_offset = 0);
1565
1566 // Picks out an array index from the hash field.
1567 // Register use:
1568 // hash - holds the index's hash. Clobbered.
1569 // index - holds the overwritten index on exit.
1570 void IndexFromHash(Register hash, Register index);
1571
1572 // ---------------------------------------------------------------------------
1573 // Inline caching support.
1574
1575 void EmitSeqStringSetCharCheck(Register string,
1576 Register index,
1577 SeqStringSetCharCheckIndexType index_type,
1578 Register scratch,
1579 uint32_t encoding_mask);
1580
1581 // Generate code for checking access rights - used for security checks
1582 // on access to global objects across environments. The holder register
1583 // is left untouched, whereas both scratch registers are clobbered.
1584 void CheckAccessGlobalProxy(Register holder_reg,
1585 Register scratch1,
1586 Register scratch2,
1587 Label* miss);
1588
1589 // Hash the interger value in 'key' register.
1590 // It uses the same algorithm as ComputeIntegerHash in utils.h.
1591 void GetNumberHash(Register key, Register scratch);
1592
1593 // Load value from the dictionary.
1594 //
1595 // elements - holds the slow-case elements of the receiver on entry.
1596 // Unchanged unless 'result' is the same register.
1597 //
1598 // key - holds the smi key on entry.
1599 // Unchanged unless 'result' is the same register.
1600 //
1601 // result - holds the result on exit if the load succeeded.
1602 // Allowed to be the same as 'key' or 'result'.
1603 // Unchanged on bailout so 'key' or 'result' can be used
1604 // in further computation.
1605 void LoadFromNumberDictionary(Label* miss,
1606 Register elements,
1607 Register key,
1608 Register result,
1609 Register scratch0,
1610 Register scratch1,
1611 Register scratch2,
1612 Register scratch3);
1613
1614 // ---------------------------------------------------------------------------
1615 // Frames.
1616
1617 // Activation support.
1618 void EnterFrame(StackFrame::Type type);
1619 void LeaveFrame(StackFrame::Type type);
1620
1621 // Returns map with validated enum cache in object register.
1622 void CheckEnumCache(Register object,
1623 Register null_value,
1624 Register scratch0,
1625 Register scratch1,
1626 Register scratch2,
1627 Register scratch3,
1628 Label* call_runtime);
1629
1630 // AllocationMemento support. Arrays may have an associated
1631 // AllocationMemento object that can be checked for in order to pretransition
1632 // to another type.
1633 // On entry, receiver should point to the array object.
1634 // If allocation info is present, the Z flag is set (so that the eq
1635 // condition will pass).
1636 void TestJSArrayForAllocationMemento(Register receiver,
1637 Register scratch1,
1638 Register scratch2,
1639 Label* no_memento_found);
1640
JumpIfJSArrayHasAllocationMemento(Register receiver,Register scratch1,Register scratch2,Label * memento_found)1641 void JumpIfJSArrayHasAllocationMemento(Register receiver,
1642 Register scratch1,
1643 Register scratch2,
1644 Label* memento_found) {
1645 Label no_memento_found;
1646 TestJSArrayForAllocationMemento(receiver, scratch1, scratch2,
1647 &no_memento_found);
1648 B(eq, memento_found);
1649 Bind(&no_memento_found);
1650 }
1651
1652 // The stack pointer has to switch between csp and jssp when setting up and
1653 // destroying the exit frame. Hence preserving/restoring the registers is
1654 // slightly more complicated than simple push/pop operations.
1655 void ExitFramePreserveFPRegs();
1656 void ExitFrameRestoreFPRegs();
1657
1658 // Generates function and stub prologue code.
1659 void StubPrologue();
1660 void Prologue(bool code_pre_aging);
1661
1662 // Enter exit frame. Exit frames are used when calling C code from generated
1663 // (JavaScript) code.
1664 //
1665 // The stack pointer must be jssp on entry, and will be set to csp by this
1666 // function. The frame pointer is also configured, but the only other
1667 // registers modified by this function are the provided scratch register, and
1668 // jssp.
1669 //
1670 // The 'extra_space' argument can be used to allocate some space in the exit
1671 // frame that will be ignored by the GC. This space will be reserved in the
1672 // bottom of the frame immediately above the return address slot.
1673 //
1674 // Set up a stack frame and registers as follows:
1675 // fp[8]: CallerPC (lr)
1676 // fp -> fp[0]: CallerFP (old fp)
1677 // fp[-8]: SPOffset (new csp)
1678 // fp[-16]: CodeObject()
1679 // fp[-16 - fp-size]: Saved doubles, if saved_doubles is true.
1680 // csp[8]: Memory reserved for the caller if extra_space != 0.
1681 // Alignment padding, if necessary.
1682 // csp -> csp[0]: Space reserved for the return address.
1683 //
1684 // This function also stores the new frame information in the top frame, so
1685 // that the new frame becomes the current frame.
1686 void EnterExitFrame(bool save_doubles,
1687 const Register& scratch,
1688 int extra_space = 0);
1689
1690 // Leave the current exit frame, after a C function has returned to generated
1691 // (JavaScript) code.
1692 //
1693 // This effectively unwinds the operation of EnterExitFrame:
1694 // * Preserved doubles are restored (if restore_doubles is true).
1695 // * The frame information is removed from the top frame.
1696 // * The exit frame is dropped.
1697 // * The stack pointer is reset to jssp.
1698 //
1699 // The stack pointer must be csp on entry.
1700 void LeaveExitFrame(bool save_doubles,
1701 const Register& scratch,
1702 bool restore_context);
1703
1704 void LoadContext(Register dst, int context_chain_length);
1705
1706 // Emit code for a truncating division by a constant. The dividend register is
1707 // unchanged. Dividend and result must be different.
1708 void TruncatingDiv(Register result, Register dividend, int32_t divisor);
1709
1710 // ---------------------------------------------------------------------------
1711 // StatsCounter support
1712
1713 void SetCounter(StatsCounter* counter, int value, Register scratch1,
1714 Register scratch2);
1715 void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
1716 Register scratch2);
1717 void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
1718 Register scratch2);
1719
1720 // ---------------------------------------------------------------------------
1721 // Garbage collector support (GC).
1722
1723 enum RememberedSetFinalAction {
1724 kReturnAtEnd,
1725 kFallThroughAtEnd
1726 };
1727
1728 // Record in the remembered set the fact that we have a pointer to new space
1729 // at the address pointed to by the addr register. Only works if addr is not
1730 // in new space.
1731 void RememberedSetHelper(Register object, // Used for debug code.
1732 Register addr,
1733 Register scratch1,
1734 SaveFPRegsMode save_fp,
1735 RememberedSetFinalAction and_then);
1736
1737 // Push and pop the registers that can hold pointers, as defined by the
1738 // RegList constant kSafepointSavedRegisters.
1739 void PushSafepointRegisters();
1740 void PopSafepointRegisters();
1741
1742 void PushSafepointRegistersAndDoubles();
1743 void PopSafepointRegistersAndDoubles();
1744
1745 // Store value in register src in the safepoint stack slot for register dst.
StoreToSafepointRegisterSlot(Register src,Register dst)1746 void StoreToSafepointRegisterSlot(Register src, Register dst) {
1747 Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
1748 }
1749
1750 // Load the value of the src register from its safepoint stack slot
1751 // into register dst.
LoadFromSafepointRegisterSlot(Register dst,Register src)1752 void LoadFromSafepointRegisterSlot(Register dst, Register src) {
1753 Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
1754 }
1755
1756 void CheckPageFlagSet(const Register& object,
1757 const Register& scratch,
1758 int mask,
1759 Label* if_any_set);
1760
1761 void CheckPageFlagClear(const Register& object,
1762 const Register& scratch,
1763 int mask,
1764 Label* if_all_clear);
1765
1766 void CheckMapDeprecated(Handle<Map> map,
1767 Register scratch,
1768 Label* if_deprecated);
1769
1770 // Check if object is in new space and jump accordingly.
1771 // Register 'object' is preserved.
JumpIfNotInNewSpace(Register object,Label * branch)1772 void JumpIfNotInNewSpace(Register object,
1773 Label* branch) {
1774 InNewSpace(object, ne, branch);
1775 }
1776
JumpIfInNewSpace(Register object,Label * branch)1777 void JumpIfInNewSpace(Register object,
1778 Label* branch) {
1779 InNewSpace(object, eq, branch);
1780 }
1781
1782 // Notify the garbage collector that we wrote a pointer into an object.
1783 // |object| is the object being stored into, |value| is the object being
1784 // stored. value and scratch registers are clobbered by the operation.
1785 // The offset is the offset from the start of the object, not the offset from
1786 // the tagged HeapObject pointer. For use with FieldOperand(reg, off).
1787 void RecordWriteField(
1788 Register object,
1789 int offset,
1790 Register value,
1791 Register scratch,
1792 LinkRegisterStatus lr_status,
1793 SaveFPRegsMode save_fp,
1794 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
1795 SmiCheck smi_check = INLINE_SMI_CHECK,
1796 PointersToHereCheck pointers_to_here_check_for_value =
1797 kPointersToHereMaybeInteresting);
1798
1799 // As above, but the offset has the tag presubtracted. For use with
1800 // MemOperand(reg, off).
1801 inline void RecordWriteContextSlot(
1802 Register context,
1803 int offset,
1804 Register value,
1805 Register scratch,
1806 LinkRegisterStatus lr_status,
1807 SaveFPRegsMode save_fp,
1808 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
1809 SmiCheck smi_check = INLINE_SMI_CHECK,
1810 PointersToHereCheck pointers_to_here_check_for_value =
1811 kPointersToHereMaybeInteresting) {
1812 RecordWriteField(context,
1813 offset + kHeapObjectTag,
1814 value,
1815 scratch,
1816 lr_status,
1817 save_fp,
1818 remembered_set_action,
1819 smi_check,
1820 pointers_to_here_check_for_value);
1821 }
1822
1823 void RecordWriteForMap(
1824 Register object,
1825 Register map,
1826 Register dst,
1827 LinkRegisterStatus lr_status,
1828 SaveFPRegsMode save_fp);
1829
1830 // For a given |object| notify the garbage collector that the slot |address|
1831 // has been written. |value| is the object being stored. The value and
1832 // address registers are clobbered by the operation.
1833 void RecordWrite(
1834 Register object,
1835 Register address,
1836 Register value,
1837 LinkRegisterStatus lr_status,
1838 SaveFPRegsMode save_fp,
1839 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
1840 SmiCheck smi_check = INLINE_SMI_CHECK,
1841 PointersToHereCheck pointers_to_here_check_for_value =
1842 kPointersToHereMaybeInteresting);
1843
1844 // Checks the color of an object. If the object is already grey or black
1845 // then we just fall through, since it is already live. If it is white and
1846 // we can determine that it doesn't need to be scanned, then we just mark it
1847 // black and fall through. For the rest we jump to the label so the
1848 // incremental marker can fix its assumptions.
1849 void EnsureNotWhite(Register object,
1850 Register scratch1,
1851 Register scratch2,
1852 Register scratch3,
1853 Register scratch4,
1854 Label* object_is_white_and_not_data);
1855
1856 // Detects conservatively whether an object is data-only, i.e. it does need to
1857 // be scanned by the garbage collector.
1858 void JumpIfDataObject(Register value,
1859 Register scratch,
1860 Label* not_data_object);
1861
1862 // Helper for finding the mark bits for an address.
1863 // Note that the behaviour slightly differs from other architectures.
1864 // On exit:
1865 // - addr_reg is unchanged.
1866 // - The bitmap register points at the word with the mark bits.
1867 // - The shift register contains the index of the first color bit for this
1868 // object in the bitmap.
1869 inline void GetMarkBits(Register addr_reg,
1870 Register bitmap_reg,
1871 Register shift_reg);
1872
1873 // Check if an object has a given incremental marking color.
1874 void HasColor(Register object,
1875 Register scratch0,
1876 Register scratch1,
1877 Label* has_color,
1878 int first_bit,
1879 int second_bit);
1880
1881 void JumpIfBlack(Register object,
1882 Register scratch0,
1883 Register scratch1,
1884 Label* on_black);
1885
1886
1887 // Get the location of a relocated constant (its address in the constant pool)
1888 // from its load site.
1889 void GetRelocatedValueLocation(Register ldr_location,
1890 Register result);
1891
1892
1893 // ---------------------------------------------------------------------------
1894 // Debugging.
1895
1896 // Calls Abort(msg) if the condition cond is not satisfied.
1897 // Use --debug_code to enable.
1898 void Assert(Condition cond, BailoutReason reason);
1899 void AssertRegisterIsClear(Register reg, BailoutReason reason);
1900 void AssertRegisterIsRoot(
1901 Register reg,
1902 Heap::RootListIndex index,
1903 BailoutReason reason = kRegisterDidNotMatchExpectedRoot);
1904 void AssertFastElements(Register elements);
1905
1906 // Abort if the specified register contains the invalid color bit pattern.
1907 // The pattern must be in bits [1:0] of 'reg' register.
1908 //
1909 // If emit_debug_code() is false, this emits no code.
1910 void AssertHasValidColor(const Register& reg);
1911
1912 // Abort if 'object' register doesn't point to a string object.
1913 //
1914 // If emit_debug_code() is false, this emits no code.
1915 void AssertIsString(const Register& object);
1916
1917 // Like Assert(), but always enabled.
1918 void Check(Condition cond, BailoutReason reason);
1919 void CheckRegisterIsClear(Register reg, BailoutReason reason);
1920
1921 // Print a message to stderr and abort execution.
1922 void Abort(BailoutReason reason);
1923
1924 // Conditionally load the cached Array transitioned map of type
1925 // transitioned_kind from the native context if the map in register
1926 // map_in_out is the cached Array map in the native context of
1927 // expected_kind.
1928 void LoadTransitionedArrayMapConditional(
1929 ElementsKind expected_kind,
1930 ElementsKind transitioned_kind,
1931 Register map_in_out,
1932 Register scratch1,
1933 Register scratch2,
1934 Label* no_map_match);
1935
1936 void LoadGlobalFunction(int index, Register function);
1937
1938 // Load the initial map from the global function. The registers function and
1939 // map can be the same, function is then overwritten.
1940 void LoadGlobalFunctionInitialMap(Register function,
1941 Register map,
1942 Register scratch);
1943
TmpList()1944 CPURegList* TmpList() { return &tmp_list_; }
FPTmpList()1945 CPURegList* FPTmpList() { return &fptmp_list_; }
1946
1947 static CPURegList DefaultTmpList();
1948 static CPURegList DefaultFPTmpList();
1949
1950 // Like printf, but print at run-time from generated code.
1951 //
1952 // The caller must ensure that arguments for floating-point placeholders
1953 // (such as %e, %f or %g) are FPRegisters, and that arguments for integer
1954 // placeholders are Registers.
1955 //
1956 // At the moment it is only possible to print the value of csp if it is the
1957 // current stack pointer. Otherwise, the MacroAssembler will automatically
1958 // update csp on every push (using BumpSystemStackPointer), so determining its
1959 // value is difficult.
1960 //
1961 // Format placeholders that refer to more than one argument, or to a specific
1962 // argument, are not supported. This includes formats like "%1$d" or "%.*d".
1963 //
1964 // This function automatically preserves caller-saved registers so that
1965 // calling code can use Printf at any point without having to worry about
1966 // corruption. The preservation mechanism generates a lot of code. If this is
1967 // a problem, preserve the important registers manually and then call
1968 // PrintfNoPreserve. Callee-saved registers are not used by Printf, and are
1969 // implicitly preserved.
1970 void Printf(const char * format,
1971 CPURegister arg0 = NoCPUReg,
1972 CPURegister arg1 = NoCPUReg,
1973 CPURegister arg2 = NoCPUReg,
1974 CPURegister arg3 = NoCPUReg);
1975
1976 // Like Printf, but don't preserve any caller-saved registers, not even 'lr'.
1977 //
1978 // The return code from the system printf call will be returned in x0.
1979 void PrintfNoPreserve(const char * format,
1980 const CPURegister& arg0 = NoCPUReg,
1981 const CPURegister& arg1 = NoCPUReg,
1982 const CPURegister& arg2 = NoCPUReg,
1983 const CPURegister& arg3 = NoCPUReg);
1984
1985 // Code ageing support functions.
1986
1987 // Code ageing on ARM64 works similarly to on ARM. When V8 wants to mark a
1988 // function as old, it replaces some of the function prologue (generated by
1989 // FullCodeGenerator::Generate) with a call to a special stub (ultimately
1990 // generated by GenerateMakeCodeYoungAgainCommon). The stub restores the
1991 // function prologue to its initial young state (indicating that it has been
1992 // recently run) and continues. A young function is therefore one which has a
1993 // normal frame setup sequence, and an old function has a code age sequence
1994 // which calls a code ageing stub.
1995
1996 // Set up a basic stack frame for young code (or code exempt from ageing) with
1997 // type FUNCTION. It may be patched later for code ageing support. This is
1998 // done by to Code::PatchPlatformCodeAge and EmitCodeAgeSequence.
1999 //
2000 // This function takes an Assembler so it can be called from either a
2001 // MacroAssembler or a PatchingAssembler context.
2002 static void EmitFrameSetupForCodeAgePatching(Assembler* assm);
2003
2004 // Call EmitFrameSetupForCodeAgePatching from a MacroAssembler context.
2005 void EmitFrameSetupForCodeAgePatching();
2006
2007 // Emit a code age sequence that calls the relevant code age stub. The code
2008 // generated by this sequence is expected to replace the code generated by
2009 // EmitFrameSetupForCodeAgePatching, and represents an old function.
2010 //
2011 // If stub is NULL, this function generates the code age sequence but omits
2012 // the stub address that is normally embedded in the instruction stream. This
2013 // can be used by debug code to verify code age sequences.
2014 static void EmitCodeAgeSequence(Assembler* assm, Code* stub);
2015
2016 // Call EmitCodeAgeSequence from a MacroAssembler context.
2017 void EmitCodeAgeSequence(Code* stub);
2018
2019 // Return true if the sequence is a young sequence geneated by
2020 // EmitFrameSetupForCodeAgePatching. Otherwise, this method asserts that the
2021 // sequence is a code age sequence (emitted by EmitCodeAgeSequence).
2022 static bool IsYoungSequence(Isolate* isolate, byte* sequence);
2023
2024 // Jumps to found label if a prototype map has dictionary elements.
2025 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
2026 Register scratch1, Label* found);
2027
2028 // Perform necessary maintenance operations before a push or after a pop.
2029 //
2030 // Note that size is specified in bytes.
2031 void PushPreamble(Operand total_size);
2032 void PopPostamble(Operand total_size);
2033
PushPreamble(int count,int size)2034 void PushPreamble(int count, int size) { PushPreamble(count * size); }
PopPostamble(int count,int size)2035 void PopPostamble(int count, int size) { PopPostamble(count * size); }
2036
2037 private:
2038 // Helpers for CopyFields.
2039 // These each implement CopyFields in a different way.
2040 void CopyFieldsLoopPairsHelper(Register dst, Register src, unsigned count,
2041 Register scratch1, Register scratch2,
2042 Register scratch3, Register scratch4,
2043 Register scratch5);
2044 void CopyFieldsUnrolledPairsHelper(Register dst, Register src, unsigned count,
2045 Register scratch1, Register scratch2,
2046 Register scratch3, Register scratch4);
2047 void CopyFieldsUnrolledHelper(Register dst, Register src, unsigned count,
2048 Register scratch1, Register scratch2,
2049 Register scratch3);
2050
2051 // The actual Push and Pop implementations. These don't generate any code
2052 // other than that required for the push or pop. This allows
2053 // (Push|Pop)CPURegList to bundle together run-time assertions for a large
2054 // block of registers.
2055 //
2056 // Note that size is per register, and is specified in bytes.
2057 void PushHelper(int count, int size,
2058 const CPURegister& src0, const CPURegister& src1,
2059 const CPURegister& src2, const CPURegister& src3);
2060 void PopHelper(int count, int size,
2061 const CPURegister& dst0, const CPURegister& dst1,
2062 const CPURegister& dst2, const CPURegister& dst3);
2063
2064 // Call Printf. On a native build, a simple call will be generated, but if the
2065 // simulator is being used then a suitable pseudo-instruction is used. The
2066 // arguments and stack (csp) must be prepared by the caller as for a normal
2067 // AAPCS64 call to 'printf'.
2068 //
2069 // The 'args' argument should point to an array of variable arguments in their
2070 // proper PCS registers (and in calling order). The argument registers can
2071 // have mixed types. The format string (x0) should not be included.
2072 void CallPrintf(int arg_count = 0, const CPURegister * args = NULL);
2073
2074 // Helper for throwing exceptions. Compute a handler address and jump to
2075 // it. See the implementation for register usage.
2076 void JumpToHandlerEntry(Register exception,
2077 Register object,
2078 Register state,
2079 Register scratch1,
2080 Register scratch2);
2081
2082 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
2083 void InNewSpace(Register object,
2084 Condition cond, // eq for new space, ne otherwise.
2085 Label* branch);
2086
2087 // Try to represent a double as an int so that integer fast-paths may be
2088 // used. Not every valid integer value is guaranteed to be caught.
2089 // It supports both 32-bit and 64-bit integers depending whether 'as_int'
2090 // is a W or X register.
2091 //
2092 // This does not distinguish between +0 and -0, so if this distinction is
2093 // important it must be checked separately.
2094 //
2095 // On output the Z flag is set if the operation was successful.
2096 void TryRepresentDoubleAsInt(Register as_int,
2097 FPRegister value,
2098 FPRegister scratch_d,
2099 Label* on_successful_conversion = NULL,
2100 Label* on_failed_conversion = NULL);
2101
2102 bool generating_stub_;
2103 #if DEBUG
2104 // Tell whether any of the macro instruction can be used. When false the
2105 // MacroAssembler will assert if a method which can emit a variable number
2106 // of instructions is called.
2107 bool allow_macro_instructions_;
2108 #endif
2109 bool has_frame_;
2110
2111 // The Abort method should call a V8 runtime function, but the CallRuntime
2112 // mechanism depends on CEntryStub. If use_real_aborts is false, Abort will
2113 // use a simpler abort mechanism that doesn't depend on CEntryStub.
2114 //
2115 // The purpose of this is to allow Aborts to be compiled whilst CEntryStub is
2116 // being generated.
2117 bool use_real_aborts_;
2118
2119 // This handle will be patched with the code object on installation.
2120 Handle<Object> code_object_;
2121
2122 // The register to use as a stack pointer for stack operations.
2123 Register sp_;
2124
2125 // Scratch registers available for use by the MacroAssembler.
2126 CPURegList tmp_list_;
2127 CPURegList fptmp_list_;
2128
2129 void InitializeNewString(Register string,
2130 Register length,
2131 Heap::RootListIndex map_index,
2132 Register scratch1,
2133 Register scratch2);
2134
2135 public:
2136 // Far branches resolving.
2137 //
2138 // The various classes of branch instructions with immediate offsets have
2139 // different ranges. While the Assembler will fail to assemble a branch
2140 // exceeding its range, the MacroAssembler offers a mechanism to resolve
2141 // branches to too distant targets, either by tweaking the generated code to
2142 // use branch instructions with wider ranges or generating veneers.
2143 //
2144 // Currently branches to distant targets are resolved using unconditional
2145 // branch isntructions with a range of +-128MB. If that becomes too little
2146 // (!), the mechanism can be extended to generate special veneers for really
2147 // far targets.
2148
2149 // Helps resolve branching to labels potentially out of range.
2150 // If the label is not bound, it registers the information necessary to later
2151 // be able to emit a veneer for this branch if necessary.
2152 // If the label is bound, it returns true if the label (or the previous link
2153 // in the label chain) is out of range. In that case the caller is responsible
2154 // for generating appropriate code.
2155 // Otherwise it returns false.
2156 // This function also checks wether veneers need to be emitted.
2157 bool NeedExtraInstructionsOrRegisterBranch(Label *label,
2158 ImmBranchType branch_type);
2159 };
2160
2161
2162 // Use this scope when you need a one-to-one mapping bewteen methods and
2163 // instructions. This scope prevents the MacroAssembler from being called and
2164 // literal pools from being emitted. It also asserts the number of instructions
2165 // emitted is what you specified when creating the scope.
2166 class InstructionAccurateScope BASE_EMBEDDED {
2167 public:
2168 InstructionAccurateScope(MacroAssembler* masm, size_t count = 0)
masm_(masm)2169 : masm_(masm)
2170 #ifdef DEBUG
2171 ,
2172 size_(count * kInstructionSize)
2173 #endif
2174 {
2175 // Before blocking the const pool, see if it needs to be emitted.
2176 masm_->CheckConstPool(false, true);
2177 masm_->CheckVeneerPool(false, true);
2178
2179 masm_->StartBlockPools();
2180 #ifdef DEBUG
2181 if (count != 0) {
2182 masm_->bind(&start_);
2183 }
2184 previous_allow_macro_instructions_ = masm_->allow_macro_instructions();
2185 masm_->set_allow_macro_instructions(false);
2186 #endif
2187 }
2188
~InstructionAccurateScope()2189 ~InstructionAccurateScope() {
2190 masm_->EndBlockPools();
2191 #ifdef DEBUG
2192 if (start_.is_bound()) {
2193 ASSERT(masm_->SizeOfCodeGeneratedSince(&start_) == size_);
2194 }
2195 masm_->set_allow_macro_instructions(previous_allow_macro_instructions_);
2196 #endif
2197 }
2198
2199 private:
2200 MacroAssembler* masm_;
2201 #ifdef DEBUG
2202 size_t size_;
2203 Label start_;
2204 bool previous_allow_macro_instructions_;
2205 #endif
2206 };
2207
2208
2209 // This scope utility allows scratch registers to be managed safely. The
2210 // MacroAssembler's TmpList() (and FPTmpList()) is used as a pool of scratch
2211 // registers. These registers can be allocated on demand, and will be returned
2212 // at the end of the scope.
2213 //
2214 // When the scope ends, the MacroAssembler's lists will be restored to their
2215 // original state, even if the lists were modified by some other means.
2216 class UseScratchRegisterScope {
2217 public:
UseScratchRegisterScope(MacroAssembler * masm)2218 explicit UseScratchRegisterScope(MacroAssembler* masm)
2219 : available_(masm->TmpList()),
2220 availablefp_(masm->FPTmpList()),
2221 old_available_(available_->list()),
2222 old_availablefp_(availablefp_->list()) {
2223 ASSERT(available_->type() == CPURegister::kRegister);
2224 ASSERT(availablefp_->type() == CPURegister::kFPRegister);
2225 }
2226
2227 ~UseScratchRegisterScope();
2228
2229 // Take a register from the appropriate temps list. It will be returned
2230 // automatically when the scope ends.
AcquireW()2231 Register AcquireW() { return AcquireNextAvailable(available_).W(); }
AcquireX()2232 Register AcquireX() { return AcquireNextAvailable(available_).X(); }
AcquireS()2233 FPRegister AcquireS() { return AcquireNextAvailable(availablefp_).S(); }
AcquireD()2234 FPRegister AcquireD() { return AcquireNextAvailable(availablefp_).D(); }
2235
UnsafeAcquire(const Register & reg)2236 Register UnsafeAcquire(const Register& reg) {
2237 return Register(UnsafeAcquire(available_, reg));
2238 }
2239
2240 Register AcquireSameSizeAs(const Register& reg);
2241 FPRegister AcquireSameSizeAs(const FPRegister& reg);
2242
2243 private:
2244 static CPURegister AcquireNextAvailable(CPURegList* available);
2245 static CPURegister UnsafeAcquire(CPURegList* available,
2246 const CPURegister& reg);
2247
2248 // Available scratch registers.
2249 CPURegList* available_; // kRegister
2250 CPURegList* availablefp_; // kFPRegister
2251
2252 // The state of the available lists at the start of this scope.
2253 RegList old_available_; // kRegister
2254 RegList old_availablefp_; // kFPRegister
2255 };
2256
2257
ContextMemOperand(Register context,int index)2258 inline MemOperand ContextMemOperand(Register context, int index) {
2259 return MemOperand(context, Context::SlotOffset(index));
2260 }
2261
GlobalObjectMemOperand()2262 inline MemOperand GlobalObjectMemOperand() {
2263 return ContextMemOperand(cp, Context::GLOBAL_OBJECT_INDEX);
2264 }
2265
2266
2267 // Encode and decode information about patchable inline SMI checks.
2268 class InlineSmiCheckInfo {
2269 public:
2270 explicit InlineSmiCheckInfo(Address info);
2271
HasSmiCheck()2272 bool HasSmiCheck() const {
2273 return smi_check_ != NULL;
2274 }
2275
SmiRegister()2276 const Register& SmiRegister() const {
2277 return reg_;
2278 }
2279
SmiCheck()2280 Instruction* SmiCheck() const {
2281 return smi_check_;
2282 }
2283
2284 // Use MacroAssembler::InlineData to emit information about patchable inline
2285 // SMI checks. The caller may specify 'reg' as NoReg and an unbound 'site' to
2286 // indicate that there is no inline SMI check. Note that 'reg' cannot be csp.
2287 //
2288 // The generated patch information can be read using the InlineSMICheckInfo
2289 // class.
2290 static void Emit(MacroAssembler* masm, const Register& reg,
2291 const Label* smi_check);
2292
2293 // Emit information to indicate that there is no inline SMI check.
EmitNotInlined(MacroAssembler * masm)2294 static void EmitNotInlined(MacroAssembler* masm) {
2295 Label unbound;
2296 Emit(masm, NoReg, &unbound);
2297 }
2298
2299 private:
2300 Register reg_;
2301 Instruction* smi_check_;
2302
2303 // Fields in the data encoded by InlineData.
2304
2305 // A width of 5 (Rd_width) for the SMI register preclues the use of csp,
2306 // since kSPRegInternalCode is 63. However, csp should never hold a SMI or be
2307 // used in a patchable check. The Emit() method checks this.
2308 //
2309 // Note that the total size of the fields is restricted by the underlying
2310 // storage size handled by the BitField class, which is a uint32_t.
2311 class RegisterBits : public BitField<unsigned, 0, 5> {};
2312 class DeltaBits : public BitField<uint32_t, 5, 32-5> {};
2313 };
2314
2315 } } // namespace v8::internal
2316
2317 #ifdef GENERATED_CODE_COVERAGE
2318 #error "Unsupported option"
2319 #define CODE_COVERAGE_STRINGIFY(x) #x
2320 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
2321 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
2322 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
2323 #else
2324 #define ACCESS_MASM(masm) masm->
2325 #endif
2326
2327 #endif // V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
2328