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