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