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