1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 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_mips32_MacroAssembler_mips32_h 8 #define jit_mips32_MacroAssembler_mips32_h 9 10 #include "mozilla/EndianUtils.h" 11 12 #include "jit/JitFrames.h" 13 #include "jit/mips-shared/MacroAssembler-mips-shared.h" 14 #include "jit/MoveResolver.h" 15 #include "vm/BytecodeUtil.h" 16 17 namespace js { 18 namespace jit { 19 20 struct ImmTag : public Imm32 { ImmTagImmTag21 ImmTag(JSValueTag mask) : Imm32(int32_t(mask)) {} 22 }; 23 24 struct ImmType : public ImmTag { ImmTypeImmType25 ImmType(JSValueType type) : ImmTag(JSVAL_TYPE_TO_TAG(type)) {} 26 }; 27 28 static constexpr ValueOperand JSReturnOperand{JSReturnReg_Type, 29 JSReturnReg_Data}; 30 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0); 31 32 static const int defaultShift = 3; 33 static_assert(1 << defaultShift == sizeof(JS::Value), 34 "The defaultShift is wrong"); 35 36 static const uint32_t LOW_32_MASK = (1LL << 32) - 1; 37 #if MOZ_LITTLE_ENDIAN 38 static const int32_t LOW_32_OFFSET = 0; 39 static const int32_t HIGH_32_OFFSET = 4; 40 #else 41 static const int32_t LOW_32_OFFSET = 4; 42 static const int32_t HIGH_32_OFFSET = 0; 43 #endif 44 45 // See documentation for ScratchTagScope and ScratchTagScopeRelease in 46 // MacroAssembler-x64.h. 47 48 class ScratchTagScope { 49 const ValueOperand& v_; 50 51 public: ScratchTagScope(MacroAssembler &,const ValueOperand & v)52 ScratchTagScope(MacroAssembler&, const ValueOperand& v) : v_(v) {} Register()53 operator Register() { return v_.typeReg(); } release()54 void release() {} reacquire()55 void reacquire() {} 56 }; 57 58 class ScratchTagScopeRelease { 59 public: ScratchTagScopeRelease(ScratchTagScope *)60 explicit ScratchTagScopeRelease(ScratchTagScope*) {} 61 }; 62 63 class MacroAssemblerMIPS : public MacroAssemblerMIPSShared { 64 public: 65 using MacroAssemblerMIPSShared::ma_b; 66 using MacroAssemblerMIPSShared::ma_cmp_set; 67 using MacroAssemblerMIPSShared::ma_ld; 68 using MacroAssemblerMIPSShared::ma_li; 69 using MacroAssemblerMIPSShared::ma_liPatchable; 70 using MacroAssemblerMIPSShared::ma_load; 71 using MacroAssemblerMIPSShared::ma_ls; 72 using MacroAssemblerMIPSShared::ma_sd; 73 using MacroAssemblerMIPSShared::ma_ss; 74 using MacroAssemblerMIPSShared::ma_store; 75 using MacroAssemblerMIPSShared::ma_subTestOverflow; 76 77 void ma_li(Register dest, CodeLabel* label); 78 79 void ma_li(Register dest, ImmWord imm); 80 void ma_liPatchable(Register dest, ImmPtr imm); 81 void ma_liPatchable(Register dest, ImmWord imm); 82 83 // load 84 void ma_load(Register dest, Address address, LoadStoreSize size = SizeWord, 85 LoadStoreExtension extension = SignExtend); 86 87 // store 88 void ma_store(Register data, Address address, LoadStoreSize size = SizeWord, 89 LoadStoreExtension extension = SignExtend); 90 91 // arithmetic based ops 92 // add 93 template <typename L> 94 void ma_addTestOverflow(Register rd, Register rs, Register rt, L overflow); 95 template <typename L> 96 void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, L overflow); 97 98 // subtract 99 void ma_subTestOverflow(Register rd, Register rs, Register rt, 100 Label* overflow); 101 102 // memory 103 // shortcut for when we know we're transferring 32 bits of data 104 void ma_lw(Register data, Address address); 105 106 void ma_sw(Register data, Address address); 107 void ma_sw(Imm32 imm, Address address); 108 void ma_sw(Register data, BaseIndex& address); 109 110 void ma_pop(Register r); 111 void ma_push(Register r); 112 113 void branchWithCode(InstImm code, Label* label, JumpKind jumpKind); 114 // branches when done from within mips-specific code 115 void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, 116 JumpKind jumpKind = LongJump) { 117 ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind); 118 } 119 void ma_b(Address addr, ImmWord imm, Label* l, Condition c, 120 JumpKind jumpKind = LongJump) { 121 ma_b(addr, Imm32(uint32_t(imm.value)), l, c, jumpKind); 122 } 123 124 void ma_b(Register lhs, Address addr, Label* l, Condition c, 125 JumpKind jumpKind = LongJump); 126 void ma_b(Address addr, Imm32 imm, Label* l, Condition c, 127 JumpKind jumpKind = LongJump); 128 void ma_b(Address addr, ImmGCPtr imm, Label* l, Condition c, 129 JumpKind jumpKind = LongJump); 130 void ma_b(Address addr, Register rhs, Label* l, Condition c, 131 JumpKind jumpKind = LongJump) { 132 MOZ_ASSERT(rhs != ScratchRegister); 133 ma_lw(ScratchRegister, addr); 134 ma_b(ScratchRegister, rhs, l, c, jumpKind); 135 } 136 137 void ma_bal(Label* l, DelaySlotFill delaySlotFill = FillDelaySlot); 138 139 // fp instructions 140 void ma_lid(FloatRegister dest, double value); 141 142 void ma_mv(FloatRegister src, ValueOperand dest); 143 void ma_mv(ValueOperand src, FloatRegister dest); 144 145 void ma_ls(FloatRegister ft, Address address); 146 void ma_ld(FloatRegister ft, Address address); 147 void ma_sd(FloatRegister ft, Address address); 148 void ma_ss(FloatRegister ft, Address address); 149 150 void ma_ldc1WordAligned(FloatRegister ft, Register base, int32_t off); 151 void ma_sdc1WordAligned(FloatRegister ft, Register base, int32_t off); 152 153 void ma_pop(FloatRegister f); 154 void ma_push(FloatRegister f); 155 ma_cmp_set(Register dst,Register lhs,ImmPtr imm,Condition c)156 void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) { 157 ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c); 158 } ma_cmp_set(Register dst,Register lhs,Address addr,Condition c)159 void ma_cmp_set(Register dst, Register lhs, Address addr, Condition c) { 160 MOZ_ASSERT(lhs != ScratchRegister); 161 ma_lw(ScratchRegister, addr); 162 ma_cmp_set(dst, lhs, ScratchRegister, c); 163 } ma_cmp_set(Register dst,Address lhs,Register rhs,Condition c)164 void ma_cmp_set(Register dst, Address lhs, Register rhs, Condition c) { 165 MOZ_ASSERT(rhs != ScratchRegister); 166 ma_lw(ScratchRegister, lhs); 167 ma_cmp_set(dst, ScratchRegister, rhs, c); 168 } ma_cmp_set(Register dst,Address lhs,ImmPtr imm,Condition c)169 void ma_cmp_set(Register dst, Address lhs, ImmPtr imm, Condition c) { 170 ma_lw(SecondScratchReg, lhs); 171 ma_cmp_set(dst, SecondScratchReg, imm, c); 172 } 173 174 // These fuctions abstract the access to high part of the double precision 175 // float register. It is intended to work on both 32 bit and 64 bit 176 // floating point coprocessor. 177 // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1 moveToDoubleHi(Register src,FloatRegister dest)178 void moveToDoubleHi(Register src, FloatRegister dest) { 179 as_mtc1(src, getOddPair(dest)); 180 } moveFromDoubleHi(FloatRegister src,Register dest)181 void moveFromDoubleHi(FloatRegister src, Register dest) { 182 as_mfc1(dest, getOddPair(src)); 183 } 184 }; 185 186 class MacroAssembler; 187 188 class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS { 189 public: 190 using MacroAssemblerMIPS::call; 191 MacroAssemblerMIPSCompat()192 MacroAssemblerMIPSCompat() {} 193 194 void convertBoolToInt32(Register source, Register dest); 195 void convertInt32ToDouble(Register src, FloatRegister dest); 196 void convertInt32ToDouble(const Address& src, FloatRegister dest); 197 void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest); 198 void convertUInt32ToDouble(Register src, FloatRegister dest); 199 void convertUInt32ToFloat32(Register src, FloatRegister dest); 200 void convertDoubleToFloat32(FloatRegister src, FloatRegister dest); 201 void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail, 202 bool negativeZeroCheck = true); 203 void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail, 204 bool negativeZeroCheck = true); 205 206 void convertFloat32ToDouble(FloatRegister src, FloatRegister dest); 207 void convertInt32ToFloat32(Register src, FloatRegister dest); 208 void convertInt32ToFloat32(const Address& src, FloatRegister dest); 209 210 void computeScaledAddress(const BaseIndex& address, Register dest); 211 computeEffectiveAddress(const Address & address,Register dest)212 void computeEffectiveAddress(const Address& address, Register dest) { 213 ma_addu(dest, address.base, Imm32(address.offset)); 214 } 215 216 inline void computeEffectiveAddress(const BaseIndex& address, Register dest); 217 j(Label * dest)218 void j(Label* dest) { ma_b(dest); } 219 mov(Register src,Register dest)220 void mov(Register src, Register dest) { as_ori(dest, src, 0); } mov(ImmWord imm,Register dest)221 void mov(ImmWord imm, Register dest) { ma_li(dest, imm); } mov(ImmPtr imm,Register dest)222 void mov(ImmPtr imm, Register dest) { 223 mov(ImmWord(uintptr_t(imm.value)), dest); 224 } mov(CodeLabel * label,Register dest)225 void mov(CodeLabel* label, Register dest) { ma_li(dest, label); } mov(Register src,Address dest)226 void mov(Register src, Address dest) { MOZ_CRASH("NYI-IC"); } mov(Address src,Register dest)227 void mov(Address src, Register dest) { MOZ_CRASH("NYI-IC"); } 228 branch(JitCode * c)229 void branch(JitCode* c) { 230 BufferOffset bo = m_buffer.nextOffset(); 231 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); 232 ma_liPatchable(ScratchRegister, ImmPtr(c->raw())); 233 as_jr(ScratchRegister); 234 as_nop(); 235 } branch(const Register reg)236 void branch(const Register reg) { 237 as_jr(reg); 238 as_nop(); 239 } nop()240 void nop() { as_nop(); } ret()241 void ret() { 242 ma_pop(ra); 243 as_jr(ra); 244 as_nop(); 245 } 246 inline void retn(Imm32 n); push(Imm32 imm)247 void push(Imm32 imm) { 248 ma_li(ScratchRegister, imm); 249 ma_push(ScratchRegister); 250 } push(ImmWord imm)251 void push(ImmWord imm) { 252 ma_li(ScratchRegister, imm); 253 ma_push(ScratchRegister); 254 } push(ImmGCPtr imm)255 void push(ImmGCPtr imm) { 256 ma_li(ScratchRegister, imm); 257 ma_push(ScratchRegister); 258 } push(const Address & address)259 void push(const Address& address) { 260 loadPtr(address, ScratchRegister); 261 ma_push(ScratchRegister); 262 } push(Register reg)263 void push(Register reg) { ma_push(reg); } push(FloatRegister reg)264 void push(FloatRegister reg) { ma_push(reg); } pop(Register reg)265 void pop(Register reg) { ma_pop(reg); } pop(FloatRegister reg)266 void pop(FloatRegister reg) { ma_pop(reg); } 267 268 // Emit a branch that can be toggled to a non-operation. On MIPS we use 269 // "andi" instruction to toggle the branch. 270 // See ToggleToJmp(), ToggleToCmp(). 271 CodeOffset toggledJump(Label* label); 272 273 // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch 274 // this instruction. 275 CodeOffset toggledCall(JitCode* target, bool enabled); 276 ToggledCallSize(uint8_t * code)277 static size_t ToggledCallSize(uint8_t* code) { 278 // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall 279 return 4 * sizeof(uint32_t); 280 } 281 pushWithPatch(ImmWord imm)282 CodeOffset pushWithPatch(ImmWord imm) { 283 CodeOffset label = movWithPatch(imm, ScratchRegister); 284 ma_push(ScratchRegister); 285 return label; 286 } 287 movWithPatch(ImmWord imm,Register dest)288 CodeOffset movWithPatch(ImmWord imm, Register dest) { 289 CodeOffset label = CodeOffset(currentOffset()); 290 ma_liPatchable(dest, imm); 291 return label; 292 } movWithPatch(ImmPtr imm,Register dest)293 CodeOffset movWithPatch(ImmPtr imm, Register dest) { 294 return movWithPatch(ImmWord(uintptr_t(imm.value)), dest); 295 } 296 writeCodePointer(CodeLabel * label)297 void writeCodePointer(CodeLabel* label) { 298 BufferOffset off = writeInst(-1); 299 label->patchAt()->bind(off.getOffset()); 300 label->setLinkMode(CodeLabel::RawPointer); 301 } 302 jump(Label * label)303 void jump(Label* label) { ma_b(label); } jump(Register reg)304 void jump(Register reg) { 305 as_jr(reg); 306 as_nop(); 307 } jump(const Address & address)308 void jump(const Address& address) { 309 loadPtr(address, ScratchRegister); 310 as_jr(ScratchRegister); 311 as_nop(); 312 } 313 jump(JitCode * code)314 void jump(JitCode* code) { branch(code); } 315 jump(wasm::OldTrapDesc target)316 void jump(wasm::OldTrapDesc target) { ma_b(target); } 317 jump(TrampolinePtr code)318 void jump(TrampolinePtr code) { 319 auto target = ImmPtr(code.value); 320 BufferOffset bo = m_buffer.nextOffset(); 321 addPendingJump(bo, target, Relocation::HARDCODED); 322 ma_jump(target); 323 } 324 negl(Register reg)325 void negl(Register reg) { ma_negu(reg, reg); } 326 splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)327 void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { 328 MOZ_ASSERT(value.typeReg() == tag); 329 } 330 331 // unboxing code 332 void unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType); 333 void unboxNonDouble(const Address& src, Register dest, JSValueType); 334 void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType); 335 void unboxInt32(const ValueOperand& operand, Register dest); 336 void unboxInt32(const Address& src, Register dest); 337 void unboxBoolean(const ValueOperand& operand, Register dest); 338 void unboxBoolean(const Address& src, Register dest); 339 void unboxDouble(const ValueOperand& operand, FloatRegister dest); 340 void unboxDouble(const Address& src, FloatRegister dest); 341 void unboxString(const ValueOperand& operand, Register dest); 342 void unboxString(const Address& src, Register dest); 343 void unboxObject(const ValueOperand& src, Register dest); 344 void unboxObject(const Address& src, Register dest); unboxObject(const BaseIndex & src,Register dest)345 void unboxObject(const BaseIndex& src, Register dest) { 346 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 347 } 348 void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType); 349 void unboxPrivate(const ValueOperand& src, Register dest); 350 unboxGCThingForPreBarrierTrampoline(const Address & src,Register dest)351 void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) { 352 unboxObject(src, dest); 353 } 354 notBoolean(const ValueOperand & val)355 void notBoolean(const ValueOperand& val) { 356 as_xori(val.payloadReg(), val.payloadReg(), 1); 357 } 358 359 // boxing code 360 void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister); 361 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest); 362 363 // Extended unboxing API. If the payload is already in a register, returns 364 // that register. Otherwise, provides a move to the given scratch register, 365 // and returns that. 366 Register extractObject(const Address& address, Register scratch); extractObject(const ValueOperand & value,Register scratch)367 Register extractObject(const ValueOperand& value, Register scratch) { 368 return value.payloadReg(); 369 } extractString(const ValueOperand & value,Register scratch)370 Register extractString(const ValueOperand& value, Register scratch) { 371 return value.payloadReg(); 372 } extractSymbol(const ValueOperand & value,Register scratch)373 Register extractSymbol(const ValueOperand& value, Register scratch) { 374 return value.payloadReg(); 375 } extractInt32(const ValueOperand & value,Register scratch)376 Register extractInt32(const ValueOperand& value, Register scratch) { 377 return value.payloadReg(); 378 } extractBoolean(const ValueOperand & value,Register scratch)379 Register extractBoolean(const ValueOperand& value, Register scratch) { 380 return value.payloadReg(); 381 } 382 Register extractTag(const Address& address, Register scratch); 383 Register extractTag(const BaseIndex& address, Register scratch); extractTag(const ValueOperand & value,Register scratch)384 Register extractTag(const ValueOperand& value, Register scratch) { 385 return value.typeReg(); 386 } 387 388 void boolValueToDouble(const ValueOperand& operand, FloatRegister dest); 389 void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest); 390 void loadInt32OrDouble(const Address& address, FloatRegister dest); 391 void loadInt32OrDouble(Register base, Register index, FloatRegister dest, 392 int32_t shift = defaultShift); 393 void loadConstantDouble(double dp, FloatRegister dest); 394 395 void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest); 396 void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest); 397 void loadConstantFloat32(float f, FloatRegister dest); 398 399 void testNullSet(Condition cond, const ValueOperand& value, Register dest); 400 401 void testObjectSet(Condition cond, const ValueOperand& value, Register dest); 402 403 void testUndefinedSet(Condition cond, const ValueOperand& value, 404 Register dest); 405 406 // higher level tag testing code 407 Operand ToPayload(Operand base); ToPayload(Address base)408 Address ToPayload(Address base) { 409 return ToPayload(Operand(base)).toAddress(); 410 } 411 ToPayload(BaseIndex base)412 BaseIndex ToPayload(BaseIndex base) { 413 return BaseIndex(base.base, base.index, base.scale, 414 base.offset + NUNBOX32_PAYLOAD_OFFSET); 415 } 416 417 protected: 418 Operand ToType(Operand base); ToType(Address base)419 Address ToType(Address base) { return ToType(Operand(base)).toAddress(); } 420 421 uint32_t getType(const Value& val); 422 void moveData(const Value& val, Register data); 423 424 public: 425 void moveValue(const Value& val, Register type, Register data); 426 427 CodeOffsetJump backedgeJump(RepatchLabel* label, 428 Label* documentation = nullptr); 429 CodeOffsetJump jumpWithPatch(RepatchLabel* label, 430 Label* documentation = nullptr); 431 loadUnboxedValue(Address address,MIRType type,AnyRegister dest)432 void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) { 433 if (dest.isFloat()) 434 loadInt32OrDouble(address, dest.fpu()); 435 else 436 ma_lw(dest.gpr(), ToPayload(address)); 437 } 438 loadUnboxedValue(BaseIndex address,MIRType type,AnyRegister dest)439 void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) { 440 if (dest.isFloat()) 441 loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale); 442 else 443 load32(ToPayload(address), dest.gpr()); 444 } 445 446 template <typename T> 447 void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, 448 const T& dest, MIRType slotType); 449 450 template <typename T> storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType)451 void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, 452 JSValueType) { 453 switch (nbytes) { 454 case 4: 455 store32(value.payloadReg(), address); 456 return; 457 case 1: 458 store8(value.payloadReg(), address); 459 return; 460 default: 461 MOZ_CRASH("Bad payload width"); 462 } 463 } 464 465 void moveValue(const Value& val, const ValueOperand& dest); 466 moveValue(const ValueOperand & src,const ValueOperand & dest)467 void moveValue(const ValueOperand& src, const ValueOperand& dest) { 468 Register s0 = src.typeReg(), d0 = dest.typeReg(), s1 = src.payloadReg(), 469 d1 = dest.payloadReg(); 470 471 // Either one or both of the source registers could be the same as a 472 // destination register. 473 if (s1 == d0) { 474 if (s0 == d1) { 475 // If both are, this is just a swap of two registers. 476 MOZ_ASSERT(d1 != ScratchRegister); 477 MOZ_ASSERT(d0 != ScratchRegister); 478 move32(d1, ScratchRegister); 479 move32(d0, d1); 480 move32(ScratchRegister, d0); 481 return; 482 } 483 // If only one is, copy that source first. 484 mozilla::Swap(s0, s1); 485 mozilla::Swap(d0, d1); 486 } 487 488 if (s0 != d0) move32(s0, d0); 489 if (s1 != d1) move32(s1, d1); 490 } 491 492 void storeValue(ValueOperand val, Operand dst); 493 void storeValue(ValueOperand val, const BaseIndex& dest); 494 void storeValue(JSValueType type, Register reg, BaseIndex dest); 495 void storeValue(ValueOperand val, const Address& dest); 496 void storeValue(JSValueType type, Register reg, Address dest); 497 void storeValue(const Value& val, Address dest); 498 void storeValue(const Value& val, BaseIndex dest); storeValue(const Address & src,const Address & dest,Register temp)499 void storeValue(const Address& src, const Address& dest, Register temp) { 500 load32(ToType(src), temp); 501 store32(temp, ToType(dest)); 502 503 load32(ToPayload(src), temp); 504 store32(temp, ToPayload(dest)); 505 } 506 507 void loadValue(Address src, ValueOperand val); loadValue(Operand dest,ValueOperand val)508 void loadValue(Operand dest, ValueOperand val) { 509 loadValue(dest.toAddress(), val); 510 } 511 void loadValue(const BaseIndex& addr, ValueOperand val); 512 void tagValue(JSValueType type, Register payload, ValueOperand dest); 513 514 void pushValue(ValueOperand val); 515 void popValue(ValueOperand val); 516 #if MOZ_LITTLE_ENDIAN pushValue(const Value & val)517 void pushValue(const Value& val) { 518 push(Imm32(val.toNunboxTag())); 519 if (val.isGCThing()) 520 push(ImmGCPtr(val.toGCThing())); 521 else 522 push(Imm32(val.toNunboxPayload())); 523 } pushValue(JSValueType type,Register reg)524 void pushValue(JSValueType type, Register reg) { 525 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); 526 ma_push(reg); 527 } 528 #else pushValue(const Value & val)529 void pushValue(const Value& val) { 530 if (val.isGCThing()) 531 push(ImmGCPtr(val.toGCThing())); 532 else 533 push(Imm32(val.toNunboxPayload())); 534 push(Imm32(val.toNunboxTag())); 535 } pushValue(JSValueType type,Register reg)536 void pushValue(JSValueType type, Register reg) { 537 ma_push(reg); 538 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); 539 } 540 #endif 541 void pushValue(const Address& addr); 542 543 void storePayload(const Value& val, Address dest); 544 void storePayload(Register src, Address dest); 545 void storePayload(const Value& val, const BaseIndex& dest); 546 void storePayload(Register src, const BaseIndex& dest); 547 void storeTypeTag(ImmTag tag, Address dest); 548 void storeTypeTag(ImmTag tag, const BaseIndex& dest); 549 550 void handleFailureWithHandlerTail(void* handler, Label* profilerExitTail); 551 552 template <typename T> 553 void atomicStore64(const T& mem, Register temp, Register64 value); 554 555 ///////////////////////////////////////////////////////////////// 556 // Common interface. 557 ///////////////////////////////////////////////////////////////// 558 public: 559 // The following functions are exposed for use in platform-shared code. 560 561 inline void incrementInt32Value(const Address& addr); 562 563 void move32(Imm32 imm, Register dest); 564 void move32(Register src, Register dest); 565 566 void movePtr(Register src, Register dest); 567 void movePtr(ImmWord imm, Register dest); 568 void movePtr(ImmPtr imm, Register dest); 569 void movePtr(wasm::SymbolicAddress imm, Register dest); 570 void movePtr(ImmGCPtr imm, Register dest); 571 572 void load8SignExtend(const Address& address, Register dest); 573 void load8SignExtend(const BaseIndex& src, Register dest); 574 575 void load8ZeroExtend(const Address& address, Register dest); 576 void load8ZeroExtend(const BaseIndex& src, Register dest); 577 578 void load16SignExtend(const Address& address, Register dest); 579 void load16SignExtend(const BaseIndex& src, Register dest); 580 581 void load16ZeroExtend(const Address& address, Register dest); 582 void load16ZeroExtend(const BaseIndex& src, Register dest); 583 584 void load32(const Address& address, Register dest); 585 void load32(const BaseIndex& address, Register dest); 586 void load32(AbsoluteAddress address, Register dest); 587 void load32(wasm::SymbolicAddress address, Register dest); load64(const Address & address,Register64 dest)588 void load64(const Address& address, Register64 dest) { 589 load32(LowWord(address), dest.low); 590 load32(HighWord(address), dest.high); 591 } 592 593 void loadPtr(const Address& address, Register dest); 594 void loadPtr(const BaseIndex& src, Register dest); 595 void loadPtr(AbsoluteAddress address, Register dest); 596 void loadPtr(wasm::SymbolicAddress address, Register dest); 597 598 void loadPrivate(const Address& address, Register dest); 599 loadInt32x1(const Address & addr,FloatRegister dest)600 void loadInt32x1(const Address& addr, FloatRegister dest) { 601 MOZ_CRASH("NYI"); 602 } loadInt32x1(const BaseIndex & addr,FloatRegister dest)603 void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { 604 MOZ_CRASH("NYI"); 605 } loadInt32x2(const Address & addr,FloatRegister dest)606 void loadInt32x2(const Address& addr, FloatRegister dest) { 607 MOZ_CRASH("NYI"); 608 } loadInt32x2(const BaseIndex & addr,FloatRegister dest)609 void loadInt32x2(const BaseIndex& addr, FloatRegister dest) { 610 MOZ_CRASH("NYI"); 611 } loadInt32x3(const Address & src,FloatRegister dest)612 void loadInt32x3(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } loadInt32x3(const BaseIndex & src,FloatRegister dest)613 void loadInt32x3(const BaseIndex& src, FloatRegister dest) { 614 MOZ_CRASH("NYI"); 615 } loadInt32x4(const Address & src,FloatRegister dest)616 void loadInt32x4(const Address& src, FloatRegister dest) { MOZ_CRASH("NYI"); } storeInt32x1(FloatRegister src,const Address & dest)617 void storeInt32x1(FloatRegister src, const Address& dest) { 618 MOZ_CRASH("NYI"); 619 } storeInt32x1(FloatRegister src,const BaseIndex & dest)620 void storeInt32x1(FloatRegister src, const BaseIndex& dest) { 621 MOZ_CRASH("NYI"); 622 } storeInt32x2(FloatRegister src,const Address & dest)623 void storeInt32x2(FloatRegister src, const Address& dest) { 624 MOZ_CRASH("NYI"); 625 } storeInt32x2(FloatRegister src,const BaseIndex & dest)626 void storeInt32x2(FloatRegister src, const BaseIndex& dest) { 627 MOZ_CRASH("NYI"); 628 } storeInt32x3(FloatRegister src,const Address & dest)629 void storeInt32x3(FloatRegister src, const Address& dest) { 630 MOZ_CRASH("NYI"); 631 } storeInt32x3(FloatRegister src,const BaseIndex & dest)632 void storeInt32x3(FloatRegister src, const BaseIndex& dest) { 633 MOZ_CRASH("NYI"); 634 } storeInt32x4(FloatRegister src,const Address & dest)635 void storeInt32x4(FloatRegister src, const Address& dest) { 636 MOZ_CRASH("NYI"); 637 } loadAlignedSimd128Int(const Address & addr,FloatRegister dest)638 void loadAlignedSimd128Int(const Address& addr, FloatRegister dest) { 639 MOZ_CRASH("NYI"); 640 } storeAlignedSimd128Int(FloatRegister src,Address addr)641 void storeAlignedSimd128Int(FloatRegister src, Address addr) { 642 MOZ_CRASH("NYI"); 643 } loadUnalignedSimd128Int(const Address & addr,FloatRegister dest)644 void loadUnalignedSimd128Int(const Address& addr, FloatRegister dest) { 645 MOZ_CRASH("NYI"); 646 } loadUnalignedSimd128Int(const BaseIndex & addr,FloatRegister dest)647 void loadUnalignedSimd128Int(const BaseIndex& addr, FloatRegister dest) { 648 MOZ_CRASH("NYI"); 649 } storeUnalignedSimd128Int(FloatRegister src,Address addr)650 void storeUnalignedSimd128Int(FloatRegister src, Address addr) { 651 MOZ_CRASH("NYI"); 652 } storeUnalignedSimd128Int(FloatRegister src,BaseIndex addr)653 void storeUnalignedSimd128Int(FloatRegister src, BaseIndex addr) { 654 MOZ_CRASH("NYI"); 655 } 656 loadFloat32x3(const Address & src,FloatRegister dest)657 void loadFloat32x3(const Address& src, FloatRegister dest) { 658 MOZ_CRASH("NYI"); 659 } loadFloat32x3(const BaseIndex & src,FloatRegister dest)660 void loadFloat32x3(const BaseIndex& src, FloatRegister dest) { 661 MOZ_CRASH("NYI"); 662 } loadFloat32x4(const Address & src,FloatRegister dest)663 void loadFloat32x4(const Address& src, FloatRegister dest) { 664 MOZ_CRASH("NYI"); 665 } storeFloat32x4(FloatRegister src,const Address & addr)666 void storeFloat32x4(FloatRegister src, const Address& addr) { 667 MOZ_CRASH("NYI"); 668 } 669 loadAlignedSimd128Float(const Address & addr,FloatRegister dest)670 void loadAlignedSimd128Float(const Address& addr, FloatRegister dest) { 671 MOZ_CRASH("NYI"); 672 } storeAlignedSimd128Float(FloatRegister src,Address addr)673 void storeAlignedSimd128Float(FloatRegister src, Address addr) { 674 MOZ_CRASH("NYI"); 675 } loadUnalignedSimd128Float(const Address & addr,FloatRegister dest)676 void loadUnalignedSimd128Float(const Address& addr, FloatRegister dest) { 677 MOZ_CRASH("NYI"); 678 } loadUnalignedSimd128Float(const BaseIndex & addr,FloatRegister dest)679 void loadUnalignedSimd128Float(const BaseIndex& addr, FloatRegister dest) { 680 MOZ_CRASH("NYI"); 681 } storeUnalignedSimd128Float(FloatRegister src,Address addr)682 void storeUnalignedSimd128Float(FloatRegister src, Address addr) { 683 MOZ_CRASH("NYI"); 684 } storeUnalignedSimd128Float(FloatRegister src,BaseIndex addr)685 void storeUnalignedSimd128Float(FloatRegister src, BaseIndex addr) { 686 MOZ_CRASH("NYI"); 687 } 688 689 void loadUnalignedDouble(const wasm::MemoryAccessDesc& access, 690 const BaseIndex& src, Register temp, 691 FloatRegister dest); 692 693 void loadUnalignedFloat32(const wasm::MemoryAccessDesc& access, 694 const BaseIndex& src, Register temp, 695 FloatRegister dest); 696 697 void store8(Register src, const Address& address); 698 void store8(Imm32 imm, const Address& address); 699 void store8(Register src, const BaseIndex& address); 700 void store8(Imm32 imm, const BaseIndex& address); 701 702 void store16(Register src, const Address& address); 703 void store16(Imm32 imm, const Address& address); 704 void store16(Register src, const BaseIndex& address); 705 void store16(Imm32 imm, const BaseIndex& address); 706 707 void store32(Register src, AbsoluteAddress address); 708 void store32(Register src, const Address& address); 709 void store32(Register src, const BaseIndex& address); 710 void store32(Imm32 src, const Address& address); 711 void store32(Imm32 src, const BaseIndex& address); 712 713 // NOTE: This will use second scratch on MIPS. Only ARM needs the 714 // implementation without second scratch. store32_NoSecondScratch(Imm32 src,const Address & address)715 void store32_NoSecondScratch(Imm32 src, const Address& address) { 716 store32(src, address); 717 } 718 store64(Register64 src,Address address)719 void store64(Register64 src, Address address) { 720 store32(src.low, Address(address.base, address.offset + LOW_32_OFFSET)); 721 store32(src.high, Address(address.base, address.offset + HIGH_32_OFFSET)); 722 } 723 store64(Imm64 imm,Address address)724 void store64(Imm64 imm, Address address) { 725 store32(imm.low(), Address(address.base, address.offset + LOW_32_OFFSET)); 726 store32(imm.hi(), Address(address.base, address.offset + HIGH_32_OFFSET)); 727 } 728 729 template <typename T> 730 void storePtr(ImmWord imm, T address); 731 template <typename T> 732 void storePtr(ImmPtr imm, T address); 733 template <typename T> 734 void storePtr(ImmGCPtr imm, T address); 735 void storePtr(Register src, const Address& address); 736 void storePtr(Register src, const BaseIndex& address); 737 void storePtr(Register src, AbsoluteAddress dest); 738 739 void storeUnalignedFloat32(const wasm::MemoryAccessDesc& access, 740 FloatRegister src, Register temp, 741 const BaseIndex& dest); 742 void storeUnalignedDouble(const wasm::MemoryAccessDesc& access, 743 FloatRegister src, Register temp, 744 const BaseIndex& dest); 745 moveDouble(FloatRegister src,FloatRegister dest)746 void moveDouble(FloatRegister src, FloatRegister dest) { as_movd(dest, src); } 747 zeroDouble(FloatRegister reg)748 void zeroDouble(FloatRegister reg) { 749 moveToDoubleLo(zero, reg); 750 moveToDoubleHi(zero, reg); 751 } 752 753 void breakpoint(); 754 755 void checkStackAlignment(); 756 757 void alignStackPointer(); 758 void restoreStackPointer(); 759 static void calculateAlignedStackPointer(void** stackPointer); 760 761 // If source is a double, load it into dest. If source is int32, 762 // convert it to double. Else, branch to failure. 763 void ensureDouble(const ValueOperand& source, FloatRegister dest, 764 Label* failure); 765 766 void cmp64Set(Condition cond, Register64 lhs, Register64 rhs, Register dest); 767 void cmp64Set(Condition cond, Register64 lhs, Imm64 val, Register dest); 768 769 protected: 770 bool buildOOLFakeExitFrame(void* fakeReturnAddr); 771 772 void enterAtomic64Region(Register addr, Register spinlock, Register tmp); 773 void exitAtomic64Region(Register spinlock); 774 void wasmLoadI64Impl(const wasm::MemoryAccessDesc& access, 775 Register memoryBase, Register ptr, Register ptrScratch, 776 Register64 output, Register tmp); 777 void wasmStoreI64Impl(const wasm::MemoryAccessDesc& access, Register64 value, 778 Register memoryBase, Register ptr, Register ptrScratch, 779 Register tmp); 780 Condition ma_cmp64(Condition cond, Register64 lhs, Register64 rhs, 781 Register dest); 782 Condition ma_cmp64(Condition cond, Register64 lhs, Imm64 val, Register dest); 783 784 public: labelForPatch()785 CodeOffset labelForPatch() { return CodeOffset(nextOffset().getOffset()); } 786 lea(Operand addr,Register dest)787 void lea(Operand addr, Register dest) { 788 ma_addu(dest, addr.baseReg(), Imm32(addr.disp())); 789 } 790 abiret()791 void abiret() { 792 as_jr(ra); 793 as_nop(); 794 } 795 ma_storeImm(Imm32 imm,const Address & addr)796 void ma_storeImm(Imm32 imm, const Address& addr) { ma_sw(imm, addr); } 797 moveFloat32(FloatRegister src,FloatRegister dest)798 void moveFloat32(FloatRegister src, FloatRegister dest) { 799 as_movs(dest, src); 800 } loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)801 void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { 802 loadPtr(Address(WasmTlsReg, 803 offsetof(wasm::TlsData, globalArea) + globalDataOffset), 804 dest); 805 } loadWasmPinnedRegsFromTls()806 void loadWasmPinnedRegsFromTls() { 807 loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg); 808 } 809 810 // Instrumentation for entering and leaving the profiler. 811 void profilerEnterFrame(Register framePtr, Register scratch); 812 void profilerExitFrame(); 813 }; 814 815 typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific; 816 817 } // namespace jit 818 } // namespace js 819 820 #endif /* jit_mips32_MacroAssembler_mips32_h */ 821