1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDED_FROM_MACRO_ASSEMBLER_H
6#error This header must be included via macro-assembler.h
7#endif
8
9#ifndef V8_CODEGEN_MIPS_MACRO_ASSEMBLER_MIPS_H_
10#define V8_CODEGEN_MIPS_MACRO_ASSEMBLER_MIPS_H_
11
12#include "src/codegen/assembler.h"
13#include "src/codegen/mips/assembler-mips.h"
14#include "src/common/globals.h"
15#include "src/objects/contexts.h"
16#include "src/objects/tagged-index.h"
17
18namespace v8 {
19namespace internal {
20
21// Forward declarations
22enum class AbortReason : uint8_t;
23
24// Reserved Register Usage Summary.
25//
26// Registers t8, t9, and at are reserved for use by the MacroAssembler.
27//
28// The programmer should know that the MacroAssembler may clobber these three,
29// but won't touch other registers except in special cases.
30//
31// Per the MIPS ABI, register t9 must be used for indirect function call
32// via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when
33// trying to update gp register for position-independent-code. Whenever
34// MIPS generated code calls C code, it must be via t9 register.
35
36// Flags used for LeaveExitFrame function.
37enum LeaveExitFrameMode { EMIT_RETURN = true, NO_EMIT_RETURN = false };
38
39// Flags used for the li macro-assembler function.
40enum LiFlags {
41  // If the constant value can be represented in just 16 bits, then
42  // optimize the li to use a single instruction, rather than lui/ori pair.
43  OPTIMIZE_SIZE = 0,
44  // Always use 2 instructions (lui/ori pair), even if the constant could
45  // be loaded with just one, so that this value is patchable later.
46  CONSTANT_SIZE = 1
47};
48
49enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved };
50
51Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg,
52                                   Register reg3 = no_reg,
53                                   Register reg4 = no_reg,
54                                   Register reg5 = no_reg,
55                                   Register reg6 = no_reg);
56
57// -----------------------------------------------------------------------------
58// Static helper functions.
59// Generate a MemOperand for loading a field from an object.
60inline MemOperand FieldMemOperand(Register object, int offset) {
61  return MemOperand(object, offset - kHeapObjectTag);
62}
63
64// Generate a MemOperand for storing arguments 5..N on the stack
65// when calling CallCFunction().
66inline MemOperand CFunctionArgumentOperand(int index) {
67  DCHECK_GT(index, kCArgSlotCount);
68  // Argument 5 takes the slot just past the four Arg-slots.
69  int offset = (index - 5) * kPointerSize + kCArgsSlotsSize;
70  return MemOperand(sp, offset);
71}
72
73class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
74 public:
75  using TurboAssemblerBase::TurboAssemblerBase;
76
77  // Activation support.
78  void EnterFrame(StackFrame::Type type);
79  void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg) {
80    // Out-of-line constant pool not implemented on mips.
81    UNREACHABLE();
82  }
83  void LeaveFrame(StackFrame::Type type);
84
85  void AllocateStackSpace(Register bytes) { Subu(sp, sp, bytes); }
86  void AllocateStackSpace(int bytes) {
87    DCHECK_GE(bytes, 0);
88    if (bytes == 0) return;
89    Subu(sp, sp, Operand(bytes));
90  }
91
92  // Generates function and stub prologue code.
93  void StubPrologue(StackFrame::Type type);
94  void Prologue();
95
96  void InitializeRootRegister() {
97    ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
98    li(kRootRegister, Operand(isolate_root));
99  }
100
101  // Jump unconditionally to given label.
102  // We NEED a nop in the branch delay slot, as it used by v8, for example in
103  // CodeGenerator::ProcessDeferred().
104  // Currently the branch delay slot is filled by the MacroAssembler.
105  // Use rather b(Label) for code generation.
106  void jmp(Label* L) { Branch(L); }
107
108  // -------------------------------------------------------------------------
109  // Debugging.
110
111  void Trap();
112  void DebugBreak();
113
114  // Calls Abort(msg) if the condition cc is not satisfied.
115  // Use --debug_code to enable.
116  void Assert(Condition cc, AbortReason reason, Register rs, Operand rt);
117
118  // Like Assert(), but always enabled.
119  void Check(Condition cc, AbortReason reason, Register rs, Operand rt);
120
121  // Print a message to stdout and abort execution.
122  void Abort(AbortReason msg);
123
124  // Arguments macros.
125#define COND_TYPED_ARGS Condition cond, Register r1, const Operand &r2
126#define COND_ARGS cond, r1, r2
127
128  // Cases when relocation is not needed.
129#define DECLARE_NORELOC_PROTOTYPE(Name, target_type)                          \
130  void Name(target_type target, BranchDelaySlot bd = PROTECT);                \
131  inline void Name(BranchDelaySlot bd, target_type target) {                  \
132    Name(target, bd);                                                         \
133  }                                                                           \
134  void Name(target_type target, COND_TYPED_ARGS,                              \
135            BranchDelaySlot bd = PROTECT);                                    \
136  inline void Name(BranchDelaySlot bd, target_type target, COND_TYPED_ARGS) { \
137    Name(target, COND_ARGS, bd);                                              \
138  }
139
140#define DECLARE_BRANCH_PROTOTYPES(Name)   \
141  DECLARE_NORELOC_PROTOTYPE(Name, Label*) \
142  DECLARE_NORELOC_PROTOTYPE(Name, int32_t)
143
144  DECLARE_BRANCH_PROTOTYPES(Branch)
145  DECLARE_BRANCH_PROTOTYPES(BranchAndLink)
146  DECLARE_BRANCH_PROTOTYPES(BranchShort)
147
148#undef DECLARE_BRANCH_PROTOTYPES
149#undef COND_TYPED_ARGS
150#undef COND_ARGS
151
152  // Floating point branches
153  void CompareF32(FPUCondition cc, FPURegister cmp1, FPURegister cmp2) {
154    CompareF(S, cc, cmp1, cmp2);
155  }
156
157  void CompareIsNanF32(FPURegister cmp1, FPURegister cmp2) {
158    CompareIsNanF(S, cmp1, cmp2);
159  }
160
161  void CompareF64(FPUCondition cc, FPURegister cmp1, FPURegister cmp2) {
162    CompareF(D, cc, cmp1, cmp2);
163  }
164
165  void CompareIsNanF64(FPURegister cmp1, FPURegister cmp2) {
166    CompareIsNanF(D, cmp1, cmp2);
167  }
168
169  void BranchTrueShortF(Label* target, BranchDelaySlot bd = PROTECT);
170  void BranchFalseShortF(Label* target, BranchDelaySlot bd = PROTECT);
171
172  void BranchTrueF(Label* target, BranchDelaySlot bd = PROTECT);
173  void BranchFalseF(Label* target, BranchDelaySlot bd = PROTECT);
174
175  // MSA Branches
176  void BranchMSA(Label* target, MSABranchDF df, MSABranchCondition cond,
177                 MSARegister wt, BranchDelaySlot bd = PROTECT);
178
179  void BranchLong(int32_t offset, BranchDelaySlot bdslot = PROTECT);
180  void Branch(Label* L, Condition cond, Register rs, RootIndex index,
181              BranchDelaySlot bdslot = PROTECT);
182
183  // Load int32 in the rd register.
184  void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE);
185  inline void li(Register rd, int32_t j, LiFlags mode = OPTIMIZE_SIZE) {
186    li(rd, Operand(j), mode);
187  }
188  void li(Register dst, Handle<HeapObject> value, LiFlags mode = OPTIMIZE_SIZE);
189  void li(Register dst, ExternalReference value, LiFlags mode = OPTIMIZE_SIZE);
190  void li(Register dst, const StringConstantBase* string,
191          LiFlags mode = OPTIMIZE_SIZE);
192
193  void LoadFromConstantsTable(Register destination, int constant_index) final;
194  void LoadRootRegisterOffset(Register destination, intptr_t offset) final;
195  void LoadRootRelative(Register destination, int32_t offset) final;
196
197  inline void Move(Register output, MemOperand operand) { Lw(output, operand); }
198
199// Jump, Call, and Ret pseudo instructions implementing inter-working.
200#define COND_ARGS                                  \
201  Condition cond = al, Register rs = zero_reg,     \
202            const Operand &rt = Operand(zero_reg), \
203            BranchDelaySlot bd = PROTECT
204
205  void Jump(Register target, int16_t offset = 0, COND_ARGS);
206  void Jump(Register target, Register base, int16_t offset = 0, COND_ARGS);
207  void Jump(Register target, const Operand& offset, COND_ARGS);
208  void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS);
209  void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS);
210  // Deffer from li, this method save target to the memory, and then load
211  // it to register use lw, it can be used in wasm jump table for concurrent
212  // patching.
213  void PatchAndJump(Address target);
214  void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS);
215  void Jump(const ExternalReference& reference);
216  void Call(Register target, int16_t offset = 0, COND_ARGS);
217  void Call(Register target, Register base, int16_t offset = 0, COND_ARGS);
218  void Call(Address target, RelocInfo::Mode rmode, COND_ARGS);
219  void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
220            COND_ARGS);
221  void Call(Label* target);
222  void LoadAddress(Register dst, Label* target);
223
224  // Load the builtin given by the Smi in |builtin| into the same
225  // register.
226  void LoadEntryFromBuiltinIndex(Register builtin);
227  void LoadEntryFromBuiltin(Builtin builtin, Register destination);
228  MemOperand EntryFromBuiltinAsOperand(Builtin builtin);
229
230  void CallBuiltinByIndex(Register builtin_index);
231  void CallBuiltin(Builtin builtin);
232
233  void LoadCodeObjectEntry(Register destination, Register code_object);
234  void CallCodeObject(Register code_object);
235
236  void JumpCodeObject(Register code_object,
237                      JumpMode jump_mode = JumpMode::kJump);
238
239  // Generates an instruction sequence s.t. the return address points to the
240  // instruction following the call.
241  // The return address on the stack is used by frame iteration.
242  void StoreReturnAddressAndCall(Register target);
243
244  void CallForDeoptimization(Builtin target, int deopt_id, Label* exit,
245                             DeoptimizeKind kind, Label* ret,
246                             Label* jump_deoptimization_entry_label);
247
248  void Ret(COND_ARGS);
249  inline void Ret(BranchDelaySlot bd, Condition cond = al,
250                  Register rs = zero_reg,
251                  const Operand& rt = Operand(zero_reg)) {
252    Ret(cond, rs, rt, bd);
253  }
254
255  // Emit code to discard a non-negative number of pointer-sized elements
256  // from the stack, clobbering only the sp register.
257  void Drop(int count, Condition cond = cc_always, Register reg = no_reg,
258            const Operand& op = Operand(no_reg));
259
260  // We assume the size of the arguments is the pointer size.
261  // An optional mode argument is passed, which can indicate we need to
262  // explicitly add the receiver to the count.
263  enum ArgumentsCountMode { kCountIncludesReceiver, kCountExcludesReceiver };
264  enum ArgumentsCountType { kCountIsInteger, kCountIsSmi, kCountIsBytes };
265  void DropArguments(Register count, ArgumentsCountType type,
266                     ArgumentsCountMode mode);
267  void DropArgumentsAndPushNewReceiver(Register argc, Register receiver,
268                                       ArgumentsCountType type,
269                                       ArgumentsCountMode mode);
270
271  // Trivial case of DropAndRet that utilizes the delay slot.
272  void DropAndRet(int drop);
273
274  void DropAndRet(int drop, Condition cond, Register reg, const Operand& op);
275
276  void Lw(Register rd, const MemOperand& rs);
277  void Sw(Register rd, const MemOperand& rs);
278
279  void push(Register src) {
280    Addu(sp, sp, Operand(-kPointerSize));
281    sw(src, MemOperand(sp, 0));
282  }
283
284  void Push(Register src) { push(src); }
285  void Push(Handle<HeapObject> handle);
286  void Push(Smi smi);
287
288  // Push two registers. Pushes leftmost register first (to highest address).
289  void Push(Register src1, Register src2) {
290    Subu(sp, sp, Operand(2 * kPointerSize));
291    sw(src1, MemOperand(sp, 1 * kPointerSize));
292    sw(src2, MemOperand(sp, 0 * kPointerSize));
293  }
294
295  // Push three registers. Pushes leftmost register first (to highest address).
296  void Push(Register src1, Register src2, Register src3) {
297    Subu(sp, sp, Operand(3 * kPointerSize));
298    sw(src1, MemOperand(sp, 2 * kPointerSize));
299    sw(src2, MemOperand(sp, 1 * kPointerSize));
300    sw(src3, MemOperand(sp, 0 * kPointerSize));
301  }
302
303  // Push four registers. Pushes leftmost register first (to highest address).
304  void Push(Register src1, Register src2, Register src3, Register src4) {
305    Subu(sp, sp, Operand(4 * kPointerSize));
306    sw(src1, MemOperand(sp, 3 * kPointerSize));
307    sw(src2, MemOperand(sp, 2 * kPointerSize));
308    sw(src3, MemOperand(sp, 1 * kPointerSize));
309    sw(src4, MemOperand(sp, 0 * kPointerSize));
310  }
311
312  // Push five registers. Pushes leftmost register first (to highest address).
313  void Push(Register src1, Register src2, Register src3, Register src4,
314            Register src5) {
315    Subu(sp, sp, Operand(5 * kPointerSize));
316    sw(src1, MemOperand(sp, 4 * kPointerSize));
317    sw(src2, MemOperand(sp, 3 * kPointerSize));
318    sw(src3, MemOperand(sp, 2 * kPointerSize));
319    sw(src4, MemOperand(sp, 1 * kPointerSize));
320    sw(src5, MemOperand(sp, 0 * kPointerSize));
321  }
322
323  void Push(Register src, Condition cond, Register tst1, Register tst2) {
324    // Since we don't have conditional execution we use a Branch.
325    Branch(3, cond, tst1, Operand(tst2));
326    Subu(sp, sp, Operand(kPointerSize));
327    sw(src, MemOperand(sp, 0));
328  }
329
330  enum PushArrayOrder { kNormal, kReverse };
331  void PushArray(Register array, Register size, Register scratch,
332                 Register scratch2, PushArrayOrder order = kNormal);
333
334  void MaybeSaveRegisters(RegList registers);
335  void MaybeRestoreRegisters(RegList registers);
336
337  void CallEphemeronKeyBarrier(Register object, Register slot_address,
338                               SaveFPRegsMode fp_mode);
339
340  void CallRecordWriteStubSaveRegisters(
341      Register object, Register slot_address,
342      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
343      StubCallMode mode = StubCallMode::kCallBuiltinPointer);
344  void CallRecordWriteStub(
345      Register object, Register slot_address,
346      RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
347      StubCallMode mode = StubCallMode::kCallBuiltinPointer);
348
349  // Push multiple registers on the stack.
350  // Registers are saved in numerical order, with higher numbered registers
351  // saved in higher memory addresses.
352  void MultiPush(RegList regs);
353  void MultiPushFPU(DoubleRegList regs);
354
355  // Calculate how much stack space (in bytes) are required to store caller
356  // registers excluding those specified in the arguments.
357  int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
358                                      Register exclusion1 = no_reg,
359                                      Register exclusion2 = no_reg,
360                                      Register exclusion3 = no_reg) const;
361
362  // Push caller saved registers on the stack, and return the number of bytes
363  // stack pointer is adjusted.
364  int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
365                      Register exclusion2 = no_reg,
366                      Register exclusion3 = no_reg);
367  // Restore caller saved registers from the stack, and return the number of
368  // bytes stack pointer is adjusted.
369  int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
370                     Register exclusion2 = no_reg,
371                     Register exclusion3 = no_reg);
372
373  void pop(Register dst) {
374    lw(dst, MemOperand(sp, 0));
375    Addu(sp, sp, Operand(kPointerSize));
376  }
377
378  void Pop(Register dst) { pop(dst); }
379
380  // Pop two registers. Pops rightmost register first (from lower address).
381  void Pop(Register src1, Register src2) {
382    DCHECK(src1 != src2);
383    lw(src2, MemOperand(sp, 0 * kPointerSize));
384    lw(src1, MemOperand(sp, 1 * kPointerSize));
385    Addu(sp, sp, 2 * kPointerSize);
386  }
387
388  // Pop three registers. Pops rightmost register first (from lower address).
389  void Pop(Register src1, Register src2, Register src3) {
390    lw(src3, MemOperand(sp, 0 * kPointerSize));
391    lw(src2, MemOperand(sp, 1 * kPointerSize));
392    lw(src1, MemOperand(sp, 2 * kPointerSize));
393    Addu(sp, sp, 3 * kPointerSize);
394  }
395
396  void Pop(uint32_t count = 1) { Addu(sp, sp, Operand(count * kPointerSize)); }
397
398  // Pops multiple values from the stack and load them in the
399  // registers specified in regs. Pop order is the opposite as in MultiPush.
400  void MultiPop(RegList regs);
401  void MultiPopFPU(DoubleRegList regs);
402
403  // Load Scaled Address instructions. Parameter sa (shift argument) must be
404  // between [1, 31] (inclusive). On pre-r6 architectures the scratch register
405  // may be clobbered.
406  void Lsa(Register rd, Register rs, Register rt, uint8_t sa,
407           Register scratch = at);
408
409#define DEFINE_INSTRUCTION(instr)                          \
410  void instr(Register rd, Register rs, const Operand& rt); \
411  void instr(Register rd, Register rs, Register rt) {      \
412    instr(rd, rs, Operand(rt));                            \
413  }                                                        \
414  void instr(Register rs, Register rt, int32_t j) { instr(rs, rt, Operand(j)); }
415
416#define DEFINE_INSTRUCTION2(instr)                                 \
417  void instr(Register rs, const Operand& rt);                      \
418  void instr(Register rs, Register rt) { instr(rs, Operand(rt)); } \
419  void instr(Register rs, int32_t j) { instr(rs, Operand(j)); }
420
421#define DEFINE_INSTRUCTION3(instr)                                            \
422  void instr(Register rd_hi, Register rd_lo, Register rs, const Operand& rt); \
423  void instr(Register rd_hi, Register rd_lo, Register rs, Register rt) {      \
424    instr(rd_hi, rd_lo, rs, Operand(rt));                                     \
425  }                                                                           \
426  void instr(Register rd_hi, Register rd_lo, Register rs, int32_t j) {        \
427    instr(rd_hi, rd_lo, rs, Operand(j));                                      \
428  }
429
430  DEFINE_INSTRUCTION(Addu)
431  DEFINE_INSTRUCTION(Subu)
432  DEFINE_INSTRUCTION(Mul)
433  DEFINE_INSTRUCTION(Div)
434  DEFINE_INSTRUCTION(Divu)
435  DEFINE_INSTRUCTION(Mod)
436  DEFINE_INSTRUCTION(Modu)
437  DEFINE_INSTRUCTION(Mulh)
438  DEFINE_INSTRUCTION2(Mult)
439  DEFINE_INSTRUCTION(Mulhu)
440  DEFINE_INSTRUCTION2(Multu)
441  DEFINE_INSTRUCTION2(Div)
442  DEFINE_INSTRUCTION2(Divu)
443
444  DEFINE_INSTRUCTION3(Div)
445  DEFINE_INSTRUCTION3(Mul)
446  DEFINE_INSTRUCTION3(Mulu)
447
448  DEFINE_INSTRUCTION(And)
449  DEFINE_INSTRUCTION(Or)
450  DEFINE_INSTRUCTION(Xor)
451  DEFINE_INSTRUCTION(Nor)
452  DEFINE_INSTRUCTION2(Neg)
453
454  DEFINE_INSTRUCTION(Slt)
455  DEFINE_INSTRUCTION(Sltu)
456  DEFINE_INSTRUCTION(Sle)
457  DEFINE_INSTRUCTION(Sleu)
458  DEFINE_INSTRUCTION(Sgt)
459  DEFINE_INSTRUCTION(Sgtu)
460  DEFINE_INSTRUCTION(Sge)
461  DEFINE_INSTRUCTION(Sgeu)
462
463  // MIPS32 R2 instruction macro.
464  DEFINE_INSTRUCTION(Ror)
465
466#undef DEFINE_INSTRUCTION
467#undef DEFINE_INSTRUCTION2
468#undef DEFINE_INSTRUCTION3
469
470  void SmiUntag(Register reg) { sra(reg, reg, kSmiTagSize); }
471
472  void SmiUntag(Register dst, Register src) { sra(dst, src, kSmiTagSize); }
473
474  void SmiToInt32(Register smi) { SmiUntag(smi); }
475
476  int CalculateStackPassedWords(int num_reg_arguments,
477                                int num_double_arguments);
478
479  // Before calling a C-function from generated code, align arguments on stack
480  // and add space for the four mips argument slots.
481  // After aligning the frame, non-register arguments must be stored on the
482  // stack, after the argument-slots using helper: CFunctionArgumentOperand().
483  // The argument count assumes all arguments are word sized.
484  // Some compilers/platforms require the stack to be aligned when calling
485  // C++ code.
486  // Needs a scratch register to do some arithmetic. This register will be
487  // trashed.
488  void PrepareCallCFunction(int num_reg_arguments, int num_double_registers,
489                            Register scratch);
490  void PrepareCallCFunction(int num_reg_arguments, Register scratch);
491
492  // Arguments 1-4 are placed in registers a0 through a3 respectively.
493  // Arguments 5..n are stored to stack using following:
494  //  sw(t0, CFunctionArgumentOperand(5));
495
496  // Calls a C function and cleans up the space for arguments allocated
497  // by PrepareCallCFunction. The called function is not allowed to trigger a
498  // garbage collection, since that might move the code and invalidate the
499  // return address (unless this is somehow accounted for by the called
500  // function).
501  void CallCFunction(ExternalReference function, int num_arguments);
502  void CallCFunction(Register function, int num_arguments);
503  void CallCFunction(ExternalReference function, int num_reg_arguments,
504                     int num_double_arguments);
505  void CallCFunction(Register function, int num_reg_arguments,
506                     int num_double_arguments);
507  void MovFromFloatResult(DoubleRegister dst);
508  void MovFromFloatParameter(DoubleRegister dst);
509
510  // There are two ways of passing double arguments on MIPS, depending on
511  // whether soft or hard floating point ABI is used. These functions
512  // abstract parameter passing for the three different ways we call
513  // C functions from generated code.
514  void MovToFloatParameter(DoubleRegister src);
515  void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
516  void MovToFloatResult(DoubleRegister src);
517
518  // See comments at the beginning of Builtins::Generate_CEntry.
519  inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); }
520  inline void PrepareCEntryFunction(const ExternalReference& ref) {
521    li(a1, ref);
522  }
523
524  void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
525                     Label* condition_met);
526#undef COND_ARGS
527
528  // Performs a truncating conversion of a floating point number as used by
529  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
530  // Exits with 'result' holding the answer.
531  void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result,
532                         DoubleRegister double_input, StubCallMode stub_mode);
533
534  // Conditional move.
535  void Movz(Register rd, Register rs, Register rt);
536  void Movn(Register rd, Register rs, Register rt);
537  void Movt(Register rd, Register rs, uint16_t cc = 0);
538  void Movf(Register rd, Register rs, uint16_t cc = 0);
539
540  void LoadZeroIfFPUCondition(Register dest);
541  void LoadZeroIfNotFPUCondition(Register dest);
542
543  void LoadZeroIfConditionNotZero(Register dest, Register condition);
544  void LoadZeroIfConditionZero(Register dest, Register condition);
545  void LoadZeroOnCondition(Register rd, Register rs, const Operand& rt,
546                           Condition cond);
547
548  void Clz(Register rd, Register rs);
549  void Ctz(Register rd, Register rs);
550  void Popcnt(Register rd, Register rs);
551
552  // Int64Lowering instructions
553  void AddPair(Register dst_low, Register dst_high, Register left_low,
554               Register left_high, Register right_low, Register right_high,
555               Register scratch1, Register scratch2);
556
557  void AddPair(Register dst_low, Register dst_high, Register left_low,
558               Register left_high, int32_t imm, Register scratch1,
559               Register scratch2);
560
561  void SubPair(Register dst_low, Register dst_high, Register left_low,
562               Register left_high, Register right_low, Register right_high,
563               Register scratch1, Register scratch2);
564
565  void AndPair(Register dst_low, Register dst_high, Register left_low,
566               Register left_high, Register right_low, Register right_high);
567
568  void OrPair(Register dst_low, Register dst_high, Register left_low,
569              Register left_high, Register right_low, Register right_high);
570
571  void XorPair(Register dst_low, Register dst_high, Register left_low,
572               Register left_high, Register right_low, Register right_high);
573
574  void MulPair(Register dst_low, Register dst_high, Register left_low,
575               Register left_high, Register right_low, Register right_high,
576               Register scratch1, Register scratch2);
577
578  void ShlPair(Register dst_low, Register dst_high, Register src_low,
579               Register src_high, Register shift, Register scratch1,
580               Register scratch2);
581
582  void ShlPair(Register dst_low, Register dst_high, Register src_low,
583               Register src_high, uint32_t shift, Register scratch);
584
585  void ShrPair(Register dst_low, Register dst_high, Register src_low,
586               Register src_high, Register shift, Register scratch1,
587               Register scratch2);
588
589  void ShrPair(Register dst_low, Register dst_high, Register src_low,
590               Register src_high, uint32_t shift, Register scratch);
591
592  void SarPair(Register dst_low, Register dst_high, Register src_low,
593               Register src_high, Register shift, Register scratch1,
594               Register scratch2);
595
596  void SarPair(Register dst_low, Register dst_high, Register src_low,
597               Register src_high, uint32_t shift, Register scratch);
598
599  // MIPS32 R2 instruction macro.
600  void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
601  void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
602  void ExtractBits(Register dest, Register source, Register pos, int size,
603                   bool sign_extend = false);
604  void InsertBits(Register dest, Register source, Register pos, int size);
605
606  void Seb(Register rd, Register rt);
607  void Seh(Register rd, Register rt);
608  void Neg_s(FPURegister fd, FPURegister fs);
609  void Neg_d(FPURegister fd, FPURegister fs);
610
611  // MIPS32 R6 instruction macros.
612  void Bovc(Register rt, Register rs, Label* L);
613  void Bnvc(Register rt, Register rs, Label* L);
614
615  // Convert single to unsigned word.
616  void Trunc_uw_s(FPURegister fd, FPURegister fs, FPURegister scratch);
617  void Trunc_uw_s(Register rd, FPURegister fs, FPURegister scratch);
618
619  void Trunc_w_d(FPURegister fd, FPURegister fs);
620  void Round_w_d(FPURegister fd, FPURegister fs);
621  void Floor_w_d(FPURegister fd, FPURegister fs);
622  void Ceil_w_d(FPURegister fd, FPURegister fs);
623
624  // Round double functions
625  void Trunc_d_d(FPURegister fd, FPURegister fs);
626  void Round_d_d(FPURegister fd, FPURegister fs);
627  void Floor_d_d(FPURegister fd, FPURegister fs);
628  void Ceil_d_d(FPURegister fd, FPURegister fs);
629
630  // Round float functions
631  void Trunc_s_s(FPURegister fd, FPURegister fs);
632  void Round_s_s(FPURegister fd, FPURegister fs);
633  void Floor_s_s(FPURegister fd, FPURegister fs);
634  void Ceil_s_s(FPURegister fd, FPURegister fs);
635
636  // FP32 mode: Move the general purpose register into
637  // the high part of the double-register pair.
638  // FP64 mode: Move the general-purpose register into
639  // the higher 32 bits of the 64-bit coprocessor register,
640  // while leaving the low bits unchanged.
641  void Mthc1(Register rt, FPURegister fs);
642
643  // FP32 mode: move the high part of the double-register pair into
644  // general purpose register.
645  // FP64 mode: Move the higher 32 bits of the 64-bit coprocessor register into
646  // general-purpose register.
647  void Mfhc1(Register rt, FPURegister fs);
648
649  void Madd_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft,
650              FPURegister scratch);
651  void Madd_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft,
652              FPURegister scratch);
653  void Msub_s(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft,
654              FPURegister scratch);
655  void Msub_d(FPURegister fd, FPURegister fr, FPURegister fs, FPURegister ft,
656              FPURegister scratch);
657
658  // Change endianness
659  void ByteSwapSigned(Register dest, Register src, int operand_size);
660  void ByteSwapUnsigned(Register dest, Register src, int operand_size);
661
662  void Ulh(Register rd, const MemOperand& rs);
663  void Ulhu(Register rd, const MemOperand& rs);
664  void Ush(Register rd, const MemOperand& rs, Register scratch);
665
666  void Ulw(Register rd, const MemOperand& rs);
667  void Usw(Register rd, const MemOperand& rs);
668
669  void Ulwc1(FPURegister fd, const MemOperand& rs, Register scratch);
670  void Uswc1(FPURegister fd, const MemOperand& rs, Register scratch);
671
672  void Uldc1(FPURegister fd, const MemOperand& rs, Register scratch);
673  void Usdc1(FPURegister fd, const MemOperand& rs, Register scratch);
674
675  void Ldc1(FPURegister fd, const MemOperand& src);
676  void Sdc1(FPURegister fs, const MemOperand& dst);
677
678  void Ll(Register rd, const MemOperand& rs);
679  void Sc(Register rd, const MemOperand& rs);
680
681  // Perform a floating-point min or max operation with the
682  // (IEEE-754-compatible) semantics of MIPS32's Release 6 MIN.fmt/MAX.fmt.
683  // Some cases, typically NaNs or +/-0.0, are expected to be rare and are
684  // handled in out-of-line code. The specific behaviour depends on supported
685  // instructions.
686  //
687  // These functions assume (and assert) that src1!=src2. It is permitted
688  // for the result to alias either input register.
689  void Float32Max(FPURegister dst, FPURegister src1, FPURegister src2,
690                  Label* out_of_line);
691  void Float32Min(FPURegister dst, FPURegister src1, FPURegister src2,
692                  Label* out_of_line);
693  void Float64Max(DoubleRegister dst, DoubleRegister src1, DoubleRegister src2,
694                  Label* out_of_line);
695  void Float64Min(DoubleRegister dst, DoubleRegister src1, DoubleRegister src2,
696                  Label* out_of_line);
697
698  // Generate out-of-line cases for the macros above.
699  void Float32MaxOutOfLine(FPURegister dst, FPURegister src1, FPURegister src2);
700  void Float32MinOutOfLine(FPURegister dst, FPURegister src1, FPURegister src2);
701  void Float64MaxOutOfLine(DoubleRegister dst, DoubleRegister src1,
702                           DoubleRegister src2);
703  void Float64MinOutOfLine(DoubleRegister dst, DoubleRegister src1,
704                           DoubleRegister src2);
705
706  bool IsDoubleZeroRegSet() { return has_double_zero_reg_set_; }
707
708  void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); }
709
710  inline void Move(Register dst, Handle<HeapObject> handle) { li(dst, handle); }
711  inline void Move(Register dst, Smi smi) { li(dst, Operand(smi)); }
712
713  inline void Move(Register dst, Register src) {
714    if (dst != src) {
715      mov(dst, src);
716    }
717  }
718
719  inline void Move_d(FPURegister dst, FPURegister src) {
720    if (dst != src) {
721      mov_d(dst, src);
722    }
723  }
724
725  inline void Move_s(FPURegister dst, FPURegister src) {
726    if (dst != src) {
727      mov_s(dst, src);
728    }
729  }
730
731  inline void Move(FPURegister dst, FPURegister src) { Move_d(dst, src); }
732
733  inline void Move(Register dst_low, Register dst_high, FPURegister src) {
734    mfc1(dst_low, src);
735    Mfhc1(dst_high, src);
736  }
737
738  inline void FmoveHigh(Register dst_high, FPURegister src) {
739    Mfhc1(dst_high, src);
740  }
741
742  inline void FmoveHigh(FPURegister dst, Register src_high) {
743    Mthc1(src_high, dst);
744  }
745
746  inline void FmoveLow(Register dst_low, FPURegister src) {
747    mfc1(dst_low, src);
748  }
749
750  void FmoveLow(FPURegister dst, Register src_low);
751
752  inline void Move(FPURegister dst, Register src_low, Register src_high) {
753    mtc1(src_low, dst);
754    Mthc1(src_high, dst);
755  }
756
757  void Move(FPURegister dst, float imm) { Move(dst, bit_cast<uint32_t>(imm)); }
758  void Move(FPURegister dst, double imm) { Move(dst, bit_cast<uint64_t>(imm)); }
759  void Move(FPURegister dst, uint32_t src);
760  void Move(FPURegister dst, uint64_t src);
761
762  // -------------------------------------------------------------------------
763  // Overflow operations.
764
765  // AddOverflow sets overflow register to a negative value if
766  // overflow occured, otherwise it is zero or positive
767  void AddOverflow(Register dst, Register left, const Operand& right,
768                   Register overflow);
769  // SubOverflow sets overflow register to a negative value if
770  // overflow occured, otherwise it is zero or positive
771  void SubOverflow(Register dst, Register left, const Operand& right,
772                   Register overflow);
773  // MulOverflow sets overflow register to zero if no overflow occured
774  void MulOverflow(Register dst, Register left, const Operand& right,
775                   Register overflow);
776
777// Number of instructions needed for calculation of switch table entry address
778#ifdef _MIPS_ARCH_MIPS32R6
779  static constexpr int kSwitchTablePrologueSize = 5;
780#else
781  static constexpr int kSwitchTablePrologueSize = 10;
782#endif
783  // GetLabelFunction must be lambda '[](size_t index) -> Label*' or a
784  // functor/function with 'Label *func(size_t index)' declaration.
785  template <typename Func>
786  void GenerateSwitchTable(Register index, size_t case_count,
787                           Func GetLabelFunction);
788
789  // Load an object from the root table.
790  void LoadRoot(Register destination, RootIndex index) final;
791  void LoadRoot(Register destination, RootIndex index, Condition cond,
792                Register src1, const Operand& src2);
793
794  void LoadMap(Register destination, Register object);
795
796  // If the value is a NaN, canonicalize the value else, do nothing.
797  void FPUCanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
798
799  // ---------------------------------------------------------------------------
800  // FPU macros. These do not handle special cases like NaN or +- inf.
801
802  // Convert unsigned word to double.
803  void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch);
804
805  // Convert double to unsigned word.
806  void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
807  void Trunc_uw_d(Register rd, FPURegister fs, FPURegister scratch);
808
809  // Jump the register contains a smi.
810  void JumpIfSmi(Register value, Label* smi_label,
811                 BranchDelaySlot bd = PROTECT);
812
813  void JumpIfEqual(Register a, int32_t b, Label* dest) {
814    li(kScratchReg, Operand(b));
815    Branch(dest, eq, a, Operand(kScratchReg));
816  }
817
818  void JumpIfLessThan(Register a, int32_t b, Label* dest) {
819    li(kScratchReg, Operand(b));
820    Branch(dest, lt, a, Operand(kScratchReg));
821  }
822
823  // Push a standard frame, consisting of ra, fp, context and JS function.
824  void PushStandardFrame(Register function_reg);
825
826  // Get the actual activation frame alignment for target environment.
827  static int ActivationFrameAlignment();
828
829  // Compute the start of the generated instruction stream from the current PC.
830  // This is an alternative to embedding the {CodeObject} handle as a reference.
831  void ComputeCodeStartAddress(Register dst);
832
833  // Control-flow integrity:
834
835  // Define a function entrypoint. This doesn't emit any code for this
836  // architecture, as control-flow integrity is not supported for it.
837  void CodeEntry() {}
838  // Define an exception handler.
839  void ExceptionHandler() {}
840  // Define an exception handler and bind a label.
841  void BindExceptionHandler(Label* label) { bind(label); }
842
843 protected:
844  void BranchLong(Label* L, BranchDelaySlot bdslot);
845
846  inline Register GetRtAsRegisterHelper(const Operand& rt, Register scratch);
847
848  inline int32_t GetOffset(int32_t offset, Label* L, OffsetSize bits);
849
850 private:
851  bool has_double_zero_reg_set_ = false;
852
853  // Performs a truncating conversion of a floating point number as used by
854  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
855  // succeeds, otherwise falls through if result is saturated. On return
856  // 'result' either holds answer, or is clobbered on fall through.
857  void TryInlineTruncateDoubleToI(Register result, DoubleRegister input,
858                                  Label* done);
859
860  void CallCFunctionHelper(Register function_base, int16_t function_offset,
861                           int num_reg_arguments, int num_double_arguments);
862
863  void CompareF(SecondaryField sizeField, FPUCondition cc, FPURegister cmp1,
864                FPURegister cmp2);
865
866  void CompareIsNanF(SecondaryField sizeField, FPURegister cmp1,
867                     FPURegister cmp2);
868
869  void BranchShortMSA(MSABranchDF df, Label* target, MSABranchCondition cond,
870                      MSARegister wt, BranchDelaySlot bd = PROTECT);
871
872  // TODO(mips) Reorder parameters so out parameters come last.
873  bool CalculateOffset(Label* L, int32_t* offset, OffsetSize bits);
874  bool CalculateOffset(Label* L, int32_t* offset, OffsetSize bits,
875                       Register* scratch, const Operand& rt);
876
877  void BranchShortHelperR6(int32_t offset, Label* L);
878  void BranchShortHelper(int16_t offset, Label* L, BranchDelaySlot bdslot);
879  bool BranchShortHelperR6(int32_t offset, Label* L, Condition cond,
880                           Register rs, const Operand& rt);
881  bool BranchShortHelper(int16_t offset, Label* L, Condition cond, Register rs,
882                         const Operand& rt, BranchDelaySlot bdslot);
883  bool BranchShortCheck(int32_t offset, Label* L, Condition cond, Register rs,
884                        const Operand& rt, BranchDelaySlot bdslot);
885
886  void BranchAndLinkShortHelperR6(int32_t offset, Label* L);
887  void BranchAndLinkShortHelper(int16_t offset, Label* L,
888                                BranchDelaySlot bdslot);
889  void BranchAndLinkShort(int32_t offset, BranchDelaySlot bdslot = PROTECT);
890  void BranchAndLinkShort(Label* L, BranchDelaySlot bdslot = PROTECT);
891  bool BranchAndLinkShortHelperR6(int32_t offset, Label* L, Condition cond,
892                                  Register rs, const Operand& rt);
893  bool BranchAndLinkShortHelper(int16_t offset, Label* L, Condition cond,
894                                Register rs, const Operand& rt,
895                                BranchDelaySlot bdslot);
896  bool BranchAndLinkShortCheck(int32_t offset, Label* L, Condition cond,
897                               Register rs, const Operand& rt,
898                               BranchDelaySlot bdslot);
899  void BranchAndLinkLong(Label* L, BranchDelaySlot bdslot);
900
901  template <typename RoundFunc>
902  void RoundDouble(FPURegister dst, FPURegister src, FPURoundingMode mode,
903                   RoundFunc round);
904
905  template <typename RoundFunc>
906  void RoundFloat(FPURegister dst, FPURegister src, FPURoundingMode mode,
907                  RoundFunc round);
908
909  // Push a fixed frame, consisting of ra, fp.
910  void PushCommonFrame(Register marker_reg = no_reg);
911};
912
913// MacroAssembler implements a collection of frequently used macros.
914class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
915 public:
916  using TurboAssembler::TurboAssembler;
917
918  // It assumes that the arguments are located below the stack pointer.
919  // argc is the number of arguments not including the receiver.
920  // TODO(victorgomes): Remove this function once we stick with the reversed
921  // arguments order.
922  void LoadReceiver(Register dest, Register argc) {
923    Lw(dest, MemOperand(sp, 0));
924  }
925
926  void StoreReceiver(Register rec, Register argc, Register scratch) {
927    Sw(rec, MemOperand(sp, 0));
928  }
929
930  // Swap two registers.  If the scratch register is omitted then a slightly
931  // less efficient form using xor instead of mov is emitted.
932  void Swap(Register reg1, Register reg2, Register scratch = no_reg);
933
934  void PushRoot(RootIndex index) {
935    UseScratchRegisterScope temps(this);
936    Register scratch = temps.Acquire();
937    LoadRoot(scratch, index);
938    Push(scratch);
939  }
940
941  // Compare the object in a register to a value and jump if they are equal.
942  void JumpIfRoot(Register with, RootIndex index, Label* if_equal) {
943    UseScratchRegisterScope temps(this);
944    Register scratch = temps.Acquire();
945    LoadRoot(scratch, index);
946    Branch(if_equal, eq, with, Operand(scratch));
947  }
948
949  // Compare the object in a register to a value and jump if they are not equal.
950  void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) {
951    UseScratchRegisterScope temps(this);
952    Register scratch = temps.Acquire();
953    LoadRoot(scratch, index);
954    Branch(if_not_equal, ne, with, Operand(scratch));
955  }
956
957  // Checks if value is in range [lower_limit, higher_limit] using a single
958  // comparison.
959  void JumpIfIsInRange(Register value, unsigned lower_limit,
960                       unsigned higher_limit, Label* on_in_range);
961
962  // ---------------------------------------------------------------------------
963  // GC Support
964
965  // Notify the garbage collector that we wrote a pointer into an object.
966  // |object| is the object being stored into, |value| is the object being
967  // stored.  value and scratch registers are clobbered by the operation.
968  // The offset is the offset from the start of the object, not the offset from
969  // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
970  void RecordWriteField(
971      Register object, int offset, Register value, Register scratch,
972      RAStatus ra_status, SaveFPRegsMode save_fp,
973      RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
974      SmiCheck smi_check = SmiCheck::kInline);
975
976  // For a given |object| notify the garbage collector that the slot |address|
977  // has been written.  |value| is the object being stored. The value and
978  // address registers are clobbered by the operation.
979  void RecordWrite(
980      Register object, Register address, Register value, RAStatus ra_status,
981      SaveFPRegsMode save_fp,
982      RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
983      SmiCheck smi_check = SmiCheck::kInline);
984
985  void Pref(int32_t hint, const MemOperand& rs);
986
987  // Enter exit frame.
988  // argc - argument count to be dropped by LeaveExitFrame.
989  // save_doubles - saves FPU registers on stack, currently disabled.
990  // stack_space - extra stack space.
991  void EnterExitFrame(bool save_doubles, int stack_space = 0,
992                      StackFrame::Type frame_type = StackFrame::EXIT);
993
994  // Leave the current exit frame.
995  void LeaveExitFrame(bool save_doubles, Register arg_count,
996                      bool do_return = NO_EMIT_RETURN,
997                      bool argument_count_is_length = false);
998
999  // Make sure the stack is aligned. Only emits code in debug mode.
1000  void AssertStackIsAligned();
1001
1002  // Load the global proxy from the current context.
1003  void LoadGlobalProxy(Register dst) {
1004    LoadNativeContextSlot(dst, Context::GLOBAL_PROXY_INDEX);
1005  }
1006
1007  void LoadNativeContextSlot(Register dst, int index);
1008
1009  // -------------------------------------------------------------------------
1010  // JavaScript invokes.
1011
1012  // Invoke the JavaScript function code by either calling or jumping.
1013  void InvokeFunctionCode(Register function, Register new_target,
1014                          Register expected_parameter_count,
1015                          Register actual_parameter_count, InvokeType type);
1016
1017  // On function call, call into the debugger if necessary.
1018  void CheckDebugHook(Register fun, Register new_target,
1019                      Register expected_parameter_count,
1020                      Register actual_parameter_count);
1021
1022  // Invoke the JavaScript function in the given register. Changes the
1023  // current context to the context in the function before invoking.
1024  void InvokeFunctionWithNewTarget(Register function, Register new_target,
1025                                   Register actual_parameter_count,
1026                                   InvokeType type);
1027
1028  void InvokeFunction(Register function, Register expected_parameter_count,
1029                      Register actual_parameter_count, InvokeType type);
1030
1031  // Exception handling.
1032
1033  // Push a new stack handler and link into stack handler chain.
1034  void PushStackHandler();
1035
1036  // Unlink the stack handler on top of the stack from the stack handler chain.
1037  // Must preserve the result register.
1038  void PopStackHandler();
1039
1040  // -------------------------------------------------------------------------
1041  // Support functions.
1042
1043  void GetObjectType(Register function, Register map, Register type_reg);
1044
1045  void GetInstanceTypeRange(Register map, Register type_reg,
1046                            InstanceType lower_limit, Register range);
1047
1048  // -------------------------------------------------------------------------
1049  // Runtime calls.
1050
1051  // Call a runtime routine.
1052  void CallRuntime(const Runtime::Function* f, int num_arguments,
1053                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore);
1054
1055  // Convenience function: Same as above, but takes the fid instead.
1056  void CallRuntime(Runtime::FunctionId fid,
1057                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1058    const Runtime::Function* function = Runtime::FunctionForId(fid);
1059    CallRuntime(function, function->nargs, save_doubles);
1060  }
1061
1062  // Convenience function: Same as above, but takes the fid instead.
1063  void CallRuntime(Runtime::FunctionId id, int num_arguments,
1064                   SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1065    CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
1066  }
1067
1068  // Convenience function: tail call a runtime routine (jump).
1069  void TailCallRuntime(Runtime::FunctionId fid);
1070
1071  // Jump to the builtin routine.
1072  void JumpToExternalReference(const ExternalReference& builtin,
1073                               BranchDelaySlot bd = PROTECT,
1074                               bool builtin_exit_frame = false);
1075
1076  // Generates a trampoline to jump to the off-heap instruction stream.
1077  void JumpToOffHeapInstructionStream(Address entry);
1078
1079  // ---------------------------------------------------------------------------
1080  // In-place weak references.
1081  void LoadWeakValue(Register out, Register in, Label* target_if_cleared);
1082
1083  // -------------------------------------------------------------------------
1084  // StatsCounter support.
1085
1086  void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
1087                        Register scratch2) {
1088    if (!FLAG_native_code_counters) return;
1089    EmitIncrementCounter(counter, value, scratch1, scratch2);
1090  }
1091  void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch1,
1092                            Register scratch2);
1093  void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
1094                        Register scratch2) {
1095    if (!FLAG_native_code_counters) return;
1096    EmitDecrementCounter(counter, value, scratch1, scratch2);
1097  }
1098  void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch1,
1099                            Register scratch2);
1100
1101  // -------------------------------------------------------------------------
1102  // Stack limit utilities
1103
1104  enum StackLimitKind { kInterruptStackLimit, kRealStackLimit };
1105  void LoadStackLimit(Register destination, StackLimitKind kind);
1106  void StackOverflowCheck(Register num_args, Register scratch1,
1107                          Register scratch2, Label* stack_overflow);
1108
1109  // ---------------------------------------------------------------------------
1110  // Smi utilities.
1111
1112  void SmiTag(Register reg) { Addu(reg, reg, reg); }
1113
1114  void SmiTag(Register dst, Register src) { Addu(dst, src, src); }
1115
1116  // Test if the register contains a smi.
1117  inline void SmiTst(Register value, Register scratch) {
1118    And(scratch, value, Operand(kSmiTagMask));
1119  }
1120
1121  // Jump if the register contains a non-smi.
1122  void JumpIfNotSmi(Register value, Label* not_smi_label,
1123                    BranchDelaySlot bd = PROTECT);
1124
1125  // Abort execution if argument is a smi, enabled via --debug-code.
1126  void AssertNotSmi(Register object);
1127  void AssertSmi(Register object);
1128
1129  // Abort execution if argument is not a Constructor, enabled via --debug-code.
1130  void AssertConstructor(Register object);
1131
1132  // Abort execution if argument is not a JSFunction, enabled via --debug-code.
1133  void AssertFunction(Register object);
1134
1135  // Abort execution if argument is not a callable JSFunction, enabled via
1136  // --debug-code.
1137  void AssertCallableFunction(Register object);
1138
1139  // Abort execution if argument is not a JSBoundFunction,
1140  // enabled via --debug-code.
1141  void AssertBoundFunction(Register object);
1142
1143  // Abort execution if argument is not a JSGeneratorObject (or subclass),
1144  // enabled via --debug-code.
1145  void AssertGeneratorObject(Register object);
1146
1147  // Abort execution if argument is not undefined or an AllocationSite, enabled
1148  // via --debug-code.
1149  void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1150
1151  template <typename Field>
1152  void DecodeField(Register dst, Register src) {
1153    Ext(dst, src, Field::kShift, Field::kSize);
1154  }
1155
1156  template <typename Field>
1157  void DecodeField(Register reg) {
1158    DecodeField<Field>(reg, reg);
1159  }
1160
1161 private:
1162  // Helper functions for generating invokes.
1163  void InvokePrologue(Register expected_parameter_count,
1164                      Register actual_parameter_count, Label* done,
1165                      InvokeType type);
1166
1167  DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler);
1168};
1169
1170template <typename Func>
1171void TurboAssembler::GenerateSwitchTable(Register index, size_t case_count,
1172                                         Func GetLabelFunction) {
1173  Label here;
1174  BlockTrampolinePoolFor(case_count + kSwitchTablePrologueSize);
1175  UseScratchRegisterScope temps(this);
1176  Register scratch = temps.Acquire();
1177  if (kArchVariant >= kMips32r6) {
1178    addiupc(scratch, 5);
1179    Lsa(scratch, scratch, index, kPointerSizeLog2);
1180    lw(scratch, MemOperand(scratch));
1181  } else {
1182    push(ra);
1183    bal(&here);
1184    sll(scratch, index, kPointerSizeLog2);  // Branch delay slot.
1185    bind(&here);
1186    addu(scratch, scratch, ra);
1187    pop(ra);
1188    lw(scratch, MemOperand(scratch, 6 * v8::internal::kInstrSize));
1189  }
1190  jr(scratch);
1191  nop();  // Branch delay slot nop.
1192  for (size_t index = 0; index < case_count; ++index) {
1193    dd(GetLabelFunction(index));
1194  }
1195}
1196
1197#define ACCESS_MASM(masm) masm->
1198
1199}  // namespace internal
1200}  // namespace v8
1201
1202#endif  // V8_CODEGEN_MIPS_MACRO_ASSEMBLER_MIPS_H_
1203