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