MacroAssembler-mips64.h (32215B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_mips64_MacroAssembler_mips64_h 8 #define jit_mips64_MacroAssembler_mips64_h 9 10 #include "jit/mips-shared/MacroAssembler-mips-shared.h" 11 #include "jit/MoveResolver.h" 12 #include "vm/BytecodeUtil.h" 13 #include "wasm/WasmBuiltins.h" 14 15 namespace js { 16 namespace jit { 17 18 enum LiFlags { 19 Li64 = 0, 20 Li48 = 1, 21 }; 22 23 struct ImmShiftedTag : public ImmWord { 24 explicit ImmShiftedTag(JSValueType type) 25 : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))) { 26 } 27 }; 28 29 struct ImmTag : public Imm32 { 30 explicit ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) {} 31 }; 32 33 static constexpr ValueOperand JSReturnOperand{JSReturnReg}; 34 35 static const int defaultShift = 3; 36 static_assert(1 << defaultShift == sizeof(JS::Value), 37 "The defaultShift is wrong"); 38 39 // See documentation for ScratchTagScope and ScratchTagScopeRelease in 40 // MacroAssembler-x64.h. 41 42 class ScratchTagScope { 43 UseScratchRegisterScope temps_; 44 Register scratch_; 45 bool owned_; 46 mozilla::DebugOnly<bool> released_; 47 48 public: 49 ScratchTagScope(Assembler& masm, const ValueOperand&) 50 : temps_(masm), owned_(true), released_(false) { 51 scratch_ = temps_.Acquire(); 52 } 53 54 operator Register() { 55 MOZ_ASSERT(!released_); 56 return scratch_; 57 } 58 59 void release() { 60 MOZ_ASSERT(!released_); 61 released_ = true; 62 if (owned_) { 63 temps_.Release(scratch_); 64 owned_ = false; 65 } 66 } 67 68 void reacquire() { 69 MOZ_ASSERT(released_); 70 released_ = false; 71 if (!owned_) { 72 scratch_ = temps_.Acquire(); 73 owned_ = true; 74 } 75 } 76 }; 77 78 class ScratchTagScopeRelease { 79 ScratchTagScope* ts_; 80 81 public: 82 explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) { 83 ts_->release(); 84 } 85 ~ScratchTagScopeRelease() { ts_->reacquire(); } 86 }; 87 88 class MacroAssemblerMIPS64 : public MacroAssemblerMIPSShared { 89 public: 90 using MacroAssemblerMIPSShared::ma_b; 91 using MacroAssemblerMIPSShared::ma_cmp_set; 92 using MacroAssemblerMIPSShared::ma_ld; 93 using MacroAssemblerMIPSShared::ma_li; 94 using MacroAssemblerMIPSShared::ma_liPatchable; 95 using MacroAssemblerMIPSShared::ma_load; 96 using MacroAssemblerMIPSShared::ma_ls; 97 using MacroAssemblerMIPSShared::ma_sd; 98 using MacroAssemblerMIPSShared::ma_ss; 99 using MacroAssemblerMIPSShared::ma_store; 100 using MacroAssemblerMIPSShared::ma_sub32TestOverflow; 101 102 void ma_li(Register dest, CodeLabel* label); 103 void ma_li(Register dest, ImmWord imm); 104 void ma_liPatchable(Register dest, ImmPtr imm); 105 void ma_liPatchable(Register dest, ImmWord imm, LiFlags flags = Li48); 106 107 // Negate 108 void ma_dnegu(Register rd, Register rs); 109 110 // Shift operations 111 void ma_dsll(Register rd, Register rt, Imm32 shift); 112 void ma_dsrl(Register rd, Register rt, Imm32 shift); 113 void ma_dsra(Register rd, Register rt, Imm32 shift); 114 void ma_dror(Register rd, Register rt, Imm32 shift); 115 void ma_drol(Register rd, Register rt, Imm32 shift); 116 117 void ma_dsll(Register rd, Register rt, Register shift); 118 void ma_dsrl(Register rd, Register rt, Register shift); 119 void ma_dsra(Register rd, Register rt, Register shift); 120 void ma_dror(Register rd, Register rt, Register shift); 121 void ma_drol(Register rd, Register rt, Register shift); 122 123 void ma_dins(Register rt, Register rs, Imm32 pos, Imm32 size); 124 void ma_dext(Register rt, Register rs, Imm32 pos, Imm32 size); 125 126 // doubleword swap bytes 127 void ma_dsbh(Register rd, Register rt); 128 void ma_dshd(Register rd, Register rt); 129 130 void ma_dctz(Register rd, Register rs); 131 132 // load 133 FaultingCodeOffset ma_load(Register dest, Address address, 134 LoadStoreSize size = SizeWord, 135 LoadStoreExtension extension = SignExtend); 136 137 // store 138 FaultingCodeOffset ma_store(Register data, Address address, 139 LoadStoreSize size = SizeWord, 140 LoadStoreExtension extension = SignExtend); 141 void ma_store(ImmWord imm, const BaseIndex& dest, 142 LoadStoreSize size = SizeWord, 143 LoadStoreExtension extension = SignExtend); 144 void ma_store(ImmWord imm, Address address, LoadStoreSize size = SizeWord, 145 LoadStoreExtension extension = SignExtend); 146 // arithmetic based ops 147 // add 148 void ma_daddu(Register rd, Register rs, Imm32 imm); 149 void ma_daddu(Register rd, Register rs, ImmWord imm); 150 void ma_daddu(Register rd, Register rs); 151 void ma_daddu(Register rd, Imm32 imm); 152 void ma_add32TestOverflow(Register rd, Register rs, Register rt, 153 Label* overflow); 154 void ma_add32TestOverflow(Register rd, Register rs, Imm32 imm, 155 Label* overflow); 156 void ma_addPtrTestOverflow(Register rd, Register rs, Register rt, 157 Label* overflow); 158 void ma_addPtrTestOverflow(Register rd, Register rs, Imm32 imm, 159 Label* overflow); 160 void ma_addPtrTestOverflow(Register rd, Register rs, ImmWord imm, 161 Label* overflow); 162 void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, Register rt, 163 Label* overflow); 164 void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, Imm32 imm, 165 Label* overflow); 166 void ma_addPtrTestCarry(Condition cond, Register rd, Register rs, ImmWord imm, 167 Label* overflow); 168 void ma_addPtrTestSigned(Condition cond, Register rd, Register rj, 169 Register rk, Label* taken); 170 void ma_addPtrTestSigned(Condition cond, Register rd, Register rj, Imm32 imm, 171 Label* taken); 172 void ma_addPtrTestSigned(Condition cond, Register rd, Register rj, 173 ImmWord imm, Label* taken); 174 // subtract 175 void ma_dsubu(Register rd, Register rs, Imm32 imm); 176 void ma_dsubu(Register rd, Register rs, ImmWord imm); 177 void ma_dsubu(Register rd, Register rs); 178 void ma_dsubu(Register rd, Imm32 imm); 179 void ma_sub32TestOverflow(Register rd, Register rs, Register rt, 180 Label* overflow); 181 void ma_subPtrTestOverflow(Register rd, Register rs, Register rt, 182 Label* overflow); 183 void ma_subPtrTestOverflow(Register rd, Register rs, Imm32 imm, 184 Label* overflow); 185 186 // multiplies. For now, there are only few that we care about. 187 void ma_dmulu(Register rd, Register rs, Register rt); 188 void ma_dmulu(Register rd, Register rs, ImmWord imm); 189 void ma_mulPtrTestOverflow(Register rd, Register rs, Register rt, 190 Label* overflow); 191 192 // stack 193 void ma_pop(Register r); 194 void ma_push(Register r); 195 196 void branchWithCode(InstImm code, Label* label, JumpKind jumpKind, 197 Register branchCodeScratch = InvalidReg); 198 // branches when done from within mips-specific code 199 void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, 200 JumpKind jumpKind = LongJump); 201 void ma_b(Register lhs, Address addr, Label* l, Condition c, 202 JumpKind jumpKind = LongJump); 203 void ma_b(Address addr, Imm32 imm, Label* l, Condition c, 204 JumpKind jumpKind = LongJump); 205 void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c, 206 JumpKind jumpKind = LongJump); 207 void ma_b(Address addr, Register rhs, Label* l, Condition c, 208 JumpKind jumpKind = LongJump) { 209 UseScratchRegisterScope temps(*this); 210 Register scratch = temps.Acquire(); 211 MOZ_ASSERT(rhs != scratch); 212 ma_load(scratch, addr, SizeDouble); 213 ma_b(scratch, rhs, l, c, jumpKind); 214 } 215 216 void ma_bal(Label* l, DelaySlotFill delaySlotFill = FillDelaySlot); 217 218 // fp instructions 219 void ma_lid(FloatRegister dest, double value); 220 221 void ma_mv(FloatRegister src, ValueOperand dest); 222 void ma_mv(ValueOperand src, FloatRegister dest); 223 224 FaultingCodeOffset ma_ls(FloatRegister ft, Address address); 225 FaultingCodeOffset ma_ld(FloatRegister ft, Address address); 226 FaultingCodeOffset ma_sd(FloatRegister ft, Address address); 227 FaultingCodeOffset ma_ss(FloatRegister ft, Address address); 228 229 void ma_pop(FloatRegister f); 230 void ma_push(FloatRegister f); 231 232 void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c); 233 void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c); 234 void ma_cmp_set(Register dst, Register lhs, ImmGCPtr imm, Condition c); 235 void ma_cmp_set(Register dst, Address address, Register rhs, Condition c); 236 void ma_cmp_set(Register dst, Address address, ImmWord imm, Condition c); 237 void ma_cmp_set(Register dst, Address address, Imm32 imm, Condition c); 238 239 // These functions abstract the access to high part of the double precision 240 // float register. They are intended to work on both 32 bit and 64 bit 241 // floating point coprocessor. 242 void moveToDoubleHi(Register src, FloatRegister dest) { as_mthc1(src, dest); } 243 void moveFromDoubleHi(FloatRegister src, Register dest) { 244 as_mfhc1(dest, src); 245 } 246 247 void moveToDouble(Register src, FloatRegister dest) { as_dmtc1(src, dest); } 248 void moveFromDouble(FloatRegister src, Register dest) { as_dmfc1(dest, src); } 249 }; 250 251 class MacroAssembler; 252 253 class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 { 254 public: 255 using MacroAssemblerMIPS64::call; 256 257 MacroAssemblerMIPS64Compat() {} 258 259 void convertBoolToInt32(Register source, Register dest); 260 void convertInt32ToDouble(Register src, FloatRegister dest); 261 void convertInt32ToDouble(const Address& src, FloatRegister dest); 262 void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest); 263 void convertUInt32ToDouble(Register src, FloatRegister dest); 264 void convertUInt32ToFloat32(Register src, FloatRegister dest); 265 void convertDoubleToFloat32(FloatRegister src, FloatRegister dest); 266 void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail, 267 bool negativeZeroCheck = true); 268 void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail, 269 bool negativeZeroCheck = true); 270 void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail, 271 bool negativeZeroCheck = true); 272 273 void convertFloat32ToDouble(FloatRegister src, FloatRegister dest); 274 void convertInt32ToFloat32(Register src, FloatRegister dest); 275 void convertInt32ToFloat32(const Address& src, FloatRegister dest); 276 277 void convertDoubleToFloat16(FloatRegister src, FloatRegister dest) { 278 MOZ_CRASH("Not supported for this target"); 279 } 280 void convertFloat16ToDouble(FloatRegister src, FloatRegister dest) { 281 MOZ_CRASH("Not supported for this target"); 282 } 283 void convertFloat32ToFloat16(FloatRegister src, FloatRegister dest) { 284 MOZ_CRASH("Not supported for this target"); 285 } 286 void convertFloat16ToFloat32(FloatRegister src, FloatRegister dest) { 287 MOZ_CRASH("Not supported for this target"); 288 } 289 void convertInt32ToFloat16(Register src, FloatRegister dest) { 290 MOZ_CRASH("Not supported for this target"); 291 } 292 293 void computeScaledAddress(const BaseIndex& address, Register dest); 294 void computeScaledAddress32(const BaseIndex& address, Register dest); 295 296 void computeEffectiveAddress(const Address& address, Register dest) { 297 ma_daddu(dest, address.base, Imm32(address.offset)); 298 } 299 300 void computeEffectiveAddress(const BaseIndex& address, Register dest); 301 302 void computeEffectiveAddress32(const Address& address, Register dest) { 303 ma_addu(dest, address.base, Imm32(address.offset)); 304 } 305 306 void computeEffectiveAddress32(const BaseIndex& address, Register dest) { 307 computeScaledAddress32(address, dest); 308 if (address.offset) { 309 ma_addu(dest, dest, Imm32(address.offset)); 310 } 311 } 312 313 void j(Label* dest) { ma_b(dest); } 314 315 void mov(Register src, Register dest) { as_ori(dest, src, 0); } 316 void mov(ImmWord imm, Register dest) { ma_li(dest, imm); } 317 void mov(ImmPtr imm, Register dest) { 318 mov(ImmWord(uintptr_t(imm.value)), dest); 319 } 320 void mov(CodeLabel* label, Register dest) { ma_li(dest, label); } 321 void mov(Register src, Address dest) { MOZ_CRASH("NYI-IC"); } 322 void mov(Address src, Register dest) { MOZ_CRASH("NYI-IC"); } 323 324 void writeDataRelocation(const Value& val) { 325 MOZ_ASSERT(val.isGCThing(), "only called for gc-things"); 326 327 // Raw GC pointer relocations and Value relocations both end up in 328 // TraceOneDataRelocation. 329 gc::Cell* cell = val.toGCThing(); 330 if (cell && gc::IsInsideNursery(cell)) { 331 embedsNurseryPointers_ = true; 332 } 333 dataRelocations_.writeUnsigned(currentOffset()); 334 } 335 336 void branch(JitCode* c) { 337 UseScratchRegisterScope temps(*this); 338 BufferOffset bo = m_buffer.nextOffset(); 339 addPendingJump(bo, ImmPtr(c->raw()), RelocationKind::JITCODE); 340 Register scratch = temps.Acquire(); 341 ma_liPatchable(scratch, ImmPtr(c->raw())); 342 as_jr(scratch); 343 as_nop(); 344 } 345 void branch(const Register reg) { 346 as_jr(reg); 347 as_nop(); 348 } 349 void nop() { as_nop(); } 350 BufferOffset ret() { 351 ma_pop(ra); 352 BufferOffset offset = as_jr(ra); 353 as_nop(); 354 return offset; 355 } 356 inline void retn(Imm32 n); 357 void push(Imm32 imm) { 358 UseScratchRegisterScope temps(*this); 359 Register scratch = temps.Acquire(); 360 ma_li(scratch, imm); 361 ma_push(scratch); 362 } 363 void push(ImmWord imm) { 364 UseScratchRegisterScope temps(*this); 365 Register scratch = temps.Acquire(); 366 ma_li(scratch, imm); 367 ma_push(scratch); 368 } 369 void push(ImmGCPtr imm) { 370 UseScratchRegisterScope temps(*this); 371 Register scratch = temps.Acquire(); 372 ma_li(scratch, imm); 373 ma_push(scratch); 374 } 375 void push(const Address& address) { 376 UseScratchRegisterScope temps(*this); 377 Register scratch = temps.Acquire(); 378 loadPtr(address, scratch); 379 ma_push(scratch); 380 } 381 void push(Register reg) { ma_push(reg); } 382 void push(FloatRegister reg) { ma_push(reg); } 383 void pop(Register reg) { ma_pop(reg); } 384 void pop(FloatRegister reg) { ma_pop(reg); } 385 386 // Emit a branch that can be toggled to a non-operation. On MIPS64 we use 387 // "andi" instruction to toggle the branch. 388 // See ToggleToJmp(), ToggleToCmp(). 389 CodeOffset toggledJump(Label* label); 390 391 // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch 392 // this instruction. 393 CodeOffset toggledCall(JitCode* target, bool enabled); 394 395 static size_t ToggledCallSize(uint8_t* code) { 396 // Six instructions used in: MacroAssemblerMIPS64Compat::toggledCall 397 return 6 * sizeof(uint32_t); 398 } 399 400 CodeOffset pushWithPatch(ImmWord imm) { 401 UseScratchRegisterScope temps(*this); 402 Register scratch = temps.Acquire(); 403 CodeOffset offset = movWithPatch(imm, scratch); 404 ma_push(scratch); 405 return offset; 406 } 407 408 CodeOffset movWithPatch(ImmWord imm, Register dest) { 409 CodeOffset offset = CodeOffset(currentOffset()); 410 ma_liPatchable(dest, imm, Li64); 411 return offset; 412 } 413 CodeOffset movWithPatch(ImmPtr imm, Register dest) { 414 CodeOffset offset = CodeOffset(currentOffset()); 415 ma_liPatchable(dest, imm); 416 return offset; 417 } 418 419 void writeCodePointer(CodeLabel* label) { 420 label->patchAt()->bind(currentOffset()); 421 label->setLinkMode(CodeLabel::RawPointer); 422 m_buffer.ensureSpace(sizeof(void*)); 423 writeInst(-1); 424 writeInst(-1); 425 } 426 427 void jump(Label* label) { ma_b(label); } 428 void jump(Register reg) { 429 as_jr(reg); 430 as_nop(); 431 } 432 void jump(const Address& address) { 433 UseScratchRegisterScope temps(*this); 434 Register scratch = temps.Acquire(); 435 loadPtr(address, scratch); 436 as_jr(scratch); 437 as_nop(); 438 } 439 440 void jump(JitCode* code) { branch(code); } 441 442 void jump(ImmPtr ptr) { 443 BufferOffset bo = m_buffer.nextOffset(); 444 addPendingJump(bo, ptr, RelocationKind::HARDCODED); 445 ma_jump(ptr); 446 } 447 448 void jump(TrampolinePtr code) { jump(ImmPtr(code.value)); } 449 450 void splitTag(Register src, Register dest) { 451 ma_dsrl(dest, src, Imm32(JSVAL_TAG_SHIFT)); 452 } 453 454 void splitTag(const ValueOperand& operand, Register dest) { 455 splitTag(operand.valueReg(), dest); 456 } 457 458 void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { 459 splitTag(value, tag); 460 } 461 462 // unboxing code 463 void unboxNonDouble(const ValueOperand& operand, Register dest, 464 JSValueType type) { 465 unboxNonDouble(operand.valueReg(), dest, type); 466 } 467 468 template <typename T> 469 void unboxNonDouble(T src, Register dest, JSValueType type) { 470 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 471 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 472 load32(src, dest); 473 return; 474 } 475 loadPtr(src, dest); 476 unboxNonDouble(dest, dest, type); 477 } 478 479 void unboxNonDouble(Register src, Register dest, JSValueType type) { 480 UseScratchRegisterScope temps(*this); 481 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 482 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 483 ma_sll(dest, src, Imm32(0)); 484 return; 485 } 486 Register scratch = temps.Acquire(); 487 MOZ_ASSERT(scratch != src); 488 mov(ImmShiftedTag(type), scratch); 489 as_xor(dest, src, scratch); 490 } 491 492 void unboxGCThingForGCBarrier(const Address& src, Register dest) { 493 loadPtr(src, dest); 494 ma_dext(dest, dest, Imm32(0), Imm32(JSVAL_TAG_SHIFT)); 495 } 496 void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { 497 ma_dext(dest, src.valueReg(), Imm32(0), Imm32(JSVAL_TAG_SHIFT)); 498 } 499 500 void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) { 501 UseScratchRegisterScope temps(*this); 502 Register scratch = temps.Acquire(); 503 MOZ_ASSERT(scratch != dest); 504 movePtr(ImmWord(wasm::AnyRef::GCThingMask), scratch); 505 loadPtr(src, dest); 506 as_and(dest, dest, scratch); 507 } 508 509 // Like unboxGCThingForGCBarrier, but loads the GC thing's chunk base. 510 void getGCThingValueChunk(const Address& src, Register dest) { 511 UseScratchRegisterScope temps(*this); 512 Register scratch = temps.Acquire(); 513 MOZ_ASSERT(scratch != dest); 514 loadPtr(src, dest); 515 movePtr(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), scratch); 516 as_and(dest, dest, scratch); 517 } 518 void getGCThingValueChunk(const ValueOperand& src, Register dest) { 519 MOZ_ASSERT(src.valueReg() != dest); 520 movePtr(ImmWord(JS::detail::ValueGCThingPayloadChunkMask), dest); 521 as_and(dest, dest, src.valueReg()); 522 } 523 524 void getWasmAnyRefGCThingChunk(Register src, Register dest) { 525 MOZ_ASSERT(src != dest); 526 movePtr(ImmWord(wasm::AnyRef::GCThingChunkMask), dest); 527 as_and(dest, dest, src); 528 } 529 530 void unboxInt32(const ValueOperand& operand, Register dest); 531 void unboxInt32(Register src, Register dest); 532 void unboxInt32(const Address& src, Register dest); 533 void unboxInt32(const BaseIndex& src, Register dest); 534 void unboxBoolean(const ValueOperand& operand, Register dest); 535 void unboxBoolean(Register src, Register dest); 536 void unboxBoolean(const Address& src, Register dest); 537 void unboxBoolean(const BaseIndex& src, Register dest); 538 void unboxDouble(const ValueOperand& operand, FloatRegister dest); 539 void unboxDouble(Register src, Register dest); 540 void unboxDouble(const Address& src, FloatRegister dest); 541 void unboxDouble(const BaseIndex& src, FloatRegister dest); 542 void unboxString(const ValueOperand& operand, Register dest); 543 void unboxString(Register src, Register dest); 544 void unboxString(const Address& src, Register dest); 545 void unboxSymbol(const ValueOperand& src, Register dest); 546 void unboxSymbol(Register src, Register dest); 547 void unboxSymbol(const Address& src, Register dest); 548 void unboxBigInt(const ValueOperand& operand, Register dest); 549 void unboxBigInt(Register src, Register dest); 550 void unboxBigInt(const Address& src, Register dest); 551 void unboxObject(const ValueOperand& src, Register dest); 552 void unboxObject(Register src, Register dest); 553 void unboxObject(const Address& src, Register dest); 554 void unboxObject(const BaseIndex& src, Register dest) { 555 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 556 } 557 void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type); 558 559 void notBoolean(const ValueOperand& val) { 560 as_xori(val.valueReg(), val.valueReg(), 1); 561 } 562 563 // boxing code 564 void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister); 565 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) { 566 boxValue(type, src, dest.valueReg()); 567 } 568 void boxNonDouble(Register type, Register src, const ValueOperand& dest) { 569 boxValue(type, src, dest.valueReg()); 570 } 571 572 // Extended unboxing API. If the payload is already in a register, returns 573 // that register. Otherwise, provides a move to the given scratch register, 574 // and returns that. 575 [[nodiscard]] Register extractObject(const Address& address, 576 Register scratch); 577 [[nodiscard]] Register extractObject(const ValueOperand& value, 578 Register scratch) { 579 unboxObject(value, scratch); 580 return scratch; 581 } 582 [[nodiscard]] Register extractString(const ValueOperand& value, 583 Register scratch) { 584 unboxString(value, scratch); 585 return scratch; 586 } 587 [[nodiscard]] Register extractSymbol(const ValueOperand& value, 588 Register scratch) { 589 unboxSymbol(value, scratch); 590 return scratch; 591 } 592 [[nodiscard]] Register extractInt32(const ValueOperand& value, 593 Register scratch) { 594 unboxInt32(value, scratch); 595 return scratch; 596 } 597 [[nodiscard]] Register extractBoolean(const ValueOperand& value, 598 Register scratch) { 599 unboxBoolean(value, scratch); 600 return scratch; 601 } 602 [[nodiscard]] Register extractTag(const Address& address, Register scratch); 603 [[nodiscard]] Register extractTag(const BaseIndex& address, Register scratch); 604 [[nodiscard]] Register extractTag(const ValueOperand& value, 605 Register scratch) { 606 splitTag(value, scratch); 607 return scratch; 608 } 609 610 void loadInt32OrDouble(const Address& src, FloatRegister dest); 611 void loadInt32OrDouble(const BaseIndex& addr, FloatRegister dest); 612 void loadConstantDouble(double dp, FloatRegister dest); 613 void loadConstantFloat32(float f, FloatRegister dest); 614 615 void testNullSet(Condition cond, const ValueOperand& value, Register dest); 616 617 void testObjectSet(Condition cond, const ValueOperand& value, Register dest); 618 619 void testUndefinedSet(Condition cond, const ValueOperand& value, 620 Register dest); 621 622 template <typename T> 623 void loadUnboxedValue(const T& address, MIRType type, AnyRegister dest) { 624 if (dest.isFloat()) { 625 loadInt32OrDouble(address, dest.fpu()); 626 } else { 627 unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type)); 628 } 629 } 630 631 void boxValue(JSValueType type, Register src, Register dest); 632 void boxValue(Register type, Register src, Register dest); 633 634 void storeValue(ValueOperand val, Operand dst); 635 void storeValue(ValueOperand val, const BaseIndex& dest); 636 void storeValue(JSValueType type, Register reg, BaseIndex dest); 637 void storeValue(ValueOperand val, const Address& dest); 638 void storeValue(JSValueType type, Register reg, Address dest); 639 void storeValue(const Value& val, Address dest); 640 void storeValue(const Value& val, BaseIndex dest); 641 void storeValue(const Address& src, const Address& dest, Register temp) { 642 loadPtr(src, temp); 643 storePtr(temp, dest); 644 } 645 646 void storePrivateValue(Register src, const Address& dest) { 647 storePtr(src, dest); 648 } 649 void storePrivateValue(ImmGCPtr imm, const Address& dest) { 650 storePtr(imm, dest); 651 } 652 653 void loadValue(Address src, ValueOperand val); 654 void loadValue(Operand dest, ValueOperand val) { 655 loadValue(dest.toAddress(), val); 656 } 657 void loadValue(const BaseIndex& addr, ValueOperand val); 658 659 void loadUnalignedValue(const Address& src, ValueOperand dest) { 660 loadValue(src, dest); 661 } 662 663 void tagValue(JSValueType type, Register payload, ValueOperand dest); 664 665 void pushValue(ValueOperand val); 666 void popValue(ValueOperand val); 667 void pushValue(const Value& val) { 668 if (val.isGCThing()) { 669 UseScratchRegisterScope temps(*this); 670 writeDataRelocation(val); 671 Register scratch = temps.Acquire(); 672 movWithPatch(ImmWord(val.asRawBits()), scratch); 673 push(scratch); 674 } else { 675 push(ImmWord(val.asRawBits())); 676 } 677 } 678 void pushValue(JSValueType type, Register reg) { 679 UseScratchRegisterScope temps(*this); 680 Register scratch = temps.Acquire(); 681 boxValue(type, reg, scratch); 682 push(scratch); 683 } 684 void pushValue(const Address& addr); 685 void pushValue(const BaseIndex& addr, Register scratch) { 686 loadValue(addr, ValueOperand(scratch)); 687 pushValue(ValueOperand(scratch)); 688 } 689 690 void handleFailureWithHandlerTail(Label* profilerExitTail, Label* bailoutTail, 691 uint32_t* returnValueCheckOffset); 692 693 ///////////////////////////////////////////////////////////////// 694 // Common interface. 695 ///////////////////////////////////////////////////////////////// 696 public: 697 // The following functions are exposed for use in platform-shared code. 698 699 inline void incrementInt32Value(const Address& addr); 700 701 void move32(Imm32 imm, Register dest); 702 void move32(Register src, Register dest); 703 704 void movePtr(Register src, Register dest); 705 void movePtr(ImmWord imm, Register dest); 706 void movePtr(ImmPtr imm, Register dest); 707 void movePtr(wasm::SymbolicAddress imm, Register dest); 708 void movePtr(ImmGCPtr imm, Register dest); 709 710 FaultingCodeOffset load8SignExtend(const Address& address, Register dest); 711 FaultingCodeOffset load8SignExtend(const BaseIndex& src, Register dest); 712 713 FaultingCodeOffset load8ZeroExtend(const Address& address, Register dest); 714 FaultingCodeOffset load8ZeroExtend(const BaseIndex& src, Register dest); 715 716 FaultingCodeOffset load16SignExtend(const Address& address, Register dest); 717 FaultingCodeOffset load16SignExtend(const BaseIndex& src, Register dest); 718 719 template <typename S> 720 void load16UnalignedSignExtend(const S& src, Register dest) { 721 ma_load_unaligned(dest, src, SizeHalfWord, SignExtend); 722 } 723 724 FaultingCodeOffset load16ZeroExtend(const Address& address, Register dest); 725 FaultingCodeOffset load16ZeroExtend(const BaseIndex& src, Register dest); 726 727 template <typename S> 728 void load16UnalignedZeroExtend(const S& src, Register dest) { 729 ma_load_unaligned(dest, src, SizeHalfWord, ZeroExtend); 730 } 731 732 FaultingCodeOffset load32(const Address& address, Register dest); 733 FaultingCodeOffset load32(const BaseIndex& address, Register dest); 734 void load32(AbsoluteAddress address, Register dest); 735 void load32(wasm::SymbolicAddress address, Register dest); 736 737 template <typename S> 738 void load32Unaligned(const S& src, Register dest) { 739 ma_load_unaligned(dest, src, SizeWord, SignExtend); 740 } 741 742 FaultingCodeOffset load64(const Address& address, Register64 dest) { 743 return loadPtr(address, dest.reg); 744 } 745 FaultingCodeOffset load64(const BaseIndex& address, Register64 dest) { 746 return loadPtr(address, dest.reg); 747 } 748 749 template <typename S> 750 void load64Unaligned(const S& src, Register64 dest) { 751 ma_load_unaligned(dest.reg, src, SizeDouble, ZeroExtend); 752 } 753 754 FaultingCodeOffset loadPtr(const Address& address, Register dest); 755 FaultingCodeOffset loadPtr(const BaseIndex& src, Register dest); 756 void loadPtr(AbsoluteAddress address, Register dest); 757 void loadPtr(wasm::SymbolicAddress address, Register dest); 758 759 void loadPrivate(const Address& address, Register dest); 760 761 void loadUnalignedDouble(const wasm::MemoryAccessDesc& access, 762 const BaseIndex& src, Register temp, 763 FloatRegister dest); 764 void loadUnalignedFloat32(const wasm::MemoryAccessDesc& access, 765 const BaseIndex& src, Register temp, 766 FloatRegister dest); 767 768 FaultingCodeOffset store8(Register src, const Address& address); 769 FaultingCodeOffset store8(Register src, const BaseIndex& address); 770 void store8(Imm32 imm, const Address& address); 771 void store8(Imm32 imm, const BaseIndex& address); 772 773 FaultingCodeOffset store16(Register src, const Address& address); 774 FaultingCodeOffset store16(Register src, const BaseIndex& address); 775 void store16(Imm32 imm, const Address& address); 776 void store16(Imm32 imm, const BaseIndex& address); 777 778 template <typename T> 779 void store16Unaligned(Register src, const T& dest) { 780 ma_store_unaligned(src, dest, SizeHalfWord); 781 } 782 783 FaultingCodeOffset store32(Register src, const Address& address); 784 FaultingCodeOffset store32(Register src, const BaseIndex& address); 785 void store32(Register src, AbsoluteAddress address); 786 void store32(Imm32 src, const Address& address); 787 void store32(Imm32 src, const BaseIndex& address); 788 789 template <typename T> 790 void store32Unaligned(Register src, const T& dest) { 791 ma_store_unaligned(src, dest, SizeWord); 792 } 793 794 void store64(Imm64 imm, Address address) { 795 storePtr(ImmWord(imm.value), address); 796 } 797 void store64(Imm64 imm, const BaseIndex& address) { 798 storePtr(ImmWord(imm.value), address); 799 } 800 801 FaultingCodeOffset store64(Register64 src, Address address) { 802 return storePtr(src.reg, address); 803 } 804 FaultingCodeOffset store64(Register64 src, const BaseIndex& address) { 805 return storePtr(src.reg, address); 806 } 807 808 template <typename T> 809 void store64Unaligned(Register64 src, const T& dest) { 810 ma_store_unaligned(src.reg, dest, SizeDouble); 811 } 812 813 template <typename T> 814 void storePtr(ImmWord imm, T address); 815 template <typename T> 816 void storePtr(ImmPtr imm, T address); 817 template <typename T> 818 void storePtr(ImmGCPtr imm, T address); 819 FaultingCodeOffset storePtr(Register src, const Address& address); 820 FaultingCodeOffset storePtr(Register src, const BaseIndex& address); 821 void storePtr(Register src, AbsoluteAddress dest); 822 823 void storeUnalignedFloat32(const wasm::MemoryAccessDesc& access, 824 FloatRegister src, Register temp, 825 const BaseIndex& dest); 826 void storeUnalignedDouble(const wasm::MemoryAccessDesc& access, 827 FloatRegister src, Register temp, 828 const BaseIndex& dest); 829 830 void moveDouble(FloatRegister src, FloatRegister dest) { as_movd(dest, src); } 831 832 void zeroDouble(FloatRegister reg) { moveToDouble(zero, reg); } 833 834 void convertUInt64ToDouble(Register src, FloatRegister dest); 835 836 void breakpoint(); 837 838 void checkStackAlignment(); 839 840 static void calculateAlignedStackPointer(void** stackPointer); 841 842 void cmpPtrSet(Assembler::Condition cond, Address lhs, ImmPtr rhs, 843 Register dest); 844 void cmpPtrSet(Assembler::Condition cond, Register lhs, Address rhs, 845 Register dest); 846 void cmpPtrSet(Assembler::Condition cond, Address lhs, Register rhs, 847 Register dest); 848 849 void cmp32Set(Assembler::Condition cond, Register lhs, Address rhs, 850 Register dest); 851 852 protected: 853 bool buildOOLFakeExitFrame(void* fakeReturnAddr); 854 855 void wasmLoadI64Impl(const wasm::MemoryAccessDesc& access, 856 Register memoryBase, Register ptr, Register ptrScratch, 857 Register64 output, Register tmp); 858 void wasmStoreI64Impl(const wasm::MemoryAccessDesc& access, Register64 value, 859 Register memoryBase, Register ptr, Register ptrScratch, 860 Register tmp); 861 862 public: 863 void lea(Operand addr, Register dest) { 864 ma_daddu(dest, addr.baseReg(), Imm32(addr.disp())); 865 } 866 867 void abiret() { 868 as_jr(ra); 869 as_nop(); 870 } 871 872 void moveFloat32(FloatRegister src, FloatRegister dest) { 873 as_movs(dest, src); 874 } 875 876 // Instrumentation for entering and leaving the profiler. 877 void profilerEnterFrame(Register framePtr, Register scratch); 878 void profilerExitFrame(); 879 }; 880 881 typedef MacroAssemblerMIPS64Compat MacroAssemblerSpecific; 882 883 } // namespace jit 884 } // namespace js 885 886 #endif /* jit_mips64_MacroAssembler_mips64_h */