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_x64_MacroAssembler_x64_h 8 #define jit_x64_MacroAssembler_x64_h 9 10 #include "jit/x86-shared/MacroAssembler-x86-shared.h" 11 #include "js/HeapAPI.h" 12 #include "wasm/WasmBuiltins.h" 13 #include "wasm/WasmTlsData.h" 14 15 namespace js { 16 namespace jit { 17 18 struct ImmShiftedTag : public ImmWord { ImmShiftedTagImmShiftedTag19 explicit ImmShiftedTag(JSValueShiftedTag shtag) : ImmWord((uintptr_t)shtag) {} 20 ImmShiftedTagImmShiftedTag21 explicit ImmShiftedTag(JSValueType type) 22 : ImmWord(uintptr_t(JSVAL_TYPE_TO_SHIFTED_TAG(type))) {} 23 }; 24 25 struct ImmTag : public Imm32 { ImmTagImmTag26 explicit ImmTag(JSValueTag tag) : Imm32(tag) {} 27 }; 28 29 // ScratchTagScope and ScratchTagScopeRelease are used to manage the tag 30 // register for splitTagForTest(), which has different register management on 31 // different platforms. On 64-bit platforms it requires a scratch register that 32 // does not interfere with other operations; on 32-bit platforms it uses a 33 // register that is already part of the Value. 34 // 35 // The ScratchTagScope RAII type acquires the appropriate register; a reference 36 // to a variable of this type is then passed to splitTagForTest(). 37 // 38 // On 64-bit platforms ScratchTagScopeRelease makes the owned scratch register 39 // available in a dynamic scope during compilation. However it is important to 40 // remember that that does not preserve the register value in any way, so this 41 // RAII type should only be used along paths that eventually branch past further 42 // uses of the extracted tag value. 43 // 44 // On 32-bit platforms ScratchTagScopeRelease has no effect, since it does not 45 // manage a register, it only aliases a register in the ValueOperand. 46 47 class ScratchTagScope : public ScratchRegisterScope { 48 public: ScratchTagScope(MacroAssembler & masm,const ValueOperand &)49 ScratchTagScope(MacroAssembler& masm, const ValueOperand&) 50 : ScratchRegisterScope(masm) {} 51 }; 52 53 class ScratchTagScopeRelease { 54 ScratchTagScope* ts_; 55 56 public: ScratchTagScopeRelease(ScratchTagScope * ts)57 explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) { 58 ts_->release(); 59 } ~ScratchTagScopeRelease()60 ~ScratchTagScopeRelease() { ts_->reacquire(); } 61 }; 62 63 class MacroAssemblerX64 : public MacroAssemblerX86Shared { 64 private: 65 // Perform a downcast. Should be removed by Bug 996602. 66 MacroAssembler& asMasm(); 67 const MacroAssembler& asMasm() const; 68 69 void bindOffsets(const MacroAssemblerX86Shared::UsesVector&); 70 71 void vpRiprOpSimd128(const SimdConstant& v, FloatRegister reg, 72 JmpSrc (X86Encoding::BaseAssemblerX64::*op)( 73 X86Encoding::XMMRegisterID id)); 74 75 void vpRiprOpSimd128(const SimdConstant& v, FloatRegister lhs, 76 FloatRegister dest, 77 JmpSrc (X86Encoding::BaseAssemblerX64::*op)( 78 X86Encoding::XMMRegisterID srcId, 79 X86Encoding::XMMRegisterID destId)); 80 81 public: 82 using MacroAssemblerX86Shared::load32; 83 using MacroAssemblerX86Shared::store16; 84 using MacroAssemblerX86Shared::store32; 85 86 MacroAssemblerX64() = default; 87 88 // The buffer is about to be linked, make sure any constant pools or excess 89 // bookkeeping has been flushed to the instruction stream. 90 void finish(); 91 92 ///////////////////////////////////////////////////////////////// 93 // X64 helpers. 94 ///////////////////////////////////////////////////////////////// writeDataRelocation(const Value & val)95 void writeDataRelocation(const Value& val) { 96 // Raw GC pointer relocations and Value relocations both end up in 97 // Assembler::TraceDataRelocations. 98 if (val.isGCThing()) { 99 gc::Cell* cell = val.toGCThing(); 100 if (cell && gc::IsInsideNursery(cell)) { 101 embedsNurseryPointers_ = true; 102 } 103 dataRelocations_.writeUnsigned(masm.currentOffset()); 104 } 105 } 106 107 // Refers to the upper 32 bits of a 64-bit Value operand. 108 // On x86_64, the upper 32 bits do not necessarily only contain the type. ToUpper32(Operand base)109 Operand ToUpper32(Operand base) { 110 switch (base.kind()) { 111 case Operand::MEM_REG_DISP: 112 return Operand(Register::FromCode(base.base()), base.disp() + 4); 113 114 case Operand::MEM_SCALE: 115 return Operand(Register::FromCode(base.base()), 116 Register::FromCode(base.index()), base.scale(), 117 base.disp() + 4); 118 119 default: 120 MOZ_CRASH("unexpected operand kind"); 121 } 122 } ToUpper32(const Address & address)123 static inline Operand ToUpper32(const Address& address) { 124 return Operand(address.base, address.offset + 4); 125 } ToUpper32(const BaseIndex & address)126 static inline Operand ToUpper32(const BaseIndex& address) { 127 return Operand(address.base, address.index, address.scale, 128 address.offset + 4); 129 } 130 Upper32Of(JSValueShiftedTag tag)131 uint32_t Upper32Of(JSValueShiftedTag tag) { return uint32_t(tag >> 32); } 132 GetShiftedTag(JSValueType type)133 JSValueShiftedTag GetShiftedTag(JSValueType type) { 134 return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); 135 } 136 137 ///////////////////////////////////////////////////////////////// 138 // X86/X64-common interface. 139 ///////////////////////////////////////////////////////////////// ToPayload(Address value)140 Address ToPayload(Address value) { return value; } 141 storeValue(ValueOperand val,Operand dest)142 void storeValue(ValueOperand val, Operand dest) { 143 movq(val.valueReg(), dest); 144 } storeValue(ValueOperand val,const Address & dest)145 void storeValue(ValueOperand val, const Address& dest) { 146 storeValue(val, Operand(dest)); 147 } 148 template <typename T> storeValue(JSValueType type,Register reg,const T & dest)149 void storeValue(JSValueType type, Register reg, const T& dest) { 150 // Value types with 32-bit payloads can be emitted as two 32-bit moves. 151 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 152 movl(reg, Operand(dest)); 153 movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest))); 154 } else { 155 ScratchRegisterScope scratch(asMasm()); 156 boxValue(type, reg, scratch); 157 movq(scratch, Operand(dest)); 158 } 159 } 160 template <typename T> storeValue(const Value & val,const T & dest)161 void storeValue(const Value& val, const T& dest) { 162 ScratchRegisterScope scratch(asMasm()); 163 if (val.isGCThing()) { 164 movWithPatch(ImmWord(val.asRawBits()), scratch); 165 writeDataRelocation(val); 166 } else { 167 mov(ImmWord(val.asRawBits()), scratch); 168 } 169 movq(scratch, Operand(dest)); 170 } storeValue(ValueOperand val,BaseIndex dest)171 void storeValue(ValueOperand val, BaseIndex dest) { 172 storeValue(val, Operand(dest)); 173 } storeValue(const Address & src,const Address & dest,Register temp)174 void storeValue(const Address& src, const Address& dest, Register temp) { 175 loadPtr(src, temp); 176 storePtr(temp, dest); 177 } storePrivateValue(Register src,const Address & dest)178 void storePrivateValue(Register src, const Address& dest) { 179 storePtr(src, dest); 180 } storePrivateValue(ImmGCPtr imm,const Address & dest)181 void storePrivateValue(ImmGCPtr imm, const Address& dest) { 182 storePtr(imm, dest); 183 } loadValue(Operand src,ValueOperand val)184 void loadValue(Operand src, ValueOperand val) { movq(src, val.valueReg()); } loadValue(Address src,ValueOperand val)185 void loadValue(Address src, ValueOperand val) { 186 loadValue(Operand(src), val); 187 } loadValue(const BaseIndex & src,ValueOperand val)188 void loadValue(const BaseIndex& src, ValueOperand val) { 189 loadValue(Operand(src), val); 190 } loadUnalignedValue(const Address & src,ValueOperand dest)191 void loadUnalignedValue(const Address& src, ValueOperand dest) { 192 loadValue(src, dest); 193 } tagValue(JSValueType type,Register payload,ValueOperand dest)194 void tagValue(JSValueType type, Register payload, ValueOperand dest) { 195 ScratchRegisterScope scratch(asMasm()); 196 MOZ_ASSERT(dest.valueReg() != scratch); 197 if (payload != dest.valueReg()) { 198 movq(payload, dest.valueReg()); 199 } 200 mov(ImmShiftedTag(type), scratch); 201 orq(scratch, dest.valueReg()); 202 } pushValue(ValueOperand val)203 void pushValue(ValueOperand val) { push(val.valueReg()); } popValue(ValueOperand val)204 void popValue(ValueOperand val) { pop(val.valueReg()); } pushValue(const Value & val)205 void pushValue(const Value& val) { 206 if (val.isGCThing()) { 207 ScratchRegisterScope scratch(asMasm()); 208 movWithPatch(ImmWord(val.asRawBits()), scratch); 209 writeDataRelocation(val); 210 push(scratch); 211 } else { 212 push(ImmWord(val.asRawBits())); 213 } 214 } pushValue(JSValueType type,Register reg)215 void pushValue(JSValueType type, Register reg) { 216 ScratchRegisterScope scratch(asMasm()); 217 boxValue(type, reg, scratch); 218 push(scratch); 219 } pushValue(const Address & addr)220 void pushValue(const Address& addr) { push(Operand(addr)); } 221 222 void boxValue(JSValueType type, Register src, Register dest); 223 testUndefined(Condition cond,Register tag)224 Condition testUndefined(Condition cond, Register tag) { 225 MOZ_ASSERT(cond == Equal || cond == NotEqual); 226 cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 227 return cond; 228 } testInt32(Condition cond,Register tag)229 Condition testInt32(Condition cond, Register tag) { 230 MOZ_ASSERT(cond == Equal || cond == NotEqual); 231 cmp32(tag, ImmTag(JSVAL_TAG_INT32)); 232 return cond; 233 } testBoolean(Condition cond,Register tag)234 Condition testBoolean(Condition cond, Register tag) { 235 MOZ_ASSERT(cond == Equal || cond == NotEqual); 236 cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 237 return cond; 238 } testNull(Condition cond,Register tag)239 Condition testNull(Condition cond, Register tag) { 240 MOZ_ASSERT(cond == Equal || cond == NotEqual); 241 cmp32(tag, ImmTag(JSVAL_TAG_NULL)); 242 return cond; 243 } testString(Condition cond,Register tag)244 Condition testString(Condition cond, Register tag) { 245 MOZ_ASSERT(cond == Equal || cond == NotEqual); 246 cmp32(tag, ImmTag(JSVAL_TAG_STRING)); 247 return cond; 248 } testSymbol(Condition cond,Register tag)249 Condition testSymbol(Condition cond, Register tag) { 250 MOZ_ASSERT(cond == Equal || cond == NotEqual); 251 cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL)); 252 return cond; 253 } testBigInt(Condition cond,Register tag)254 Condition testBigInt(Condition cond, Register tag) { 255 MOZ_ASSERT(cond == Equal || cond == NotEqual); 256 cmp32(tag, ImmTag(JSVAL_TAG_BIGINT)); 257 return cond; 258 } testObject(Condition cond,Register tag)259 Condition testObject(Condition cond, Register tag) { 260 MOZ_ASSERT(cond == Equal || cond == NotEqual); 261 cmp32(tag, ImmTag(JSVAL_TAG_OBJECT)); 262 return cond; 263 } testDouble(Condition cond,Register tag)264 Condition testDouble(Condition cond, Register tag) { 265 MOZ_ASSERT(cond == Equal || cond == NotEqual); 266 cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE)); 267 return cond == Equal ? BelowOrEqual : Above; 268 } testNumber(Condition cond,Register tag)269 Condition testNumber(Condition cond, Register tag) { 270 MOZ_ASSERT(cond == Equal || cond == NotEqual); 271 cmp32(tag, Imm32(JS::detail::ValueUpperInclNumberTag)); 272 return cond == Equal ? BelowOrEqual : Above; 273 } testGCThing(Condition cond,Register tag)274 Condition testGCThing(Condition cond, Register tag) { 275 MOZ_ASSERT(cond == Equal || cond == NotEqual); 276 cmp32(tag, Imm32(JS::detail::ValueLowerInclGCThingTag)); 277 return cond == Equal ? AboveOrEqual : Below; 278 } 279 testMagic(Condition cond,Register tag)280 Condition testMagic(Condition cond, Register tag) { 281 MOZ_ASSERT(cond == Equal || cond == NotEqual); 282 cmp32(tag, ImmTag(JSVAL_TAG_MAGIC)); 283 return cond; 284 } testError(Condition cond,Register tag)285 Condition testError(Condition cond, Register tag) { 286 return testMagic(cond, tag); 287 } testPrimitive(Condition cond,Register tag)288 Condition testPrimitive(Condition cond, Register tag) { 289 MOZ_ASSERT(cond == Equal || cond == NotEqual); 290 cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag)); 291 return cond == Equal ? Below : AboveOrEqual; 292 } 293 testUndefined(Condition cond,const ValueOperand & src)294 Condition testUndefined(Condition cond, const ValueOperand& src) { 295 ScratchRegisterScope scratch(asMasm()); 296 splitTag(src, scratch); 297 return testUndefined(cond, scratch); 298 } testInt32(Condition cond,const ValueOperand & src)299 Condition testInt32(Condition cond, const ValueOperand& src) { 300 ScratchRegisterScope scratch(asMasm()); 301 splitTag(src, scratch); 302 return testInt32(cond, scratch); 303 } testBoolean(Condition cond,const ValueOperand & src)304 Condition testBoolean(Condition cond, const ValueOperand& src) { 305 ScratchRegisterScope scratch(asMasm()); 306 splitTag(src, scratch); 307 return testBoolean(cond, scratch); 308 } testDouble(Condition cond,const ValueOperand & src)309 Condition testDouble(Condition cond, const ValueOperand& src) { 310 ScratchRegisterScope scratch(asMasm()); 311 splitTag(src, scratch); 312 return testDouble(cond, scratch); 313 } testNumber(Condition cond,const ValueOperand & src)314 Condition testNumber(Condition cond, const ValueOperand& src) { 315 ScratchRegisterScope scratch(asMasm()); 316 splitTag(src, scratch); 317 return testNumber(cond, scratch); 318 } testNull(Condition cond,const ValueOperand & src)319 Condition testNull(Condition cond, const ValueOperand& src) { 320 ScratchRegisterScope scratch(asMasm()); 321 splitTag(src, scratch); 322 return testNull(cond, scratch); 323 } testString(Condition cond,const ValueOperand & src)324 Condition testString(Condition cond, const ValueOperand& src) { 325 ScratchRegisterScope scratch(asMasm()); 326 splitTag(src, scratch); 327 return testString(cond, scratch); 328 } testSymbol(Condition cond,const ValueOperand & src)329 Condition testSymbol(Condition cond, const ValueOperand& src) { 330 ScratchRegisterScope scratch(asMasm()); 331 splitTag(src, scratch); 332 return testSymbol(cond, scratch); 333 } testBigInt(Condition cond,const ValueOperand & src)334 Condition testBigInt(Condition cond, const ValueOperand& src) { 335 ScratchRegisterScope scratch(asMasm()); 336 splitTag(src, scratch); 337 return testBigInt(cond, scratch); 338 } testObject(Condition cond,const ValueOperand & src)339 Condition testObject(Condition cond, const ValueOperand& src) { 340 ScratchRegisterScope scratch(asMasm()); 341 splitTag(src, scratch); 342 return testObject(cond, scratch); 343 } testGCThing(Condition cond,const ValueOperand & src)344 Condition testGCThing(Condition cond, const ValueOperand& src) { 345 ScratchRegisterScope scratch(asMasm()); 346 splitTag(src, scratch); 347 return testGCThing(cond, scratch); 348 } testPrimitive(Condition cond,const ValueOperand & src)349 Condition testPrimitive(Condition cond, const ValueOperand& src) { 350 ScratchRegisterScope scratch(asMasm()); 351 splitTag(src, scratch); 352 return testPrimitive(cond, scratch); 353 } 354 testUndefined(Condition cond,const Address & src)355 Condition testUndefined(Condition cond, const Address& src) { 356 cmp32(ToUpper32(src), 357 Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED)))); 358 return cond; 359 } testInt32(Condition cond,const Address & src)360 Condition testInt32(Condition cond, const Address& src) { 361 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); 362 return cond; 363 } testBoolean(Condition cond,const Address & src)364 Condition testBoolean(Condition cond, const Address& src) { 365 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN)))); 366 return cond; 367 } testDouble(Condition cond,const Address & src)368 Condition testDouble(Condition cond, const Address& src) { 369 ScratchRegisterScope scratch(asMasm()); 370 splitTag(src, scratch); 371 return testDouble(cond, scratch); 372 } testNumber(Condition cond,const Address & src)373 Condition testNumber(Condition cond, const Address& src) { 374 ScratchRegisterScope scratch(asMasm()); 375 splitTag(src, scratch); 376 return testNumber(cond, scratch); 377 } testNull(Condition cond,const Address & src)378 Condition testNull(Condition cond, const Address& src) { 379 cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL)))); 380 return cond; 381 } testString(Condition cond,const Address & src)382 Condition testString(Condition cond, const Address& src) { 383 ScratchRegisterScope scratch(asMasm()); 384 splitTag(src, scratch); 385 return testString(cond, scratch); 386 } testSymbol(Condition cond,const Address & src)387 Condition testSymbol(Condition cond, const Address& src) { 388 ScratchRegisterScope scratch(asMasm()); 389 splitTag(src, scratch); 390 return testSymbol(cond, scratch); 391 } testBigInt(Condition cond,const Address & src)392 Condition testBigInt(Condition cond, const Address& src) { 393 ScratchRegisterScope scratch(asMasm()); 394 splitTag(src, scratch); 395 return testBigInt(cond, scratch); 396 } testObject(Condition cond,const Address & src)397 Condition testObject(Condition cond, const Address& src) { 398 ScratchRegisterScope scratch(asMasm()); 399 splitTag(src, scratch); 400 return testObject(cond, scratch); 401 } testPrimitive(Condition cond,const Address & src)402 Condition testPrimitive(Condition cond, const Address& src) { 403 ScratchRegisterScope scratch(asMasm()); 404 splitTag(src, scratch); 405 return testPrimitive(cond, scratch); 406 } testGCThing(Condition cond,const Address & src)407 Condition testGCThing(Condition cond, const Address& src) { 408 ScratchRegisterScope scratch(asMasm()); 409 splitTag(src, scratch); 410 return testGCThing(cond, scratch); 411 } testMagic(Condition cond,const Address & src)412 Condition testMagic(Condition cond, const Address& src) { 413 ScratchRegisterScope scratch(asMasm()); 414 splitTag(src, scratch); 415 return testMagic(cond, scratch); 416 } 417 testUndefined(Condition cond,const BaseIndex & src)418 Condition testUndefined(Condition cond, const BaseIndex& src) { 419 ScratchRegisterScope scratch(asMasm()); 420 splitTag(src, scratch); 421 return testUndefined(cond, scratch); 422 } testNull(Condition cond,const BaseIndex & src)423 Condition testNull(Condition cond, const BaseIndex& src) { 424 ScratchRegisterScope scratch(asMasm()); 425 splitTag(src, scratch); 426 return testNull(cond, scratch); 427 } testBoolean(Condition cond,const BaseIndex & src)428 Condition testBoolean(Condition cond, const BaseIndex& src) { 429 ScratchRegisterScope scratch(asMasm()); 430 splitTag(src, scratch); 431 return testBoolean(cond, scratch); 432 } testString(Condition cond,const BaseIndex & src)433 Condition testString(Condition cond, const BaseIndex& src) { 434 ScratchRegisterScope scratch(asMasm()); 435 splitTag(src, scratch); 436 return testString(cond, scratch); 437 } testSymbol(Condition cond,const BaseIndex & src)438 Condition testSymbol(Condition cond, const BaseIndex& src) { 439 ScratchRegisterScope scratch(asMasm()); 440 splitTag(src, scratch); 441 return testSymbol(cond, scratch); 442 } testBigInt(Condition cond,const BaseIndex & src)443 Condition testBigInt(Condition cond, const BaseIndex& src) { 444 ScratchRegisterScope scratch(asMasm()); 445 splitTag(src, scratch); 446 return testBigInt(cond, scratch); 447 } testInt32(Condition cond,const BaseIndex & src)448 Condition testInt32(Condition cond, const BaseIndex& src) { 449 ScratchRegisterScope scratch(asMasm()); 450 splitTag(src, scratch); 451 return testInt32(cond, scratch); 452 } testObject(Condition cond,const BaseIndex & src)453 Condition testObject(Condition cond, const BaseIndex& src) { 454 ScratchRegisterScope scratch(asMasm()); 455 splitTag(src, scratch); 456 return testObject(cond, scratch); 457 } testDouble(Condition cond,const BaseIndex & src)458 Condition testDouble(Condition cond, const BaseIndex& src) { 459 ScratchRegisterScope scratch(asMasm()); 460 splitTag(src, scratch); 461 return testDouble(cond, scratch); 462 } testMagic(Condition cond,const BaseIndex & src)463 Condition testMagic(Condition cond, const BaseIndex& src) { 464 ScratchRegisterScope scratch(asMasm()); 465 splitTag(src, scratch); 466 return testMagic(cond, scratch); 467 } testGCThing(Condition cond,const BaseIndex & src)468 Condition testGCThing(Condition cond, const BaseIndex& src) { 469 ScratchRegisterScope scratch(asMasm()); 470 splitTag(src, scratch); 471 return testGCThing(cond, scratch); 472 } 473 isMagic(Condition cond,const ValueOperand & src,JSWhyMagic why)474 Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) { 475 uint64_t magic = MagicValue(why).asRawBits(); 476 cmpPtr(src.valueReg(), ImmWord(magic)); 477 return cond; 478 } 479 cmpPtr(Register lhs,const ImmWord rhs)480 void cmpPtr(Register lhs, const ImmWord rhs) { 481 ScratchRegisterScope scratch(asMasm()); 482 MOZ_ASSERT(lhs != scratch); 483 if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) { 484 cmpPtr(lhs, Imm32(int32_t(rhs.value))); 485 } else { 486 movePtr(rhs, scratch); 487 cmpPtr(lhs, scratch); 488 } 489 } cmpPtr(Register lhs,const ImmPtr rhs)490 void cmpPtr(Register lhs, const ImmPtr rhs) { 491 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 492 } cmpPtr(Register lhs,const ImmGCPtr rhs)493 void cmpPtr(Register lhs, const ImmGCPtr rhs) { 494 ScratchRegisterScope scratch(asMasm()); 495 MOZ_ASSERT(lhs != scratch); 496 movePtr(rhs, scratch); 497 cmpPtr(lhs, scratch); 498 } cmpPtr(Register lhs,const Imm32 rhs)499 void cmpPtr(Register lhs, const Imm32 rhs) { cmpq(rhs, lhs); } cmpPtr(const Operand & lhs,const ImmGCPtr rhs)500 void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { 501 ScratchRegisterScope scratch(asMasm()); 502 MOZ_ASSERT(!lhs.containsReg(scratch)); 503 movePtr(rhs, scratch); 504 cmpPtr(lhs, scratch); 505 } cmpPtr(const Operand & lhs,const ImmWord rhs)506 void cmpPtr(const Operand& lhs, const ImmWord rhs) { 507 if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { 508 cmpPtr(lhs, Imm32((int32_t)rhs.value)); 509 } else { 510 ScratchRegisterScope scratch(asMasm()); 511 movePtr(rhs, scratch); 512 cmpPtr(lhs, scratch); 513 } 514 } cmpPtr(const Operand & lhs,const ImmPtr rhs)515 void cmpPtr(const Operand& lhs, const ImmPtr rhs) { 516 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 517 } cmpPtr(const Address & lhs,const ImmGCPtr rhs)518 void cmpPtr(const Address& lhs, const ImmGCPtr rhs) { 519 cmpPtr(Operand(lhs), rhs); 520 } cmpPtr(const Address & lhs,const ImmWord rhs)521 void cmpPtr(const Address& lhs, const ImmWord rhs) { 522 cmpPtr(Operand(lhs), rhs); 523 } cmpPtr(const Address & lhs,const ImmPtr rhs)524 void cmpPtr(const Address& lhs, const ImmPtr rhs) { 525 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 526 } cmpPtr(const Operand & lhs,Register rhs)527 void cmpPtr(const Operand& lhs, Register rhs) { cmpq(rhs, lhs); } cmpPtr(Register lhs,const Operand & rhs)528 void cmpPtr(Register lhs, const Operand& rhs) { cmpq(rhs, lhs); } cmpPtr(const Operand & lhs,const Imm32 rhs)529 void cmpPtr(const Operand& lhs, const Imm32 rhs) { cmpq(rhs, lhs); } cmpPtr(const Address & lhs,Register rhs)530 void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); } cmpPtr(Register lhs,Register rhs)531 void cmpPtr(Register lhs, Register rhs) { cmpq(rhs, lhs); } testPtr(Register lhs,Register rhs)532 void testPtr(Register lhs, Register rhs) { testq(rhs, lhs); } testPtr(Register lhs,Imm32 rhs)533 void testPtr(Register lhs, Imm32 rhs) { testq(rhs, lhs); } testPtr(const Operand & lhs,Imm32 rhs)534 void testPtr(const Operand& lhs, Imm32 rhs) { testq(rhs, lhs); } test64(Register lhs,Register rhs)535 void test64(Register lhs, Register rhs) { testq(rhs, lhs); } test64(Register lhs,const Imm64 rhs)536 void test64(Register lhs, const Imm64 rhs) { 537 if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { 538 testq(Imm32((int32_t)rhs.value), lhs); 539 } else { 540 ScratchRegisterScope scratch(asMasm()); 541 movq(ImmWord(rhs.value), scratch); 542 testq(scratch, lhs); 543 } 544 } 545 546 // Compare-then-conditionally-move/load, for integer types 547 template <size_t CmpSize, size_t MoveSize> 548 void cmpMove(Condition cond, Register lhs, Register rhs, Register falseVal, 549 Register trueValAndDest); 550 551 template <size_t CmpSize, size_t MoveSize> 552 void cmpMove(Condition cond, Register lhs, const Address& rhs, 553 Register falseVal, Register trueValAndDest); 554 555 template <size_t CmpSize, size_t LoadSize> 556 void cmpLoad(Condition cond, Register lhs, Register rhs, 557 const Address& falseVal, Register trueValAndDest); 558 559 template <size_t CmpSize, size_t LoadSize> 560 void cmpLoad(Condition cond, Register lhs, const Address& rhs, 561 const Address& falseVal, Register trueValAndDest); 562 563 ///////////////////////////////////////////////////////////////// 564 // Common interface. 565 ///////////////////////////////////////////////////////////////// 566 movePtr(Register src,Register dest)567 void movePtr(Register src, Register dest) { movq(src, dest); } movePtr(Register src,const Operand & dest)568 void movePtr(Register src, const Operand& dest) { movq(src, dest); } movePtr(ImmWord imm,Register dest)569 void movePtr(ImmWord imm, Register dest) { mov(imm, dest); } movePtr(ImmPtr imm,Register dest)570 void movePtr(ImmPtr imm, Register dest) { mov(imm, dest); } movePtr(wasm::SymbolicAddress imm,Register dest)571 void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); } movePtr(ImmGCPtr imm,Register dest)572 void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); } loadPtr(AbsoluteAddress address,Register dest)573 void loadPtr(AbsoluteAddress address, Register dest) { 574 if (X86Encoding::IsAddressImmediate(address.addr)) { 575 movq(Operand(address), dest); 576 } else { 577 ScratchRegisterScope scratch(asMasm()); 578 mov(ImmPtr(address.addr), scratch); 579 loadPtr(Address(scratch, 0x0), dest); 580 } 581 } loadPtr(const Address & address,Register dest)582 void loadPtr(const Address& address, Register dest) { 583 movq(Operand(address), dest); 584 } load64(const Address & address,Register dest)585 void load64(const Address& address, Register dest) { 586 movq(Operand(address), dest); 587 } loadPtr(const Operand & src,Register dest)588 void loadPtr(const Operand& src, Register dest) { movq(src, dest); } loadPtr(const BaseIndex & src,Register dest)589 void loadPtr(const BaseIndex& src, Register dest) { 590 movq(Operand(src), dest); 591 } loadPrivate(const Address & src,Register dest)592 void loadPrivate(const Address& src, Register dest) { loadPtr(src, dest); } load32(AbsoluteAddress address,Register dest)593 void load32(AbsoluteAddress address, Register dest) { 594 if (X86Encoding::IsAddressImmediate(address.addr)) { 595 movl(Operand(address), dest); 596 } else { 597 ScratchRegisterScope scratch(asMasm()); 598 mov(ImmPtr(address.addr), scratch); 599 load32(Address(scratch, 0x0), dest); 600 } 601 } load64(const Operand & address,Register64 dest)602 void load64(const Operand& address, Register64 dest) { 603 movq(address, dest.reg); 604 } load64(const Address & address,Register64 dest)605 void load64(const Address& address, Register64 dest) { 606 movq(Operand(address), dest.reg); 607 } load64(const BaseIndex & address,Register64 dest)608 void load64(const BaseIndex& address, Register64 dest) { 609 movq(Operand(address), dest.reg); 610 } 611 template <typename S> load64Unaligned(const S & src,Register64 dest)612 void load64Unaligned(const S& src, Register64 dest) { 613 load64(src, dest); 614 } 615 template <typename T> storePtr(ImmWord imm,T address)616 void storePtr(ImmWord imm, T address) { 617 if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { 618 movq(Imm32((int32_t)imm.value), Operand(address)); 619 } else { 620 ScratchRegisterScope scratch(asMasm()); 621 mov(imm, scratch); 622 movq(scratch, Operand(address)); 623 } 624 } 625 template <typename T> storePtr(ImmPtr imm,T address)626 void storePtr(ImmPtr imm, T address) { 627 storePtr(ImmWord(uintptr_t(imm.value)), address); 628 } 629 template <typename T> storePtr(ImmGCPtr imm,T address)630 void storePtr(ImmGCPtr imm, T address) { 631 ScratchRegisterScope scratch(asMasm()); 632 movq(imm, scratch); 633 movq(scratch, Operand(address)); 634 } storePtr(Register src,const Address & address)635 void storePtr(Register src, const Address& address) { 636 movq(src, Operand(address)); 637 } store64(Register src,const Address & address)638 void store64(Register src, const Address& address) { 639 movq(src, Operand(address)); 640 } store64(Register64 src,const Operand & address)641 void store64(Register64 src, const Operand& address) { 642 movq(src.reg, address); 643 } storePtr(Register src,const BaseIndex & address)644 void storePtr(Register src, const BaseIndex& address) { 645 movq(src, Operand(address)); 646 } storePtr(Register src,const Operand & dest)647 void storePtr(Register src, const Operand& dest) { movq(src, dest); } storePtr(Register src,AbsoluteAddress address)648 void storePtr(Register src, AbsoluteAddress address) { 649 if (X86Encoding::IsAddressImmediate(address.addr)) { 650 movq(src, Operand(address)); 651 } else { 652 ScratchRegisterScope scratch(asMasm()); 653 mov(ImmPtr(address.addr), scratch); 654 storePtr(src, Address(scratch, 0x0)); 655 } 656 } store32(Register src,AbsoluteAddress address)657 void store32(Register src, AbsoluteAddress address) { 658 if (X86Encoding::IsAddressImmediate(address.addr)) { 659 movl(src, Operand(address)); 660 } else { 661 ScratchRegisterScope scratch(asMasm()); 662 mov(ImmPtr(address.addr), scratch); 663 store32(src, Address(scratch, 0x0)); 664 } 665 } store16(Register src,AbsoluteAddress address)666 void store16(Register src, AbsoluteAddress address) { 667 if (X86Encoding::IsAddressImmediate(address.addr)) { 668 movw(src, Operand(address)); 669 } else { 670 ScratchRegisterScope scratch(asMasm()); 671 mov(ImmPtr(address.addr), scratch); 672 store16(src, Address(scratch, 0x0)); 673 } 674 } store64(Register64 src,Address address)675 void store64(Register64 src, Address address) { storePtr(src.reg, address); } store64(Register64 src,const BaseIndex & address)676 void store64(Register64 src, const BaseIndex& address) { 677 storePtr(src.reg, address); 678 } store64(Imm64 imm,Address address)679 void store64(Imm64 imm, Address address) { 680 storePtr(ImmWord(imm.value), address); 681 } store64(Imm64 imm,const BaseIndex & address)682 void store64(Imm64 imm, const BaseIndex& address) { 683 storePtr(ImmWord(imm.value), address); 684 } 685 template <typename S, typename T> store64Unaligned(const S & src,const T & dest)686 void store64Unaligned(const S& src, const T& dest) { 687 store64(src, dest); 688 } 689 splitTag(Register src,Register dest)690 void splitTag(Register src, Register dest) { 691 if (src != dest) { 692 movq(src, dest); 693 } 694 shrq(Imm32(JSVAL_TAG_SHIFT), dest); 695 } splitTag(const ValueOperand & operand,Register dest)696 void splitTag(const ValueOperand& operand, Register dest) { 697 splitTag(operand.valueReg(), dest); 698 } splitTag(const Operand & operand,Register dest)699 void splitTag(const Operand& operand, Register dest) { 700 movq(operand, dest); 701 shrq(Imm32(JSVAL_TAG_SHIFT), dest); 702 } splitTag(const Address & operand,Register dest)703 void splitTag(const Address& operand, Register dest) { 704 splitTag(Operand(operand), dest); 705 } splitTag(const BaseIndex & operand,Register dest)706 void splitTag(const BaseIndex& operand, Register dest) { 707 splitTag(Operand(operand), dest); 708 } 709 710 // Extracts the tag of a value and places it in tag. splitTagForTest(const ValueOperand & value,ScratchTagScope & tag)711 void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { 712 splitTag(value, tag); 713 } cmpTag(const ValueOperand & operand,ImmTag tag)714 void cmpTag(const ValueOperand& operand, ImmTag tag) { 715 ScratchTagScope reg(asMasm(), operand); 716 splitTagForTest(operand, reg); 717 cmp32(reg, tag); 718 } 719 testMagic(Condition cond,const ValueOperand & src)720 Condition testMagic(Condition cond, const ValueOperand& src) { 721 ScratchTagScope scratch(asMasm(), src); 722 splitTagForTest(src, scratch); 723 return testMagic(cond, scratch); 724 } testError(Condition cond,const ValueOperand & src)725 Condition testError(Condition cond, const ValueOperand& src) { 726 return testMagic(cond, src); 727 } 728 testNullSet(Condition cond,const ValueOperand & value,Register dest)729 void testNullSet(Condition cond, const ValueOperand& value, Register dest) { 730 cond = testNull(cond, value); 731 emitSet(cond, dest); 732 } 733 testObjectSet(Condition cond,const ValueOperand & value,Register dest)734 void testObjectSet(Condition cond, const ValueOperand& value, Register dest) { 735 cond = testObject(cond, value); 736 emitSet(cond, dest); 737 } 738 testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)739 void testUndefinedSet(Condition cond, const ValueOperand& value, 740 Register dest) { 741 cond = testUndefined(cond, value); 742 emitSet(cond, dest); 743 } 744 boxDouble(FloatRegister src,const ValueOperand & dest,FloatRegister)745 void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) { 746 vmovq(src, dest.valueReg()); 747 } boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)748 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) { 749 MOZ_ASSERT(src != dest.valueReg()); 750 boxValue(type, src, dest.valueReg()); 751 } 752 753 // Note that the |dest| register here may be ScratchReg, so we shouldn't 754 // use it. unboxInt32(const ValueOperand & src,Register dest)755 void unboxInt32(const ValueOperand& src, Register dest) { 756 movl(src.valueReg(), dest); 757 } unboxInt32(const Operand & src,Register dest)758 void unboxInt32(const Operand& src, Register dest) { movl(src, dest); } unboxInt32(const Address & src,Register dest)759 void unboxInt32(const Address& src, Register dest) { 760 unboxInt32(Operand(src), dest); 761 } unboxInt32(const BaseIndex & src,Register dest)762 void unboxInt32(const BaseIndex& src, Register dest) { 763 unboxInt32(Operand(src), dest); 764 } 765 template <typename T> unboxDouble(const T & src,FloatRegister dest)766 void unboxDouble(const T& src, FloatRegister dest) { 767 loadDouble(Operand(src), dest); 768 } 769 unboxArgObjMagic(const ValueOperand & src,Register dest)770 void unboxArgObjMagic(const ValueOperand& src, Register dest) { 771 unboxArgObjMagic(Operand(src.valueReg()), dest); 772 } unboxArgObjMagic(const Operand & src,Register dest)773 void unboxArgObjMagic(const Operand& src, Register dest) { 774 mov(ImmWord(0), dest); 775 } unboxArgObjMagic(const Address & src,Register dest)776 void unboxArgObjMagic(const Address& src, Register dest) { 777 unboxArgObjMagic(Operand(src), dest); 778 } 779 unboxBoolean(const ValueOperand & src,Register dest)780 void unboxBoolean(const ValueOperand& src, Register dest) { 781 movl(src.valueReg(), dest); 782 } unboxBoolean(const Operand & src,Register dest)783 void unboxBoolean(const Operand& src, Register dest) { movl(src, dest); } unboxBoolean(const Address & src,Register dest)784 void unboxBoolean(const Address& src, Register dest) { 785 unboxBoolean(Operand(src), dest); 786 } unboxBoolean(const BaseIndex & src,Register dest)787 void unboxBoolean(const BaseIndex& src, Register dest) { 788 unboxBoolean(Operand(src), dest); 789 } 790 unboxMagic(const ValueOperand & src,Register dest)791 void unboxMagic(const ValueOperand& src, Register dest) { 792 movl(src.valueReg(), dest); 793 } 794 unboxDouble(const ValueOperand & src,FloatRegister dest)795 void unboxDouble(const ValueOperand& src, FloatRegister dest) { 796 vmovq(src.valueReg(), dest); 797 } 798 notBoolean(const ValueOperand & val)799 void notBoolean(const ValueOperand& val) { xorq(Imm32(1), val.valueReg()); } 800 unboxNonDouble(const ValueOperand & src,Register dest,JSValueType type)801 void unboxNonDouble(const ValueOperand& src, Register dest, 802 JSValueType type) { 803 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 804 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 805 movl(src.valueReg(), dest); 806 return; 807 } 808 if (src.valueReg() == dest) { 809 ScratchRegisterScope scratch(asMasm()); 810 mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch); 811 xorq(scratch, dest); 812 } else { 813 mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest); 814 xorq(src.valueReg(), dest); 815 } 816 } unboxNonDouble(const Operand & src,Register dest,JSValueType type)817 void unboxNonDouble(const Operand& src, Register dest, JSValueType type) { 818 MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE); 819 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 820 movl(src, dest); 821 return; 822 } 823 // Explicitly permits |dest| to be used in |src|. 824 ScratchRegisterScope scratch(asMasm()); 825 MOZ_ASSERT(dest != scratch); 826 if (src.containsReg(dest)) { 827 mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch); 828 // If src is already a register, then src and dest are the same 829 // thing and we don't need to move anything into dest. 830 if (src.kind() != Operand::REG) { 831 movq(src, dest); 832 } 833 xorq(scratch, dest); 834 } else { 835 mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest); 836 xorq(src, dest); 837 } 838 } unboxNonDouble(const Address & src,Register dest,JSValueType type)839 void unboxNonDouble(const Address& src, Register dest, JSValueType type) { 840 unboxNonDouble(Operand(src), dest, type); 841 } unboxNonDouble(const BaseIndex & src,Register dest,JSValueType type)842 void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) { 843 unboxNonDouble(Operand(src), dest, type); 844 } 845 unboxString(const ValueOperand & src,Register dest)846 void unboxString(const ValueOperand& src, Register dest) { 847 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 848 } unboxString(const Operand & src,Register dest)849 void unboxString(const Operand& src, Register dest) { 850 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 851 } unboxString(const Address & src,Register dest)852 void unboxString(const Address& src, Register dest) { 853 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 854 } 855 unboxSymbol(const ValueOperand & src,Register dest)856 void unboxSymbol(const ValueOperand& src, Register dest) { 857 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 858 } unboxSymbol(const Operand & src,Register dest)859 void unboxSymbol(const Operand& src, Register dest) { 860 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 861 } 862 unboxBigInt(const ValueOperand & src,Register dest)863 void unboxBigInt(const ValueOperand& src, Register dest) { 864 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 865 } unboxBigInt(const Operand & src,Register dest)866 void unboxBigInt(const Operand& src, Register dest) { 867 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 868 } unboxBigInt(const Address & src,Register dest)869 void unboxBigInt(const Address& src, Register dest) { 870 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 871 } 872 unboxObject(const ValueOperand & src,Register dest)873 void unboxObject(const ValueOperand& src, Register dest) { 874 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 875 } unboxObject(const Operand & src,Register dest)876 void unboxObject(const Operand& src, Register dest) { 877 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 878 } unboxObject(const Address & src,Register dest)879 void unboxObject(const Address& src, Register dest) { 880 unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT); 881 } unboxObject(const BaseIndex & src,Register dest)882 void unboxObject(const BaseIndex& src, Register dest) { 883 unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT); 884 } 885 886 template <typename T> unboxObjectOrNull(const T & src,Register dest)887 void unboxObjectOrNull(const T& src, Register dest) { 888 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 889 ScratchRegisterScope scratch(asMasm()); 890 mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch); 891 andq(scratch, dest); 892 } 893 894 // This should only be used for GC barrier code, to unbox a GC thing Value. 895 // It's fine there because we don't depend on the actual Value type (all Cells 896 // are treated the same way). In almost all other cases this would be 897 // Spectre-unsafe - use unboxNonDouble and friends instead. unboxGCThingForGCBarrier(const Address & src,Register dest)898 void unboxGCThingForGCBarrier(const Address& src, Register dest) { 899 movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest); 900 andq(Operand(src), dest); 901 } unboxGCThingForGCBarrier(const ValueOperand & src,Register dest)902 void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { 903 MOZ_ASSERT(src.valueReg() != dest); 904 movq(ImmWord(JS::detail::ValueGCThingPayloadMask), dest); 905 andq(src.valueReg(), dest); 906 } 907 908 inline void fallibleUnboxPtrImpl(const Operand& src, Register dest, 909 JSValueType type, Label* fail); 910 911 // Extended unboxing API. If the payload is already in a register, returns 912 // that register. Otherwise, provides a move to the given scratch register, 913 // and returns that. extractObject(const Address & address,Register scratch)914 [[nodiscard]] Register extractObject(const Address& address, 915 Register scratch) { 916 MOZ_ASSERT(scratch != ScratchReg); 917 unboxObject(address, scratch); 918 return scratch; 919 } extractObject(const ValueOperand & value,Register scratch)920 [[nodiscard]] Register extractObject(const ValueOperand& value, 921 Register scratch) { 922 MOZ_ASSERT(scratch != ScratchReg); 923 unboxObject(value, scratch); 924 return scratch; 925 } extractSymbol(const ValueOperand & value,Register scratch)926 [[nodiscard]] Register extractSymbol(const ValueOperand& value, 927 Register scratch) { 928 MOZ_ASSERT(scratch != ScratchReg); 929 unboxSymbol(value, scratch); 930 return scratch; 931 } extractInt32(const ValueOperand & value,Register scratch)932 [[nodiscard]] Register extractInt32(const ValueOperand& value, 933 Register scratch) { 934 MOZ_ASSERT(scratch != ScratchReg); 935 unboxInt32(value, scratch); 936 return scratch; 937 } extractBoolean(const ValueOperand & value,Register scratch)938 [[nodiscard]] Register extractBoolean(const ValueOperand& value, 939 Register scratch) { 940 MOZ_ASSERT(scratch != ScratchReg); 941 unboxBoolean(value, scratch); 942 return scratch; 943 } extractTag(const Address & address,Register scratch)944 [[nodiscard]] Register extractTag(const Address& address, Register scratch) { 945 MOZ_ASSERT(scratch != ScratchReg); 946 loadPtr(address, scratch); 947 splitTag(scratch, scratch); 948 return scratch; 949 } extractTag(const ValueOperand & value,Register scratch)950 [[nodiscard]] Register extractTag(const ValueOperand& value, 951 Register scratch) { 952 MOZ_ASSERT(scratch != ScratchReg); 953 splitTag(value, scratch); 954 return scratch; 955 } 956 957 inline void unboxValue(const ValueOperand& src, AnyRegister dest, 958 JSValueType type); 959 960 // These two functions use the low 32-bits of the full value register. boolValueToDouble(const ValueOperand & operand,FloatRegister dest)961 void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) { 962 convertInt32ToDouble(operand.valueReg(), dest); 963 } int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)964 void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) { 965 convertInt32ToDouble(operand.valueReg(), dest); 966 } 967 boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)968 void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 969 convertInt32ToFloat32(operand.valueReg(), dest); 970 } int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)971 void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 972 convertInt32ToFloat32(operand.valueReg(), dest); 973 } 974 975 void loadConstantDouble(double d, FloatRegister dest); 976 void loadConstantFloat32(float f, FloatRegister dest); 977 978 void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest); 979 void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest); 980 void vpaddbSimd128(const SimdConstant& v, FloatRegister lhs, 981 FloatRegister dest); 982 void vpaddwSimd128(const SimdConstant& v, FloatRegister lhs, 983 FloatRegister dest); 984 void vpadddSimd128(const SimdConstant& v, FloatRegister lhs, 985 FloatRegister dest); 986 void vpaddqSimd128(const SimdConstant& v, FloatRegister lhs, 987 FloatRegister dest); 988 void vpsubbSimd128(const SimdConstant& v, FloatRegister lhs, 989 FloatRegister dest); 990 void vpsubwSimd128(const SimdConstant& v, FloatRegister lhs, 991 FloatRegister dest); 992 void vpsubdSimd128(const SimdConstant& v, FloatRegister lhs, 993 FloatRegister dest); 994 void vpsubqSimd128(const SimdConstant& v, FloatRegister lhs, 995 FloatRegister dest); 996 void vpmullwSimd128(const SimdConstant& v, FloatRegister lhs, 997 FloatRegister dest); 998 void vpmulldSimd128(const SimdConstant& v, FloatRegister lhs, 999 FloatRegister dest); 1000 void vpaddsbSimd128(const SimdConstant& v, FloatRegister lhs, 1001 FloatRegister dest); 1002 void vpaddusbSimd128(const SimdConstant& v, FloatRegister lhs, 1003 FloatRegister dest); 1004 void vpaddswSimd128(const SimdConstant& v, FloatRegister lhs, 1005 FloatRegister dest); 1006 void vpadduswSimd128(const SimdConstant& v, FloatRegister lhs, 1007 FloatRegister dest); 1008 void vpsubsbSimd128(const SimdConstant& v, FloatRegister lhs, 1009 FloatRegister dest); 1010 void vpsubusbSimd128(const SimdConstant& v, FloatRegister lhs, 1011 FloatRegister dest); 1012 void vpsubswSimd128(const SimdConstant& v, FloatRegister lhs, 1013 FloatRegister dest); 1014 void vpsubuswSimd128(const SimdConstant& v, FloatRegister lhs, 1015 FloatRegister dest); 1016 void vpminsbSimd128(const SimdConstant& v, FloatRegister lhs, 1017 FloatRegister dest); 1018 void vpminubSimd128(const SimdConstant& v, FloatRegister lhs, 1019 FloatRegister dest); 1020 void vpminswSimd128(const SimdConstant& v, FloatRegister lhs, 1021 FloatRegister dest); 1022 void vpminuwSimd128(const SimdConstant& v, FloatRegister lhs, 1023 FloatRegister dest); 1024 void vpminsdSimd128(const SimdConstant& v, FloatRegister lhs, 1025 FloatRegister dest); 1026 void vpminudSimd128(const SimdConstant& v, FloatRegister lhs, 1027 FloatRegister dest); 1028 void vpmaxsbSimd128(const SimdConstant& v, FloatRegister lhs, 1029 FloatRegister dest); 1030 void vpmaxubSimd128(const SimdConstant& v, FloatRegister lhs, 1031 FloatRegister dest); 1032 void vpmaxswSimd128(const SimdConstant& v, FloatRegister lhs, 1033 FloatRegister dest); 1034 void vpmaxuwSimd128(const SimdConstant& v, FloatRegister lhs, 1035 FloatRegister dest); 1036 void vpmaxsdSimd128(const SimdConstant& v, FloatRegister lhs, 1037 FloatRegister dest); 1038 void vpmaxudSimd128(const SimdConstant& v, FloatRegister lhs, 1039 FloatRegister dest); 1040 void vpandSimd128(const SimdConstant& v, FloatRegister lhs, 1041 FloatRegister dest); 1042 void vpxorSimd128(const SimdConstant& v, FloatRegister lhs, 1043 FloatRegister dest); 1044 void vporSimd128(const SimdConstant& v, FloatRegister lhs, 1045 FloatRegister dest); 1046 void vaddpsSimd128(const SimdConstant& v, FloatRegister lhs, 1047 FloatRegister dest); 1048 void vaddpdSimd128(const SimdConstant& v, FloatRegister lhs, 1049 FloatRegister dest); 1050 void vsubpsSimd128(const SimdConstant& v, FloatRegister lhs, 1051 FloatRegister dest); 1052 void vsubpdSimd128(const SimdConstant& v, FloatRegister lhs, 1053 FloatRegister dest); 1054 void vdivpsSimd128(const SimdConstant& v, FloatRegister lhs, 1055 FloatRegister dest); 1056 void vdivpdSimd128(const SimdConstant& v, FloatRegister lhs, 1057 FloatRegister dest); 1058 void vmulpsSimd128(const SimdConstant& v, FloatRegister lhs, 1059 FloatRegister dest); 1060 void vmulpdSimd128(const SimdConstant& v, FloatRegister lhs, 1061 FloatRegister dest); 1062 void vpacksswbSimd128(const SimdConstant& v, FloatRegister lhs, 1063 FloatRegister dest); 1064 void vpackuswbSimd128(const SimdConstant& v, FloatRegister lhs, 1065 FloatRegister dest); 1066 void vpackssdwSimd128(const SimdConstant& v, FloatRegister lhs, 1067 FloatRegister dest); 1068 void vpackusdwSimd128(const SimdConstant& v, FloatRegister lhs, 1069 FloatRegister dest); 1070 void vpshufbSimd128(const SimdConstant& v, FloatRegister lhs, 1071 FloatRegister dest); 1072 void vptestSimd128(const SimdConstant& v, FloatRegister lhs); 1073 void vpmaddwdSimd128(const SimdConstant& v, FloatRegister lhs, 1074 FloatRegister dest); 1075 void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister lhs, 1076 FloatRegister dest); 1077 void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister lhs, 1078 FloatRegister dest); 1079 void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister lhs, 1080 FloatRegister dest); 1081 void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister lhs, 1082 FloatRegister dest); 1083 void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister lhs, 1084 FloatRegister dest); 1085 void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister lhs, 1086 FloatRegister dest); 1087 void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1088 FloatRegister dest); 1089 void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1090 FloatRegister dest); 1091 void vcmpltpsSimd128(const SimdConstant& v, FloatRegister lhs, 1092 FloatRegister dest); 1093 void vcmplepsSimd128(const SimdConstant& v, FloatRegister lhs, 1094 FloatRegister dest); 1095 void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1096 FloatRegister dest); 1097 void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1098 FloatRegister dest); 1099 void vcmpltpdSimd128(const SimdConstant& v, FloatRegister lhs, 1100 FloatRegister dest); 1101 void vcmplepdSimd128(const SimdConstant& v, FloatRegister lhs, 1102 FloatRegister dest); 1103 void vpmaddubswSimd128(const SimdConstant& v, FloatRegister lhs, 1104 FloatRegister dest); 1105 1106 public: testInt32Truthy(bool truthy,const ValueOperand & operand)1107 Condition testInt32Truthy(bool truthy, const ValueOperand& operand) { 1108 test32(operand.valueReg(), operand.valueReg()); 1109 return truthy ? NonZero : Zero; 1110 } 1111 Condition testStringTruthy(bool truthy, const ValueOperand& value); 1112 Condition testBigIntTruthy(bool truthy, const ValueOperand& value); 1113 1114 template <typename T> 1115 inline void loadInt32OrDouble(const T& src, FloatRegister dest); 1116 1117 template <typename T> loadUnboxedValue(const T & src,MIRType type,AnyRegister dest)1118 void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { 1119 if (dest.isFloat()) { 1120 loadInt32OrDouble(src, dest.fpu()); 1121 } else { 1122 unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type)); 1123 } 1124 } 1125 1126 template <typename T> storeUnboxedPayload(ValueOperand value,T address,size_t nbytes,JSValueType type)1127 void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, 1128 JSValueType type) { 1129 switch (nbytes) { 1130 case 8: { 1131 ScratchRegisterScope scratch(asMasm()); 1132 unboxNonDouble(value, scratch, type); 1133 storePtr(scratch, address); 1134 if (type == JSVAL_TYPE_OBJECT) { 1135 // Ideally we would call unboxObjectOrNull, but we need an extra 1136 // scratch register for that. So unbox as object, then clear the 1137 // object-or-null bit. 1138 mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch); 1139 andq(scratch, Operand(address)); 1140 } 1141 return; 1142 } 1143 case 4: 1144 store32(value.valueReg(), address); 1145 return; 1146 case 1: 1147 store8(value.valueReg(), address); 1148 return; 1149 default: 1150 MOZ_CRASH("Bad payload width"); 1151 } 1152 } 1153 loadInstructionPointerAfterCall(Register dest)1154 void loadInstructionPointerAfterCall(Register dest) { 1155 loadPtr(Address(StackPointer, 0x0), dest); 1156 } 1157 1158 // Checks whether a double is representable as a 64-bit integer. If so, the 1159 // integer is written to the output register. Otherwise, a bailout is taken to 1160 // the given snapshot. This function overwrites the scratch float register. 1161 void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail, 1162 bool negativeZeroCheck = true); 1163 convertUInt32ToDouble(Register src,FloatRegister dest)1164 void convertUInt32ToDouble(Register src, FloatRegister dest) { 1165 // Zero the output register to break dependencies, see convertInt32ToDouble. 1166 zeroDouble(dest); 1167 1168 vcvtsq2sd(src, dest, dest); 1169 } 1170 convertUInt32ToFloat32(Register src,FloatRegister dest)1171 void convertUInt32ToFloat32(Register src, FloatRegister dest) { 1172 // Zero the output register to break dependencies, see convertInt32ToDouble. 1173 zeroDouble(dest); 1174 1175 vcvtsq2ss(src, dest, dest); 1176 } 1177 1178 inline void incrementInt32Value(const Address& addr); 1179 1180 inline void ensureDouble(const ValueOperand& source, FloatRegister dest, 1181 Label* failure); 1182 1183 public: 1184 void handleFailureWithHandlerTail(Label* profilerExitTail); 1185 1186 // Instrumentation for entering and leaving the profiler. 1187 void profilerEnterFrame(Register framePtr, Register scratch); 1188 void profilerExitFrame(); 1189 }; 1190 1191 using MacroAssemblerSpecific = MacroAssemblerX64; 1192 1193 } // namespace jit 1194 } // namespace js 1195 1196 #endif /* jit_x64_MacroAssembler_x64_h */ 1197