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