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