1// Copyright 2014 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 INCLUDED_FROM_MACRO_ASSEMBLER_H
6#error This header must be included via macro-assembler.h
7#endif
8
9#ifndef V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
10#define V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
11
12#include "src/base/numbers/double.h"
13#include "src/codegen/bailout-reason.h"
14#include "src/codegen/ppc/assembler-ppc.h"
15#include "src/common/globals.h"
16#include "src/objects/contexts.h"
17
18namespace v8 {
19namespace internal {
20
21enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit };
22
23// ----------------------------------------------------------------------------
24// Static helper functions
25
26// Generate a MemOperand for loading a field from an object.
27inline MemOperand FieldMemOperand(Register object, int offset) {
28  return MemOperand(object, offset - kHeapObjectTag);
29}
30
31enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
32
33Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg,
34                                   Register reg3 = no_reg,
35                                   Register reg4 = no_reg,
36                                   Register reg5 = no_reg,
37                                   Register reg6 = no_reg);
38
39// These exist to provide portability between 32 and 64bit
40#if V8_TARGET_ARCH_PPC64
41#define ClearLeftImm clrldi
42#define ClearRightImm clrrdi
43#else
44#define ClearLeftImm clrlwi
45#define ClearRightImm clrrwi
46#endif
47
48class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
49 public:
50  using TurboAssemblerBase::TurboAssemblerBase;
51
52  void CallBuiltin(Builtin builtin, Condition cond);
53  void TailCallBuiltin(Builtin builtin);
54  void Popcnt32(Register dst, Register src);
55  void Popcnt64(Register dst, Register src);
56  // Converts the integer (untagged smi) in |src| to a double, storing
57  // the result to |dst|
58  void ConvertIntToDouble(Register src, DoubleRegister dst);
59
60  // Converts the unsigned integer (untagged smi) in |src| to
61  // a double, storing the result to |dst|
62  void ConvertUnsignedIntToDouble(Register src, DoubleRegister dst);
63
64  // Converts the integer (untagged smi) in |src| to
65  // a float, storing the result in |dst|
66  void ConvertIntToFloat(Register src, DoubleRegister dst);
67
68  // Converts the unsigned integer (untagged smi) in |src| to
69  // a float, storing the result in |dst|
70  void ConvertUnsignedIntToFloat(Register src, DoubleRegister dst);
71
72#if V8_TARGET_ARCH_PPC64
73  void ConvertInt64ToFloat(Register src, DoubleRegister double_dst);
74  void ConvertInt64ToDouble(Register src, DoubleRegister double_dst);
75  void ConvertUnsignedInt64ToFloat(Register src, DoubleRegister double_dst);
76  void ConvertUnsignedInt64ToDouble(Register src, DoubleRegister double_dst);
77#endif
78
79  // Converts the double_input to an integer.  Note that, upon return,
80  // the contents of double_dst will also hold the fixed point representation.
81  void ConvertDoubleToInt64(const DoubleRegister double_input,
82#if !V8_TARGET_ARCH_PPC64
83                            const Register dst_hi,
84#endif
85                            const Register dst, const DoubleRegister double_dst,
86                            FPRoundingMode rounding_mode = kRoundToZero);
87
88#if V8_TARGET_ARCH_PPC64
89  // Converts the double_input to an unsigned integer.  Note that, upon return,
90  // the contents of double_dst will also hold the fixed point representation.
91  void ConvertDoubleToUnsignedInt64(
92      const DoubleRegister double_input, const Register dst,
93      const DoubleRegister double_dst,
94      FPRoundingMode rounding_mode = kRoundToZero);
95#endif
96
97  // Activation support.
98  void EnterFrame(StackFrame::Type type,
99                  bool load_constant_pool_pointer_reg = false);
100
101  // Returns the pc offset at which the frame ends.
102  int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0);
103
104  void AllocateStackSpace(int bytes) {
105    DCHECK_GE(bytes, 0);
106    if (bytes == 0) return;
107    AddS64(sp, sp, Operand(-bytes), r0);
108  }
109
110  void AllocateStackSpace(Register bytes) { sub(sp, sp, bytes); }
111
112  // Push a fixed frame, consisting of lr, fp, constant pool.
113  void PushCommonFrame(Register marker_reg = no_reg);
114
115  // Generates function and stub prologue code.
116  void StubPrologue(StackFrame::Type type);
117  void Prologue();
118
119  enum ArgumentsCountMode { kCountIncludesReceiver, kCountExcludesReceiver };
120  enum ArgumentsCountType { kCountIsInteger, kCountIsSmi, kCountIsBytes };
121  void DropArguments(Register count, ArgumentsCountType type,
122                     ArgumentsCountMode mode);
123  void DropArgumentsAndPushNewReceiver(Register argc, Register receiver,
124                                       ArgumentsCountType type,
125                                       ArgumentsCountMode mode);
126
127  // Push a standard frame, consisting of lr, fp, constant pool,
128  // context and JS function
129  void PushStandardFrame(Register function_reg);
130
131  // Restore caller's frame pointer and return address prior to being
132  // overwritten by tail call stack preparation.
133  void RestoreFrameStateForTailCall();
134
135  // Get the actual activation frame alignment for target environment.
136  static int ActivationFrameAlignment();
137
138  void InitializeRootRegister() {
139    ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
140    mov(kRootRegister, Operand(isolate_root));
141  }
142
143  void LoadDoubleLiteral(DoubleRegister result, base::Double value,
144                         Register scratch);
145  void LoadSimd128(Simd128Register dst, const MemOperand& mem);
146
147  // load a literal signed int value <value> to GPR <dst>
148  void LoadIntLiteral(Register dst, int value);
149  // load an SMI value <value> to GPR <dst>
150  void LoadSmiLiteral(Register dst, Smi smi);
151
152  void LoadPC(Register dst);
153  void ComputeCodeStartAddress(Register dst);
154
155  void CmpS64(Register src1, const Operand& src2, Register scratch,
156              CRegister cr = cr7);
157  void CmpS64(Register src1, Register src2, CRegister cr = cr7);
158  void CmpU64(Register src1, const Operand& src2, Register scratch,
159              CRegister cr = cr7);
160  void CmpU64(Register src1, Register src2, CRegister cr = cr7);
161  void CmpS32(Register src1, const Operand& src2, Register scratch,
162              CRegister cr = cr7);
163  void CmpS32(Register src1, Register src2, CRegister cr = cr7);
164  void CmpU32(Register src1, const Operand& src2, Register scratch,
165              CRegister cr = cr7);
166  void CmpU32(Register src1, Register src2, CRegister cr = cr7);
167  void CompareTagged(Register src1, Register src2, CRegister cr = cr7) {
168    if (COMPRESS_POINTERS_BOOL) {
169      CmpS32(src1, src2, cr);
170    } else {
171      CmpS64(src1, src2, cr);
172    }
173  }
174
175  void MinF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
176              DoubleRegister scratch = kScratchDoubleReg);
177  void MaxF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
178              DoubleRegister scratch = kScratchDoubleReg);
179
180  // Set new rounding mode RN to FPSCR
181  void SetRoundingMode(FPRoundingMode RN);
182
183  // reset rounding mode to default (kRoundToNearest)
184  void ResetRoundingMode();
185
186  void AddS64(Register dst, Register src, const Operand& value,
187              Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
188  void AddS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
189              RCBit r = LeaveRC);
190  void SubS64(Register dst, Register src, const Operand& value,
191              Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
192  void SubS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
193              RCBit r = LeaveRC);
194  void AddS32(Register dst, Register src, const Operand& value,
195              Register scratch = r0, RCBit r = LeaveRC);
196  void AddS32(Register dst, Register src, Register value, RCBit r = LeaveRC);
197  void SubS32(Register dst, Register src, const Operand& value,
198              Register scratch = r0, RCBit r = LeaveRC);
199  void SubS32(Register dst, Register src, Register value, RCBit r = LeaveRC);
200  void MulS64(Register dst, Register src, const Operand& value,
201              Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
202  void MulS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
203              RCBit r = LeaveRC);
204  void MulS32(Register dst, Register src, const Operand& value,
205              Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
206  void MulS32(Register dst, Register src, Register value, OEBit s = LeaveOE,
207              RCBit r = LeaveRC);
208  void DivS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
209              RCBit r = LeaveRC);
210  void DivU64(Register dst, Register src, Register value, OEBit s = LeaveOE,
211              RCBit r = LeaveRC);
212  void DivS32(Register dst, Register src, Register value, OEBit s = LeaveOE,
213              RCBit r = LeaveRC);
214  void DivU32(Register dst, Register src, Register value, OEBit s = LeaveOE,
215              RCBit r = LeaveRC);
216  void ModS64(Register dst, Register src, Register value);
217  void ModU64(Register dst, Register src, Register value);
218  void ModS32(Register dst, Register src, Register value);
219  void ModU32(Register dst, Register src, Register value);
220
221  void AndU64(Register dst, Register src, const Operand& value,
222              Register scratch = r0, RCBit r = SetRC);
223  void AndU64(Register dst, Register src, Register value, RCBit r = SetRC);
224  void OrU64(Register dst, Register src, const Operand& value,
225             Register scratch = r0, RCBit r = SetRC);
226  void OrU64(Register dst, Register src, Register value, RCBit r = LeaveRC);
227  void XorU64(Register dst, Register src, const Operand& value,
228              Register scratch = r0, RCBit r = SetRC);
229  void XorU64(Register dst, Register src, Register value, RCBit r = LeaveRC);
230  void AndU32(Register dst, Register src, const Operand& value,
231              Register scratch = r0, RCBit r = SetRC);
232  void AndU32(Register dst, Register src, Register value, RCBit r = SetRC);
233  void OrU32(Register dst, Register src, const Operand& value,
234             Register scratch = r0, RCBit r = SetRC);
235  void OrU32(Register dst, Register src, Register value, RCBit r = LeaveRC);
236  void XorU32(Register dst, Register src, const Operand& value,
237              Register scratch = r0, RCBit r = SetRC);
238  void XorU32(Register dst, Register src, Register value, RCBit r = LeaveRC);
239
240  void ShiftLeftU64(Register dst, Register src, const Operand& value,
241                    RCBit r = LeaveRC);
242  void ShiftRightU64(Register dst, Register src, const Operand& value,
243                     RCBit r = LeaveRC);
244  void ShiftRightS64(Register dst, Register src, const Operand& value,
245                     RCBit r = LeaveRC);
246  void ShiftLeftU32(Register dst, Register src, const Operand& value,
247                    RCBit r = LeaveRC);
248  void ShiftRightU32(Register dst, Register src, const Operand& value,
249                     RCBit r = LeaveRC);
250  void ShiftRightS32(Register dst, Register src, const Operand& value,
251                     RCBit r = LeaveRC);
252  void ShiftLeftU64(Register dst, Register src, Register value,
253                    RCBit r = LeaveRC);
254  void ShiftRightU64(Register dst, Register src, Register value,
255                     RCBit r = LeaveRC);
256  void ShiftRightS64(Register dst, Register src, Register value,
257                     RCBit r = LeaveRC);
258  void ShiftLeftU32(Register dst, Register src, Register value,
259                    RCBit r = LeaveRC);
260  void ShiftRightU32(Register dst, Register src, Register value,
261                     RCBit r = LeaveRC);
262  void ShiftRightS32(Register dst, Register src, Register value,
263                     RCBit r = LeaveRC);
264
265  void CountLeadingZerosU32(Register dst, Register src, RCBit r = LeaveRC);
266  void CountLeadingZerosU64(Register dst, Register src, RCBit r = LeaveRC);
267  void CountTrailingZerosU32(Register dst, Register src, Register scratch1 = ip,
268                             Register scratch2 = r0, RCBit r = LeaveRC);
269  void CountTrailingZerosU64(Register dst, Register src, Register scratch1 = ip,
270                             Register scratch2 = r0, RCBit r = LeaveRC);
271
272  void ClearByteU64(Register dst, int byte_idx);
273  void ReverseBitsU64(Register dst, Register src, Register scratch1,
274                      Register scratch2);
275  void ReverseBitsU32(Register dst, Register src, Register scratch1,
276                      Register scratch2);
277  void ReverseBitsInSingleByteU64(Register dst, Register src,
278                                  Register scratch1, Register scratch2,
279                                  int byte_idx);
280
281  void AddF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
282              RCBit r = LeaveRC);
283  void SubF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
284              RCBit r = LeaveRC);
285  void MulF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
286              RCBit r = LeaveRC);
287  void DivF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
288              RCBit r = LeaveRC);
289  void AddF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
290              RCBit r = LeaveRC);
291  void SubF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
292              RCBit r = LeaveRC);
293  void MulF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
294              RCBit r = LeaveRC);
295  void DivF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
296              RCBit r = LeaveRC);
297  void CopySignF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
298                   RCBit r = LeaveRC);
299
300  template <class _type>
301  void SignedExtend(Register dst, Register value) {
302    switch (sizeof(_type)) {
303      case 1:
304        extsb(dst, value);
305        break;
306      case 2:
307        extsh(dst, value);
308        break;
309      case 4:
310        extsw(dst, value);
311        break;
312      case 8:
313        if (dst != value) mr(dst, value);
314        break;
315      default:
316        UNREACHABLE();
317    }
318  }
319
320  template <class _type>
321  void ZeroExtend(Register dst, Register value) {
322    switch (sizeof(_type)) {
323      case 1:
324        ZeroExtByte(dst, value);
325        break;
326      case 2:
327        ZeroExtHalfWord(dst, value);
328        break;
329      case 4:
330        ZeroExtWord32(dst, value);
331        break;
332      case 8:
333        if (dst != value) mr(dst, value);
334        break;
335      default:
336        UNREACHABLE();
337    }
338  }
339  template <class _type>
340  void ExtendValue(Register dst, Register value) {
341    if (std::is_signed<_type>::value) {
342      SignedExtend<_type>(dst, value);
343    } else {
344      ZeroExtend<_type>(dst, value);
345    }
346  }
347
348  template <class _type>
349  void LoadReserve(Register output, MemOperand dst) {
350    switch (sizeof(_type)) {
351      case 1:
352        lbarx(output, dst);
353        break;
354      case 2:
355        lharx(output, dst);
356        break;
357      case 4:
358        lwarx(output, dst);
359        break;
360      case 8:
361        ldarx(output, dst);
362        break;
363      default:
364        UNREACHABLE();
365    }
366    if (std::is_signed<_type>::value) {
367      SignedExtend<_type>(output, output);
368    }
369  }
370
371  template <class _type>
372  void StoreConditional(Register value, MemOperand dst) {
373    switch (sizeof(_type)) {
374      case 1:
375        stbcx(value, dst);
376        break;
377      case 2:
378        sthcx(value, dst);
379        break;
380      case 4:
381        stwcx(value, dst);
382        break;
383      case 8:
384        stdcx(value, dst);
385        break;
386      default:
387        UNREACHABLE();
388    }
389  }
390
391  template <class _type>
392  void AtomicCompareExchange(MemOperand dst, Register old_value,
393                             Register new_value, Register output,
394                             Register scratch) {
395    Label loop;
396    Label exit;
397    if (sizeof(_type) != 8) {
398      ExtendValue<_type>(scratch, old_value);
399      old_value = scratch;
400    }
401    lwsync();
402    bind(&loop);
403    LoadReserve<_type>(output, dst);
404    cmp(output, old_value, cr0);
405    bne(&exit, cr0);
406    StoreConditional<_type>(new_value, dst);
407    bne(&loop, cr0);
408    bind(&exit);
409    sync();
410  }
411
412  template <class _type>
413  void AtomicExchange(MemOperand dst, Register new_value, Register output) {
414    Label exchange;
415    lwsync();
416    bind(&exchange);
417    LoadReserve<_type>(output, dst);
418    StoreConditional<_type>(new_value, dst);
419    bne(&exchange, cr0);
420    sync();
421  }
422
423  template <class _type, class bin_op>
424  void AtomicOps(MemOperand dst, Register value, Register output,
425                 Register result, bin_op op) {
426    Label binop;
427    lwsync();
428    bind(&binop);
429    switch (sizeof(_type)) {
430      case 1:
431        lbarx(output, dst);
432        break;
433      case 2:
434        lharx(output, dst);
435        break;
436      case 4:
437        lwarx(output, dst);
438        break;
439      case 8:
440        ldarx(output, dst);
441        break;
442      default:
443        UNREACHABLE();
444    }
445    op(result, output, value);
446    switch (sizeof(_type)) {
447      case 1:
448        stbcx(result, dst);
449        break;
450      case 2:
451        sthcx(result, dst);
452        break;
453      case 4:
454        stwcx(result, dst);
455        break;
456      case 8:
457        stdcx(result, dst);
458        break;
459      default:
460        UNREACHABLE();
461    }
462    bne(&binop, cr0);
463    sync();
464  }
465
466  void Push(Register src) { push(src); }
467  // Push a handle.
468  void Push(Handle<HeapObject> handle);
469  void Push(Smi smi);
470
471  // Push two registers.  Pushes leftmost register first (to highest address).
472  void Push(Register src1, Register src2) {
473    StoreU64WithUpdate(src2, MemOperand(sp, -2 * kSystemPointerSize));
474    StoreU64(src1, MemOperand(sp, kSystemPointerSize));
475  }
476
477  // Push three registers.  Pushes leftmost register first (to highest address).
478  void Push(Register src1, Register src2, Register src3) {
479    StoreU64WithUpdate(src3, MemOperand(sp, -3 * kSystemPointerSize));
480    StoreU64(src2, MemOperand(sp, kSystemPointerSize));
481    StoreU64(src1, MemOperand(sp, 2 * kSystemPointerSize));
482  }
483
484  // Push four registers.  Pushes leftmost register first (to highest address).
485  void Push(Register src1, Register src2, Register src3, Register src4) {
486    StoreU64WithUpdate(src4, MemOperand(sp, -4 * kSystemPointerSize));
487    StoreU64(src3, MemOperand(sp, kSystemPointerSize));
488    StoreU64(src2, MemOperand(sp, 2 * kSystemPointerSize));
489    StoreU64(src1, MemOperand(sp, 3 * kSystemPointerSize));
490  }
491
492  // Push five registers.  Pushes leftmost register first (to highest address).
493  void Push(Register src1, Register src2, Register src3, Register src4,
494            Register src5) {
495    StoreU64WithUpdate(src5, MemOperand(sp, -5 * kSystemPointerSize));
496    StoreU64(src4, MemOperand(sp, kSystemPointerSize));
497    StoreU64(src3, MemOperand(sp, 2 * kSystemPointerSize));
498    StoreU64(src2, MemOperand(sp, 3 * kSystemPointerSize));
499    StoreU64(src1, MemOperand(sp, 4 * kSystemPointerSize));
500  }
501
502  enum PushArrayOrder { kNormal, kReverse };
503  void PushArray(Register array, Register size, Register scratch,
504                 Register scratch2, PushArrayOrder order = kNormal);
505
506  void Pop(Register dst) { pop(dst); }
507
508  // Pop two registers. Pops rightmost register first (from lower address).
509  void Pop(Register src1, Register src2) {
510    LoadU64(src2, MemOperand(sp, 0));
511    LoadU64(src1, MemOperand(sp, kSystemPointerSize));
512    addi(sp, sp, Operand(2 * kSystemPointerSize));
513  }
514
515  // Pop three registers.  Pops rightmost register first (from lower address).
516  void Pop(Register src1, Register src2, Register src3) {
517    LoadU64(src3, MemOperand(sp, 0));
518    LoadU64(src2, MemOperand(sp, kSystemPointerSize));
519    LoadU64(src1, MemOperand(sp, 2 * kSystemPointerSize));
520    addi(sp, sp, Operand(3 * kSystemPointerSize));
521  }
522
523  // Pop four registers.  Pops rightmost register first (from lower address).
524  void Pop(Register src1, Register src2, Register src3, Register src4) {
525    LoadU64(src4, MemOperand(sp, 0));
526    LoadU64(src3, MemOperand(sp, kSystemPointerSize));
527    LoadU64(src2, MemOperand(sp, 2 * kSystemPointerSize));
528    LoadU64(src1, MemOperand(sp, 3 * kSystemPointerSize));
529    addi(sp, sp, Operand(4 * kSystemPointerSize));
530  }
531
532  // Pop five registers.  Pops rightmost register first (from lower address).
533  void Pop(Register src1, Register src2, Register src3, Register src4,
534           Register src5) {
535    LoadU64(src5, MemOperand(sp, 0));
536    LoadU64(src4, MemOperand(sp, kSystemPointerSize));
537    LoadU64(src3, MemOperand(sp, 2 * kSystemPointerSize));
538    LoadU64(src2, MemOperand(sp, 3 * kSystemPointerSize));
539    LoadU64(src1, MemOperand(sp, 4 * kSystemPointerSize));
540    addi(sp, sp, Operand(5 * kSystemPointerSize));
541  }
542
543  void MaybeSaveRegisters(RegList registers);
544  void MaybeRestoreRegisters(RegList registers);
545
546  void CallEphemeronKeyBarrier(Register object, Register slot_address,
547                               SaveFPRegsMode fp_mode);
548
549  void CallRecordWriteStubSaveRegisters(
550      Register object, Register slot_address,
551      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
552      StubCallMode mode = StubCallMode::kCallBuiltinPointer);
553  void CallRecordWriteStub(
554      Register object, Register slot_address,
555      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
556      StubCallMode mode = StubCallMode::kCallBuiltinPointer);
557
558  void MultiPush(RegList regs, Register location = sp);
559  void MultiPop(RegList regs, Register location = sp);
560
561  void MultiPushDoubles(DoubleRegList dregs, Register location = sp);
562  void MultiPopDoubles(DoubleRegList dregs, Register location = sp);
563
564  void MultiPushV128(Simd128RegList dregs, Register location = sp);
565  void MultiPopV128(Simd128RegList dregs, Register location = sp);
566
567  void MultiPushF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs,
568                           Register location = sp);
569  void MultiPopF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs,
570                          Register location = sp);
571
572  // Calculate how much stack space (in bytes) are required to store caller
573  // registers excluding those specified in the arguments.
574  int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
575                                      Register exclusion1 = no_reg,
576                                      Register exclusion2 = no_reg,
577                                      Register exclusion3 = no_reg) const;
578
579  // Push caller saved registers on the stack, and return the number of bytes
580  // stack pointer is adjusted.
581  int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
582                      Register exclusion2 = no_reg,
583                      Register exclusion3 = no_reg);
584  // Restore caller saved registers from the stack, and return the number of
585  // bytes stack pointer is adjusted.
586  int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
587                     Register exclusion2 = no_reg,
588                     Register exclusion3 = no_reg);
589
590  // Load an object from the root table.
591  void LoadRoot(Register destination, RootIndex index) final {
592    LoadRoot(destination, index, al);
593  }
594  void LoadRoot(Register destination, RootIndex index, Condition cond);
595
596  void SwapP(Register src, Register dst, Register scratch);
597  void SwapP(Register src, MemOperand dst, Register scratch);
598  void SwapP(MemOperand src, MemOperand dst, Register scratch_0,
599             Register scratch_1);
600  void SwapFloat32(DoubleRegister src, DoubleRegister dst,
601                   DoubleRegister scratch);
602  void SwapFloat32(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
603  void SwapFloat32(MemOperand src, MemOperand dst, DoubleRegister scratch_0,
604                   DoubleRegister scratch_1);
605  void SwapDouble(DoubleRegister src, DoubleRegister dst,
606                  DoubleRegister scratch);
607  void SwapDouble(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
608  void SwapDouble(MemOperand src, MemOperand dst, DoubleRegister scratch_0,
609                  DoubleRegister scratch_1);
610  void SwapSimd128(Simd128Register src, Simd128Register dst,
611                   Simd128Register scratch);
612  void SwapSimd128(Simd128Register src, MemOperand dst,
613                   Simd128Register scratch);
614  void SwapSimd128(MemOperand src, MemOperand dst, Simd128Register scratch);
615
616  void ByteReverseU16(Register dst, Register val, Register scratch);
617  void ByteReverseU32(Register dst, Register val, Register scratch);
618  void ByteReverseU64(Register dst, Register val, Register = r0);
619
620  // Before calling a C-function from generated code, align arguments on stack.
621  // After aligning the frame, non-register arguments must be stored in
622  // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
623  // are word sized. If double arguments are used, this function assumes that
624  // all double arguments are stored before core registers; otherwise the
625  // correct alignment of the double values is not guaranteed.
626  // Some compilers/platforms require the stack to be aligned when calling
627  // C++ code.
628  // Needs a scratch register to do some arithmetic. This register will be
629  // trashed.
630  void PrepareCallCFunction(int num_reg_arguments, int num_double_registers,
631                            Register scratch);
632  void PrepareCallCFunction(int num_reg_arguments, Register scratch);
633
634  // There are two ways of passing double arguments on ARM, depending on
635  // whether soft or hard floating point ABI is used. These functions
636  // abstract parameter passing for the three different ways we call
637  // C functions from generated code.
638  void MovToFloatParameter(DoubleRegister src);
639  void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
640  void MovToFloatResult(DoubleRegister src);
641
642  // Calls a C function and cleans up the space for arguments allocated
643  // by PrepareCallCFunction. The called function is not allowed to trigger a
644  // garbage collection, since that might move the code and invalidate the
645  // return address (unless this is somehow accounted for by the called
646  // function).
647  void CallCFunction(ExternalReference function, int num_arguments,
648                     bool has_function_descriptor = true);
649  void CallCFunction(Register function, int num_arguments,
650                     bool has_function_descriptor = true);
651  void CallCFunction(ExternalReference function, int num_reg_arguments,
652                     int num_double_arguments,
653                     bool has_function_descriptor = true);
654  void CallCFunction(Register function, int num_reg_arguments,
655                     int num_double_arguments,
656                     bool has_function_descriptor = true);
657
658  void MovFromFloatParameter(DoubleRegister dst);
659  void MovFromFloatResult(DoubleRegister dst);
660
661  void Trap();
662  void DebugBreak();
663
664  // Calls Abort(msg) if the condition cond is not satisfied.
665  // Use --debug_code to enable.
666  void Assert(Condition cond, AbortReason reason, CRegister cr = cr7);
667
668  // Like Assert(), but always enabled.
669  void Check(Condition cond, AbortReason reason, CRegister cr = cr7);
670
671  // Print a message to stdout and abort execution.
672  void Abort(AbortReason reason);
673
674#if !V8_TARGET_ARCH_PPC64
675  void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
676                     Register src_high, Register scratch, Register shift);
677  void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
678                     Register src_high, uint32_t shift);
679  void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
680                      Register src_high, Register scratch, Register shift);
681  void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
682                      Register src_high, uint32_t shift);
683  void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low,
684                         Register src_high, Register scratch, Register shift);
685  void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low,
686                         Register src_high, uint32_t shift);
687#endif
688
689  void LoadFromConstantsTable(Register destination, int constant_index) final;
690  void LoadRootRegisterOffset(Register destination, intptr_t offset) final;
691  void LoadRootRelative(Register destination, int32_t offset) final;
692
693  // Jump, Call, and Ret pseudo instructions implementing inter-working.
694  void Jump(Register target);
695  void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al,
696            CRegister cr = cr7);
697  void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al,
698            CRegister cr = cr7);
699  void Jump(const ExternalReference& reference);
700  void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al,
701            CRegister cr = cr7);
702  void Call(Register target);
703  void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
704  void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
705            Condition cond = al);
706  void Call(Label* target);
707
708  // Load the builtin given by the Smi in |builtin_index| into the same
709  // register.
710  void LoadEntryFromBuiltinIndex(Register builtin_index);
711  void LoadEntryFromBuiltin(Builtin builtin, Register destination);
712  MemOperand EntryFromBuiltinAsOperand(Builtin builtin);
713  void LoadCodeObjectEntry(Register destination, Register code_object);
714  void CallCodeObject(Register code_object);
715  void JumpCodeObject(Register code_object,
716                      JumpMode jump_mode = JumpMode::kJump);
717
718  void CallBuiltinByIndex(Register builtin_index);
719  void CallForDeoptimization(Builtin target, int deopt_id, Label* exit,
720                             DeoptimizeKind kind, Label* ret,
721                             Label* jump_deoptimization_entry_label);
722
723  // Emit code to discard a non-negative number of pointer-sized elements
724  // from the stack, clobbering only the sp register.
725  void Drop(int count);
726  void Drop(Register count, Register scratch = r0);
727
728  void Ret() { blr(); }
729  void Ret(Condition cond, CRegister cr = cr7) { bclr(cond, cr); }
730  void Ret(int drop) {
731    Drop(drop);
732    blr();
733  }
734
735  // If the value is a NaN, canonicalize the value else, do nothing.
736  void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
737  void CanonicalizeNaN(const DoubleRegister value) {
738    CanonicalizeNaN(value, value);
739  }
740  void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
741                     Label* condition_met);
742
743  // Move values between integer and floating point registers.
744  void MovIntToDouble(DoubleRegister dst, Register src, Register scratch);
745  void MovUnsignedIntToDouble(DoubleRegister dst, Register src,
746                              Register scratch);
747  void MovInt64ToDouble(DoubleRegister dst,
748#if !V8_TARGET_ARCH_PPC64
749                        Register src_hi,
750#endif
751                        Register src);
752#if V8_TARGET_ARCH_PPC64
753  void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi,
754                                  Register src_lo, Register scratch);
755#endif
756  void InsertDoubleLow(DoubleRegister dst, Register src, Register scratch);
757  void InsertDoubleHigh(DoubleRegister dst, Register src, Register scratch);
758  void MovDoubleLowToInt(Register dst, DoubleRegister src);
759  void MovDoubleHighToInt(Register dst, DoubleRegister src);
760  void MovDoubleToInt64(
761#if !V8_TARGET_ARCH_PPC64
762      Register dst_hi,
763#endif
764      Register dst, DoubleRegister src);
765  void MovIntToFloat(DoubleRegister dst, Register src, Register scratch);
766  void MovFloatToInt(Register dst, DoubleRegister src, DoubleRegister scratch);
767  // Register move. May do nothing if the registers are identical.
768  void Move(Register dst, Smi smi) { LoadSmiLiteral(dst, smi); }
769  void Move(Register dst, Handle<HeapObject> value,
770            RelocInfo::Mode rmode = RelocInfo::FULL_EMBEDDED_OBJECT);
771  void Move(Register dst, ExternalReference reference);
772  void Move(Register dst, Register src, Condition cond = al);
773  void Move(DoubleRegister dst, DoubleRegister src);
774  void Move(Register dst, const MemOperand& src) { LoadU64(dst, src); }
775
776  void SmiUntag(Register dst, const MemOperand& src, RCBit rc = LeaveRC,
777                Register scratch = no_reg);
778  void SmiUntag(Register reg, RCBit rc = LeaveRC) { SmiUntag(reg, reg, rc); }
779
780  void SmiUntag(Register dst, Register src, RCBit rc = LeaveRC) {
781    if (COMPRESS_POINTERS_BOOL) {
782      srawi(dst, src, kSmiShift, rc);
783    } else {
784      ShiftRightS64(dst, src, Operand(kSmiShift), rc);
785    }
786  }
787  void SmiToInt32(Register smi) {
788    if (FLAG_enable_slow_asserts) {
789      AssertSmi(smi);
790    }
791    DCHECK(SmiValuesAre32Bits() || SmiValuesAre31Bits());
792    SmiUntag(smi);
793  }
794
795  // Shift left by kSmiShift
796  void SmiTag(Register reg, RCBit rc = LeaveRC) { SmiTag(reg, reg, rc); }
797  void SmiTag(Register dst, Register src, RCBit rc = LeaveRC) {
798    ShiftLeftU64(dst, src, Operand(kSmiShift), rc);
799  }
800
801  // Abort execution if argument is a smi, enabled via --debug-code.
802  void AssertNotSmi(Register object);
803  void AssertSmi(Register object);
804
805  void ZeroExtByte(Register dst, Register src);
806  void ZeroExtHalfWord(Register dst, Register src);
807  void ZeroExtWord32(Register dst, Register src);
808
809  // ---------------------------------------------------------------------------
810  // Bit testing/extraction
811  //
812  // Bit numbering is such that the least significant bit is bit 0
813  // (for consistency between 32/64-bit).
814
815  // Extract consecutive bits (defined by rangeStart - rangeEnd) from src
816  // and, if !test, shift them into the least significant bits of dst.
817  inline void ExtractBitRange(Register dst, Register src, int rangeStart,
818                              int rangeEnd, RCBit rc = LeaveRC,
819                              bool test = false) {
820    DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerSystemPointer);
821    int rotate = (rangeEnd == 0) ? 0 : kBitsPerSystemPointer - rangeEnd;
822    int width = rangeStart - rangeEnd + 1;
823    if (rc == SetRC && rangeStart < 16 && (rangeEnd == 0 || test)) {
824      // Prefer faster andi when applicable.
825      andi(dst, src, Operand(((1 << width) - 1) << rangeEnd));
826    } else {
827#if V8_TARGET_ARCH_PPC64
828      rldicl(dst, src, rotate, kBitsPerSystemPointer - width, rc);
829#else
830      rlwinm(dst, src, rotate, kBitsPerSystemPointer - width,
831             kBitsPerSystemPointer - 1, rc);
832#endif
833    }
834  }
835
836  inline void ExtractBit(Register dst, Register src, uint32_t bitNumber,
837                         RCBit rc = LeaveRC, bool test = false) {
838    ExtractBitRange(dst, src, bitNumber, bitNumber, rc, test);
839  }
840
841  // Extract consecutive bits (defined by mask) from src and place them
842  // into the least significant bits of dst.
843  inline void ExtractBitMask(Register dst, Register src, uintptr_t mask,
844                             RCBit rc = LeaveRC, bool test = false) {
845    int start = kBitsPerSystemPointer - 1;
846    int end;
847    uintptr_t bit = (1L << start);
848
849    while (bit && (mask & bit) == 0) {
850      start--;
851      bit >>= 1;
852    }
853    end = start;
854    bit >>= 1;
855
856    while (bit && (mask & bit)) {
857      end--;
858      bit >>= 1;
859    }
860
861    // 1-bits in mask must be contiguous
862    DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0);
863
864    ExtractBitRange(dst, src, start, end, rc, test);
865  }
866
867  // Test single bit in value.
868  inline void TestBit(Register value, int bitNumber, Register scratch = r0) {
869    ExtractBitRange(scratch, value, bitNumber, bitNumber, SetRC, true);
870  }
871
872  // Test consecutive bit range in value.  Range is defined by mask.
873  inline void TestBitMask(Register value, uintptr_t mask,
874                          Register scratch = r0) {
875    ExtractBitMask(scratch, value, mask, SetRC, true);
876  }
877  // Test consecutive bit range in value.  Range is defined by
878  // rangeStart - rangeEnd.
879  inline void TestBitRange(Register value, int rangeStart, int rangeEnd,
880                           Register scratch = r0) {
881    ExtractBitRange(scratch, value, rangeStart, rangeEnd, SetRC, true);
882  }
883
884  inline void TestIfSmi(Register value, Register scratch) {
885    TestBitRange(value, kSmiTagSize - 1, 0, scratch);
886  }
887  // Jump the register contains a smi.
888  inline void JumpIfSmi(Register value, Label* smi_label) {
889    TestIfSmi(value, r0);
890    beq(smi_label, cr0);  // branch if SMI
891  }
892  void JumpIfEqual(Register x, int32_t y, Label* dest);
893  void JumpIfLessThan(Register x, int32_t y, Label* dest);
894
895  void LoadMap(Register destination, Register object);
896
897#if V8_TARGET_ARCH_PPC64
898  inline void TestIfInt32(Register value, Register scratch,
899                          CRegister cr = cr7) {
900    // High bits must be identical to fit into an 32-bit integer
901    extsw(scratch, value);
902    CmpS64(scratch, value, cr);
903  }
904#else
905  inline void TestIfInt32(Register hi_word, Register lo_word, Register scratch,
906                          CRegister cr = cr7) {
907    // High bits must be identical to fit into an 32-bit integer
908    srawi(scratch, lo_word, 31);
909    CmpS64(scratch, hi_word, cr);
910  }
911#endif
912
913  // Overflow handling functions.
914  // Usage: call the appropriate arithmetic function and then call one of the
915  // flow control functions with the corresponding label.
916
917  // Compute dst = left + right, setting condition codes. dst may be same as
918  // either left or right (or a unique register). left and right must not be
919  // the same register.
920  void AddAndCheckForOverflow(Register dst, Register left, Register right,
921                              Register overflow_dst, Register scratch = r0);
922  void AddAndCheckForOverflow(Register dst, Register left, intptr_t right,
923                              Register overflow_dst, Register scratch = r0);
924
925  // Compute dst = left - right, setting condition codes. dst may be same as
926  // either left or right (or a unique register). left and right must not be
927  // the same register.
928  void SubAndCheckForOverflow(Register dst, Register left, Register right,
929                              Register overflow_dst, Register scratch = r0);
930
931  // Performs a truncating conversion of a floating point number as used by
932  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
933  // succeeds, otherwise falls through if result is saturated. On return
934  // 'result' either holds answer, or is clobbered on fall through.
935  void TryInlineTruncateDoubleToI(Register result, DoubleRegister input,
936                                  Label* done);
937  void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result,
938                         DoubleRegister double_input, StubCallMode stub_mode);
939
940  void LoadConstantPoolPointerRegister();
941
942  // Loads the constant pool pointer (kConstantPoolRegister).
943  void LoadConstantPoolPointerRegisterFromCodeTargetAddress(
944      Register code_target_address);
945  void AbortConstantPoolBuilding() {
946#ifdef DEBUG
947    // Avoid DCHECK(!is_linked()) failure in ~Label()
948    bind(ConstantPoolPosition());
949#endif
950  }
951
952  // Generates an instruction sequence s.t. the return address points to the
953  // instruction following the call.
954  // The return address on the stack is used by frame iteration.
955  void StoreReturnAddressAndCall(Register target);
956
957  // Control-flow integrity:
958
959  // Define a function entrypoint. This doesn't emit any code for this
960  // architecture, as control-flow integrity is not supported for it.
961  void CodeEntry() {}
962  // Define an exception handler.
963  void ExceptionHandler() {}
964  // Define an exception handler and bind a label.
965  void BindExceptionHandler(Label* label) { bind(label); }
966
967  // ---------------------------------------------------------------------------
968  // Pointer compression Support
969
970  void SmiToPtrArrayOffset(Register dst, Register src) {
971#if defined(V8_COMPRESS_POINTERS) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
972    STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kSystemPointerSizeLog2);
973    ShiftLeftU64(dst, src, Operand(kSystemPointerSizeLog2 - kSmiShift));
974#else
975    STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kSystemPointerSizeLog2);
976    ShiftRightS64(dst, src, Operand(kSmiShift - kSystemPointerSizeLog2));
977#endif
978  }
979
980  // Loads a field containing a HeapObject and decompresses it if pointer
981  // compression is enabled.
982  void LoadTaggedPointerField(const Register& destination,
983                              const MemOperand& field_operand,
984                              const Register& scratch = no_reg);
985  void LoadTaggedSignedField(Register destination, MemOperand field_operand,
986                             Register scratch);
987
988  // Loads a field containing any tagged value and decompresses it if necessary.
989  void LoadAnyTaggedField(const Register& destination,
990                          const MemOperand& field_operand,
991                          const Register& scratch = no_reg);
992
993  // Compresses and stores tagged value to given on-heap location.
994  void StoreTaggedField(const Register& value,
995                        const MemOperand& dst_field_operand,
996                        const Register& scratch = no_reg);
997
998  void DecompressTaggedSigned(Register destination, MemOperand field_operand);
999  void DecompressTaggedSigned(Register destination, Register src);
1000  void DecompressTaggedPointer(Register destination, MemOperand field_operand);
1001  void DecompressTaggedPointer(Register destination, Register source);
1002  void DecompressAnyTagged(Register destination, MemOperand field_operand);
1003  void DecompressAnyTagged(Register destination, Register source);
1004
1005  void LoadF64(DoubleRegister dst, const MemOperand& mem,
1006               Register scratch = no_reg);
1007  void LoadF32(DoubleRegister dst, const MemOperand& mem,
1008               Register scratch = no_reg);
1009
1010  void StoreF32(DoubleRegister src, const MemOperand& mem,
1011                Register scratch = no_reg);
1012  void StoreF64(DoubleRegister src, const MemOperand& mem,
1013                Register scratch = no_reg);
1014
1015  void LoadF32WithUpdate(DoubleRegister dst, const MemOperand& mem,
1016                         Register scratch = no_reg);
1017  void LoadF64WithUpdate(DoubleRegister dst, const MemOperand& mem,
1018                         Register scratch = no_reg);
1019
1020  void StoreF32WithUpdate(DoubleRegister src, const MemOperand& mem,
1021                          Register scratch = no_reg);
1022  void StoreF64WithUpdate(DoubleRegister src, const MemOperand& mem,
1023                          Register scratch = no_reg);
1024
1025  void StoreSimd128(Simd128Register src, const MemOperand& mem);
1026
1027  void LoadU64(Register dst, const MemOperand& mem, Register scratch = no_reg);
1028  void LoadU32(Register dst, const MemOperand& mem, Register scratch = no_reg);
1029  void LoadS32(Register dst, const MemOperand& mem, Register scratch = no_reg);
1030  void LoadU16(Register dst, const MemOperand& mem, Register scratch = no_reg);
1031  void LoadS16(Register dst, const MemOperand& mem, Register scratch = no_reg);
1032  void LoadU8(Register dst, const MemOperand& mem, Register scratch = no_reg);
1033  void LoadS8(Register dst, const MemOperand& mem, Register scratch = no_reg);
1034
1035  void StoreU64(Register src, const MemOperand& mem, Register scratch = no_reg);
1036  void StoreU32(Register src, const MemOperand& mem, Register scratch);
1037  void StoreU16(Register src, const MemOperand& mem, Register scratch);
1038  void StoreU8(Register src, const MemOperand& mem, Register scratch);
1039
1040  void LoadU64WithUpdate(Register dst, const MemOperand& mem,
1041                         Register scratch = no_reg);
1042  void StoreU64WithUpdate(Register src, const MemOperand& mem,
1043                          Register scratch = no_reg);
1044
1045  void LoadU64LE(Register dst, const MemOperand& mem, Register scratch);
1046  void LoadU32LE(Register dst, const MemOperand& mem, Register scratch);
1047  void LoadU16LE(Register dst, const MemOperand& mem, Register scratch);
1048  void StoreU64LE(Register src, const MemOperand& mem, Register scratch);
1049  void StoreU32LE(Register src, const MemOperand& mem, Register scratch);
1050  void StoreU16LE(Register src, const MemOperand& mem, Register scratch);
1051
1052  void LoadS32LE(Register dst, const MemOperand& mem, Register scratch);
1053  void LoadS16LE(Register dst, const MemOperand& mem, Register scratch);
1054
1055  void LoadF64LE(DoubleRegister dst, const MemOperand& mem, Register scratch,
1056                 Register scratch2);
1057  void LoadF32LE(DoubleRegister dst, const MemOperand& mem, Register scratch,
1058                 Register scratch2);
1059
1060  void StoreF32LE(DoubleRegister src, const MemOperand& mem, Register scratch,
1061                  Register scratch2);
1062  void StoreF64LE(DoubleRegister src, const MemOperand& mem, Register scratch,
1063                  Register scratch2);
1064
1065 private:
1066  static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1067
1068  int CalculateStackPassedWords(int num_reg_arguments,
1069                                int num_double_arguments);
1070  void CallCFunctionHelper(Register function, int num_reg_arguments,
1071                           int num_double_arguments,
1072                           bool has_function_descriptor);
1073};
1074
1075// MacroAssembler implements a collection of frequently used acros.
1076class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
1077 public:
1078  using TurboAssembler::TurboAssembler;
1079
1080  // It assumes that the arguments are located below the stack pointer.
1081  // argc is the number of arguments not including the receiver.
1082  // TODO(victorgomes): Remove this function once we stick with the reversed
1083  // arguments order.
1084  void LoadReceiver(Register dest, Register argc) {
1085    LoadU64(dest, MemOperand(sp, 0));
1086  }
1087
1088  void StoreReceiver(Register rec, Register argc, Register scratch) {
1089    StoreU64(rec, MemOperand(sp, 0));
1090  }
1091
1092  // ---------------------------------------------------------------------------
1093  // GC Support
1094
1095  // Notify the garbage collector that we wrote a pointer into an object.
1096  // |object| is the object being stored into, |value| is the object being
1097  // stored.  value and scratch registers are clobbered by the operation.
1098  // The offset is the offset from the start of the object, not the offset from
1099  // the tagged HeapObject pointer.  For use with FieldMemOperand(reg, off).
1100  void RecordWriteField(
1101      Register object, int offset, Register value, Register slot_address,
1102      LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1103      RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
1104      SmiCheck smi_check = SmiCheck::kInline);
1105
1106  // For a given |object| notify the garbage collector that the slot |address|
1107  // has been written.  |value| is the object being stored. The value and
1108  // address registers are clobbered by the operation.
1109  void RecordWrite(
1110      Register object, Register slot_address, Register value,
1111      LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1112      RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
1113      SmiCheck smi_check = SmiCheck::kInline);
1114
1115  // Enter exit frame.
1116  // stack_space - extra stack space, used for parameters before call to C.
1117  // At least one slot (for the return address) should be provided.
1118  void EnterExitFrame(bool save_doubles, int stack_space = 1,
1119                      StackFrame::Type frame_type = StackFrame::EXIT);
1120
1121  // Leave the current exit frame. Expects the return value in r0.
1122  // Expect the number of values, pushed prior to the exit frame, to
1123  // remove in a register (or no_reg, if there is nothing to remove).
1124  void LeaveExitFrame(bool save_doubles, Register argument_count,
1125                      bool argument_count_is_length = false);
1126
1127  // Load the global proxy from the current context.
1128  void LoadGlobalProxy(Register dst) {
1129    LoadNativeContextSlot(dst, Context::GLOBAL_PROXY_INDEX);
1130  }
1131
1132  void LoadNativeContextSlot(Register dst, int index);
1133
1134  // ----------------------------------------------------------------
1135  // new PPC macro-assembler interfaces that are slightly higher level
1136  // than assembler-ppc and may generate variable length sequences
1137
1138  // load a literal double value <value> to FPR <result>
1139
1140  void AddSmiLiteral(Register dst, Register src, Smi smi, Register scratch);
1141  void SubSmiLiteral(Register dst, Register src, Smi smi, Register scratch);
1142  void CmpSmiLiteral(Register src1, Smi smi, Register scratch,
1143                     CRegister cr = cr7);
1144  void CmplSmiLiteral(Register src1, Smi smi, Register scratch,
1145                      CRegister cr = cr7);
1146  void AndSmiLiteral(Register dst, Register src, Smi smi, Register scratch,
1147                     RCBit rc = LeaveRC);
1148
1149  // ---------------------------------------------------------------------------
1150  // JavaScript invokes
1151
1152  // Removes current frame and its arguments from the stack preserving
1153  // the arguments and a return address pushed to the stack for the next call.
1154  // Both |callee_args_count| and |caller_args_countg| do not include
1155  // receiver. |callee_args_count| is not modified. |caller_args_count|
1156  // is trashed.
1157
1158  // Invoke the JavaScript function code by either calling or jumping.
1159  void InvokeFunctionCode(Register function, Register new_target,
1160                          Register expected_parameter_count,
1161                          Register actual_parameter_count, InvokeType type);
1162
1163  // On function call, call into the debugger if necessary.
1164  void CheckDebugHook(Register fun, Register new_target,
1165                      Register expected_parameter_count,
1166                      Register actual_parameter_count);
1167
1168  // Invoke the JavaScript function in the given register. Changes the
1169  // current context to the context in the function before invoking.
1170  void InvokeFunctionWithNewTarget(Register function, Register new_target,
1171                                   Register actual_parameter_count,
1172                                   InvokeType type);
1173  void InvokeFunction(Register function, Register expected_parameter_count,
1174                      Register actual_parameter_count, InvokeType type);
1175
1176  // Exception handling
1177
1178  // Push a new stack handler and link into stack handler chain.
1179  void PushStackHandler();
1180
1181  // Unlink the stack handler on top of the stack from the stack handler chain.
1182  // Must preserve the result register.
1183  void PopStackHandler();
1184
1185  // ---------------------------------------------------------------------------
1186  // Support functions.
1187
1188  // Compare object type for heap object.  heap_object contains a non-Smi
1189  // whose object type should be compared with the given type.  This both
1190  // sets the flags and leaves the object type in the type_reg register.
1191  // It leaves the map in the map register (unless the type_reg and map register
1192  // are the same register).  It leaves the heap object in the heap_object
1193  // register unless the heap_object register is the same register as one of the
1194  // other registers.
1195  // Type_reg can be no_reg. In that case ip is used.
1196  void CompareObjectType(Register heap_object, Register map, Register type_reg,
1197                         InstanceType type);
1198
1199  // Compare instance type in a map.  map contains a valid map object whose
1200  // object type should be compared with the given type.  This both
1201  // sets the flags and leaves the object type in the type_reg register.
1202  void CompareInstanceType(Register map, Register type_reg, InstanceType type);
1203
1204  // Compare instance type ranges for a map (lower_limit and higher_limit
1205  // inclusive).
1206  //
1207  // Always use unsigned comparisons: ls for a positive result.
1208  void CompareInstanceTypeRange(Register map, Register type_reg,
1209                                InstanceType lower_limit,
1210                                InstanceType higher_limit);
1211
1212  // Compare the object in a register to a value from the root list.
1213  // Uses the ip register as scratch.
1214  void CompareRoot(Register obj, RootIndex index);
1215  void PushRoot(RootIndex index) {
1216    LoadRoot(r0, index);
1217    Push(r0);
1218  }
1219
1220  // Compare the object in a register to a value and jump if they are equal.
1221  void JumpIfRoot(Register with, RootIndex index, Label* if_equal) {
1222    CompareRoot(with, index);
1223    beq(if_equal);
1224  }
1225
1226  // Compare the object in a register to a value and jump if they are not equal.
1227  void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) {
1228    CompareRoot(with, index);
1229    bne(if_not_equal);
1230  }
1231
1232  // Checks if value is in range [lower_limit, higher_limit] using a single
1233  // comparison.
1234  void CompareRange(Register value, unsigned lower_limit,
1235                    unsigned higher_limit);
1236  void JumpIfIsInRange(Register value, unsigned lower_limit,
1237                       unsigned higher_limit, Label* on_in_range);
1238
1239  // ---------------------------------------------------------------------------
1240  // Runtime calls
1241
1242  static int CallSizeNotPredictableCodeSize(Address target,
1243                                            RelocInfo::Mode rmode,
1244                                            Condition cond = al);
1245  void CallJSEntry(Register target);
1246
1247  // Call a runtime routine.
1248  void CallRuntime(const Runtime::Function* f, int num_arguments,
1249                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore);
1250  void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
1251    const Runtime::Function* function = Runtime::FunctionForId(fid);
1252    CallRuntime(function, function->nargs, SaveFPRegsMode::kSave);
1253  }
1254
1255  // Convenience function: Same as above, but takes the fid instead.
1256  void CallRuntime(Runtime::FunctionId fid,
1257                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1258    const Runtime::Function* function = Runtime::FunctionForId(fid);
1259    CallRuntime(function, function->nargs, save_doubles);
1260  }
1261
1262  // Convenience function: Same as above, but takes the fid instead.
1263  void CallRuntime(Runtime::FunctionId fid, int num_arguments,
1264                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1265    CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
1266  }
1267
1268  // Convenience function: tail call a runtime routine (jump).
1269  void TailCallRuntime(Runtime::FunctionId fid);
1270
1271  // Jump to a runtime routine.
1272  void JumpToExternalReference(const ExternalReference& builtin,
1273                               bool builtin_exit_frame = false);
1274
1275  // Generates a trampoline to jump to the off-heap instruction stream.
1276  void JumpToOffHeapInstructionStream(Address entry);
1277
1278  // ---------------------------------------------------------------------------
1279  // In-place weak references.
1280  void LoadWeakValue(Register out, Register in, Label* target_if_cleared);
1281
1282  // ---------------------------------------------------------------------------
1283  // StatsCounter support
1284
1285  void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
1286                        Register scratch2) {
1287    if (!FLAG_native_code_counters) return;
1288    EmitIncrementCounter(counter, value, scratch1, scratch2);
1289  }
1290  void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch1,
1291                            Register scratch2);
1292  void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
1293                        Register scratch2) {
1294    if (!FLAG_native_code_counters) return;
1295    EmitDecrementCounter(counter, value, scratch1, scratch2);
1296  }
1297  void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch1,
1298                            Register scratch2);
1299
1300  // ---------------------------------------------------------------------------
1301  // Stack limit utilities
1302
1303  void StackOverflowCheck(Register num_args, Register scratch,
1304                          Label* stack_overflow);
1305  void LoadStackLimit(Register destination, StackLimitKind kind);
1306
1307  // ---------------------------------------------------------------------------
1308  // Smi utilities
1309
1310  // Jump if either of the registers contain a non-smi.
1311  inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
1312    TestIfSmi(value, r0);
1313    bne(not_smi_label, cr0);
1314  }
1315
1316#if !defined(V8_COMPRESS_POINTERS) && !defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
1317  // Ensure it is permissible to read/write int value directly from
1318  // upper half of the smi.
1319  STATIC_ASSERT(kSmiTag == 0);
1320  STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
1321#endif
1322#if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN
1323#define SmiWordOffset(offset) (offset + kSystemPointerSize / 2)
1324#else
1325#define SmiWordOffset(offset) offset
1326#endif
1327
1328  // Abort execution if argument is not a Constructor, enabled via --debug-code.
1329  void AssertConstructor(Register object);
1330
1331  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
1332  void AssertFunction(Register object);
1333
1334  // Abort execution if argument is not a callable JSFunction, enabled via
1335  // --debug-code.
1336  void AssertCallableFunction(Register object);
1337
1338  // Abort execution if argument is not a JSBoundFunction,
1339  // enabled via --debug-code.
1340  void AssertBoundFunction(Register object);
1341
1342  // Abort execution if argument is not a JSGeneratorObject (or subclass),
1343  // enabled via --debug-code.
1344  void AssertGeneratorObject(Register object);
1345
1346  // Abort execution if argument is not undefined or an AllocationSite, enabled
1347  // via --debug-code.
1348  void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1349
1350  // ---------------------------------------------------------------------------
1351  // Patching helpers.
1352
1353  template <typename Field>
1354  void DecodeField(Register dst, Register src, RCBit rc = LeaveRC) {
1355    ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift,
1356                    rc);
1357  }
1358
1359  template <typename Field>
1360  void DecodeField(Register reg, RCBit rc = LeaveRC) {
1361    DecodeField<Field>(reg, reg, rc);
1362  }
1363
1364 private:
1365  static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1366
1367  // Helper functions for generating invokes.
1368  void InvokePrologue(Register expected_parameter_count,
1369                      Register actual_parameter_count, Label* done,
1370                      InvokeType type);
1371
1372  DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler);
1373};
1374
1375#define ACCESS_MASM(masm) masm->
1376
1377}  // namespace internal
1378}  // namespace v8
1379
1380#endif  // V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
1381