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 18namespace v8 { 19namespace internal { 20 21// Forward declarations 22enum 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. 37enum LeaveExitFrameMode { EMIT_RETURN = true, NO_EMIT_RETURN = false }; 38 39// Flags used for the li macro-assembler function. 40enum 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 49enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved }; 50 51Register 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. 60inline 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(). 66inline 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 73class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { 74 public: 75 using TurboAssemblerBase::TurboAssemblerBase; 76 77 // Activation support. 78 void EnterFrame(StackFrame::Type type); 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 85 void AllocateStackSpace(Register bytes) { Subu(sp, sp, 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 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. 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) 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 157 void CompareIsNanF32(FPURegister cmp1, FPURegister cmp2) { 158 CompareIsNanF(S, cmp1, cmp2); 159 } 160 161 void CompareF64(FPUCondition cc, FPURegister cmp1, FPURegister cmp2) { 162 CompareF(D, cc, cmp1, cmp2); 163 } 164 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 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 279 void push(Register src) { 280 Addu(sp, sp, Operand(-kPointerSize)); 281 sw(src, MemOperand(sp, 0)); 282 } 283 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). 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). 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). 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). 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 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 373 void pop(Register dst) { 374 lw(dst, MemOperand(sp, 0)); 375 Addu(sp, sp, Operand(kPointerSize)); 376 } 377 378 void Pop(Register dst) { pop(dst); } 379 380 // Pop two registers. Pops rightmost register first (from lower address). 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). 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) 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 472 void SmiUntag(Register dst, Register src) { sra(dst, src, kSmiTagSize); } 473 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. 519 inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); } 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 706 bool IsDoubleZeroRegSet() { return has_double_zero_reg_set_; } 707 708 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); } 709 710 inline void Move(Register dst, Handle<HeapObject> handle) { li(dst, handle); } 711 inline void Move(Register dst, Smi smi) { li(dst, Operand(smi)); } 712 713 inline void Move(Register dst, Register src) { 714 if (dst != src) { 715 mov(dst, src); 716 } 717 } 718 719 inline void Move_d(FPURegister dst, FPURegister src) { 720 if (dst != src) { 721 mov_d(dst, src); 722 } 723 } 724 725 inline void Move_s(FPURegister dst, FPURegister src) { 726 if (dst != src) { 727 mov_s(dst, src); 728 } 729 } 730 731 inline void Move(FPURegister dst, FPURegister src) { Move_d(dst, src); } 732 733 inline void Move(Register dst_low, Register dst_high, FPURegister src) { 734 mfc1(dst_low, src); 735 Mfhc1(dst_high, src); 736 } 737 738 inline void FmoveHigh(Register dst_high, FPURegister src) { 739 Mfhc1(dst_high, src); 740 } 741 742 inline void FmoveHigh(FPURegister dst, Register src_high) { 743 Mthc1(src_high, dst); 744 } 745 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 752 inline void Move(FPURegister dst, Register src_low, Register src_high) { 753 mtc1(src_low, dst); 754 Mthc1(src_high, dst); 755 } 756 757 void Move(FPURegister dst, float imm) { Move(dst, bit_cast<uint32_t>(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 813 void JumpIfEqual(Register a, int32_t b, Label* dest) { 814 li(kScratchReg, Operand(b)); 815 Branch(dest, eq, a, Operand(kScratchReg)); 816 } 817 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. 837 void CodeEntry() {} 838 // Define an exception handler. 839 void ExceptionHandler() {} 840 // Define an exception handler and bind a 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. 914class 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. 922 void LoadReceiver(Register dest, Register argc) { 923 Lw(dest, MemOperand(sp, 0)); 924 } 925 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 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. 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. 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. 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 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); 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 1112 void SmiTag(Register reg) { Addu(reg, reg, reg); } 1113 1114 void SmiTag(Register dst, Register src) { Addu(dst, src, src); } 1115 1116 // Test if the register contains a smi. 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> 1152 void DecodeField(Register dst, Register src) { 1153 Ext(dst, src, Field::kShift, Field::kSize); 1154 } 1155 1156 template <typename Field> 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 1170template <typename Func> 1171void 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