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