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