MacroAssembler-x86.h (45502B)
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_x86_MacroAssembler_x86_h 8 #define jit_x86_MacroAssembler_x86_h 9 10 #include "jit/JitOptions.h" 11 #include "jit/MoveResolver.h" 12 #include "jit/x86-shared/MacroAssembler-x86-shared.h" 13 #include "js/HeapAPI.h" 14 #include "wasm/WasmBuiltins.h" 15 #include "wasm/WasmCodegenTypes.h" 16 17 using js::wasm::FaultingCodeOffsetPair; 18 19 namespace js { 20 namespace jit { 21 22 // See documentation for ScratchTagScope and ScratchTagScopeRelease in 23 // MacroAssembler-x64.h. 24 25 class ScratchTagScope { 26 const ValueOperand& v_; 27 28 public: 29 ScratchTagScope(MacroAssembler&, const ValueOperand& v) : v_(v) {} 30 operator Register() { return v_.typeReg(); } 31 void release() {} 32 void reacquire() {} 33 }; 34 35 class ScratchTagScopeRelease { 36 public: 37 explicit ScratchTagScopeRelease(ScratchTagScope*) {} 38 }; 39 40 class MacroAssemblerX86 : public MacroAssemblerX86Shared { 41 private: 42 // Perform a downcast. Should be removed by Bug 996602. 43 MacroAssembler& asMasm(); 44 const MacroAssembler& asMasm() const; 45 46 protected: 47 MoveResolver moveResolver_; 48 49 private: 50 Operand payloadOfAfterStackPush(const Address& address) { 51 // If we are basing off %esp, the address will be invalid after the 52 // first push. 53 if (address.base == StackPointer) { 54 return Operand(address.base, address.offset + 4); 55 } 56 return payloadOf(address); 57 } 58 Operand payloadOfAfterStackPush(const BaseIndex& address) { 59 // If we are basing off %esp, the address will be invalid after the 60 // first push. 61 if (address.base == StackPointer) { 62 return Operand(address.base, address.index, address.scale, 63 address.offset + 4); 64 } 65 return payloadOf(address); 66 } 67 Operand payloadOf(const Address& address) { 68 return Operand(address.base, address.offset); 69 } 70 Operand payloadOf(const BaseIndex& address) { 71 return Operand(address.base, address.index, address.scale, address.offset); 72 } 73 Operand tagOf(const Address& address) { 74 return Operand(address.base, address.offset + 4); 75 } 76 Operand tagOf(const BaseIndex& address) { 77 return Operand(address.base, address.index, address.scale, 78 address.offset + 4); 79 } 80 81 void setupABICall(uint32_t args); 82 83 void vpPatchOpSimd128(const SimdConstant& v, FloatRegister reg, 84 void (X86Encoding::BaseAssemblerX86::*op)( 85 const void* address, 86 X86Encoding::XMMRegisterID srcId, 87 X86Encoding::XMMRegisterID destId)) { 88 vpPatchOpSimd128(v, reg, reg, op); 89 } 90 91 void vpPatchOpSimd128(const SimdConstant& v, FloatRegister lhs, 92 FloatRegister dest, 93 void (X86Encoding::BaseAssemblerX86::*op)( 94 const void* address, 95 X86Encoding::XMMRegisterID srcId, 96 X86Encoding::XMMRegisterID destId)); 97 98 void vpPatchOpSimd128(const SimdConstant& v, FloatRegister reg, 99 size_t (X86Encoding::BaseAssemblerX86::*op)( 100 const void* address, 101 X86Encoding::XMMRegisterID srcId, 102 X86Encoding::XMMRegisterID destId)) { 103 vpPatchOpSimd128(v, reg, reg, op); 104 } 105 106 void vpPatchOpSimd128(const SimdConstant& v, FloatRegister lhs, 107 FloatRegister dest, 108 size_t (X86Encoding::BaseAssemblerX86::*op)( 109 const void* address, 110 X86Encoding::XMMRegisterID srcId, 111 X86Encoding::XMMRegisterID destId)); 112 113 public: 114 using MacroAssemblerX86Shared::call; 115 using MacroAssemblerX86Shared::load32; 116 using MacroAssemblerX86Shared::store16; 117 using MacroAssemblerX86Shared::store32; 118 119 MacroAssemblerX86() {} 120 121 // The buffer is about to be linked, make sure any constant pools or excess 122 // bookkeeping has been flushed to the instruction stream. 123 void finish(); 124 125 ///////////////////////////////////////////////////////////////// 126 // X86-specific interface. 127 ///////////////////////////////////////////////////////////////// 128 129 Operand ToPayload(Operand base) { return base; } 130 Address ToPayload(Address base) { return base; } 131 BaseIndex ToPayload(BaseIndex base) { return base; } 132 Operand ToType(Operand base) { 133 switch (base.kind()) { 134 case Operand::MEM_REG_DISP: 135 return Operand(Register::FromCode(base.base()), 136 base.disp() + sizeof(void*)); 137 138 case Operand::MEM_SCALE: 139 return Operand(Register::FromCode(base.base()), 140 Register::FromCode(base.index()), base.scale(), 141 base.disp() + sizeof(void*)); 142 143 default: 144 MOZ_CRASH("unexpected operand kind"); 145 } 146 } 147 Address ToType(Address base) { return ToType(Operand(base)).toAddress(); } 148 BaseIndex ToType(BaseIndex base) { 149 return ToType(Operand(base)).toBaseIndex(); 150 } 151 152 template <typename T> 153 void add64FromMemory(const T& address, Register64 dest) { 154 addl(Operand(LowWord(address)), dest.low); 155 adcl(Operand(HighWord(address)), dest.high); 156 } 157 template <typename T> 158 void sub64FromMemory(const T& address, Register64 dest) { 159 subl(Operand(LowWord(address)), dest.low); 160 sbbl(Operand(HighWord(address)), dest.high); 161 } 162 template <typename T> 163 void and64FromMemory(const T& address, Register64 dest) { 164 andl(Operand(LowWord(address)), dest.low); 165 andl(Operand(HighWord(address)), dest.high); 166 } 167 template <typename T> 168 void or64FromMemory(const T& address, Register64 dest) { 169 orl(Operand(LowWord(address)), dest.low); 170 orl(Operand(HighWord(address)), dest.high); 171 } 172 template <typename T> 173 void xor64FromMemory(const T& address, Register64 dest) { 174 xorl(Operand(LowWord(address)), dest.low); 175 xorl(Operand(HighWord(address)), dest.high); 176 } 177 178 template <typename T1, typename T2> 179 inline void cmp64SetAliased(Condition cond, T1 lhs, T2 rhs, Register dest); 180 181 template <typename T1, typename T2> 182 inline void cmp64SetNonAliased(Condition cond, T1 lhs, T2 rhs, Register dest); 183 184 template <typename T1, typename T2> 185 inline void branch64Impl(Condition cond, T1 lhs, T2 rhs, Label* success, 186 Label* fail); 187 188 ///////////////////////////////////////////////////////////////// 189 // X86/X64-common interface. 190 ///////////////////////////////////////////////////////////////// 191 void storeValue(ValueOperand val, Operand dest) { 192 movl(val.payloadReg(), ToPayload(dest)); 193 movl(val.typeReg(), ToType(dest)); 194 } 195 void storeValue(ValueOperand val, const Address& dest) { 196 storeValue(val, Operand(dest)); 197 } 198 template <typename T> 199 void storeValue(JSValueType type, Register reg, const T& dest) { 200 storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest)); 201 storePayload(reg, Operand(dest)); 202 } 203 template <typename T> 204 void storeValue(const Value& val, const T& dest) { 205 storeTypeTag(ImmTag(val.toNunboxTag()), Operand(dest)); 206 storePayload(val, Operand(dest)); 207 } 208 void storeValue(ValueOperand val, BaseIndex dest) { 209 storeValue(val, Operand(dest)); 210 } 211 void storeValue(const Address& src, const Address& dest, Register temp) { 212 MOZ_ASSERT(src.base != temp); 213 MOZ_ASSERT(dest.base != temp); 214 215 load32(ToType(src), temp); 216 store32(temp, ToType(dest)); 217 218 load32(ToPayload(src), temp); 219 store32(temp, ToPayload(dest)); 220 } 221 void storePrivateValue(Register src, const Address& dest) { 222 store32(Imm32(0), ToType(dest)); 223 store32(src, ToPayload(dest)); 224 } 225 void storePrivateValue(ImmGCPtr imm, const Address& dest) { 226 store32(Imm32(0), ToType(dest)); 227 movl(imm, Operand(ToPayload(dest))); 228 } 229 void loadValue(Operand src, ValueOperand val) { 230 Operand payload = ToPayload(src); 231 Operand type = ToType(src); 232 233 // Ensure that loading the payload does not erase the pointer to the 234 // Value in memory or the index. 235 Register baseReg = Register::FromCode(src.base()); 236 Register indexReg = (src.kind() == Operand::MEM_SCALE) 237 ? Register::FromCode(src.index()) 238 : InvalidReg; 239 240 // If we have a BaseIndex that uses both result registers, first compute 241 // the address and then load the Value from there. 242 if ((baseReg == val.payloadReg() && indexReg == val.typeReg()) || 243 (baseReg == val.typeReg() && indexReg == val.payloadReg())) { 244 computeEffectiveAddress(src, val.scratchReg()); 245 loadValue(Address(val.scratchReg(), 0), val); 246 return; 247 } 248 249 if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) { 250 MOZ_ASSERT(baseReg != val.typeReg()); 251 MOZ_ASSERT(indexReg != val.typeReg()); 252 253 movl(type, val.typeReg()); 254 movl(payload, val.payloadReg()); 255 } else { 256 MOZ_ASSERT(baseReg != val.payloadReg()); 257 MOZ_ASSERT(indexReg != val.payloadReg()); 258 259 movl(payload, val.payloadReg()); 260 movl(type, val.typeReg()); 261 } 262 } 263 void loadValue(Address src, ValueOperand val) { 264 loadValue(Operand(src), val); 265 } 266 void loadValue(const BaseIndex& src, ValueOperand val) { 267 loadValue(Operand(src), val); 268 } 269 void loadUnalignedValue(const Address& src, ValueOperand dest) { 270 loadValue(src, dest); 271 } 272 void tagValue(JSValueType type, Register payload, ValueOperand dest) { 273 boxNonDouble(type, payload, dest); 274 } 275 void pushValue(ValueOperand val) { 276 push(val.typeReg()); 277 push(val.payloadReg()); 278 } 279 void popValue(ValueOperand val) { 280 pop(val.payloadReg()); 281 pop(val.typeReg()); 282 } 283 void pushValue(const Value& val) { 284 push(Imm32(val.toNunboxTag())); 285 if (val.isGCThing()) { 286 push(ImmGCPtr(val.toGCThing())); 287 } else { 288 push(Imm32(val.toNunboxPayload())); 289 } 290 } 291 void pushValue(JSValueType type, Register reg) { 292 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); 293 push(reg); 294 } 295 void pushValue(const Address& addr) { 296 push(tagOf(addr)); 297 push(payloadOfAfterStackPush(addr)); 298 } 299 void pushValue(const BaseIndex& addr, Register scratch) { 300 push(tagOf(addr)); 301 push(payloadOfAfterStackPush(addr)); 302 } 303 void push64(Register64 src) { 304 push(src.high); 305 push(src.low); 306 } 307 void pop64(Register64 dest) { 308 pop(dest.low); 309 pop(dest.high); 310 } 311 void storePayload(const Value& val, Operand dest) { 312 if (val.isGCThing()) { 313 movl(ImmGCPtr(val.toGCThing()), ToPayload(dest)); 314 } else { 315 movl(Imm32(val.toNunboxPayload()), ToPayload(dest)); 316 } 317 } 318 void storePayload(Register src, Operand dest) { movl(src, ToPayload(dest)); } 319 void storeTypeTag(ImmTag tag, Operand dest) { movl(tag, ToType(dest)); } 320 321 void movePtr(Register src, Register dest) { movl(src, dest); } 322 void movePtr(Register src, const Operand& dest) { movl(src, dest); } 323 324 void splitTagForTest(const ValueOperand& value, ScratchTagScope& tag) { 325 MOZ_ASSERT(value.typeReg() == tag); 326 } 327 328 Condition testUndefined(Condition cond, Register tag) { 329 MOZ_ASSERT(cond == Equal || cond == NotEqual); 330 cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 331 return cond; 332 } 333 Condition testBoolean(Condition cond, Register tag) { 334 MOZ_ASSERT(cond == Equal || cond == NotEqual); 335 cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 336 return cond; 337 } 338 Condition testInt32(Condition cond, Register tag) { 339 MOZ_ASSERT(cond == Equal || cond == NotEqual); 340 cmp32(tag, ImmTag(JSVAL_TAG_INT32)); 341 return cond; 342 } 343 Condition testDouble(Condition cond, Register tag) { 344 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 345 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 346 cmp32(tag, ImmTag(JSVAL_TAG_CLEAR)); 347 return actual; 348 } 349 Condition testNull(Condition cond, Register tag) { 350 MOZ_ASSERT(cond == Equal || cond == NotEqual); 351 cmp32(tag, ImmTag(JSVAL_TAG_NULL)); 352 return cond; 353 } 354 Condition testString(Condition cond, Register tag) { 355 MOZ_ASSERT(cond == Equal || cond == NotEqual); 356 cmp32(tag, ImmTag(JSVAL_TAG_STRING)); 357 return cond; 358 } 359 Condition testSymbol(Condition cond, Register tag) { 360 MOZ_ASSERT(cond == Equal || cond == NotEqual); 361 cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL)); 362 return cond; 363 } 364 Condition testBigInt(Condition cond, Register tag) { 365 MOZ_ASSERT(cond == Equal || cond == NotEqual); 366 cmp32(tag, ImmTag(JSVAL_TAG_BIGINT)); 367 return cond; 368 } 369 Condition testObject(Condition cond, Register tag) { 370 MOZ_ASSERT(cond == Equal || cond == NotEqual); 371 cmp32(tag, ImmTag(JSVAL_TAG_OBJECT)); 372 return cond; 373 } 374 Condition testNumber(Condition cond, Register tag) { 375 MOZ_ASSERT(cond == Equal || cond == NotEqual); 376 cmp32(tag, ImmTag(JS::detail::ValueUpperInclNumberTag)); 377 return cond == Equal ? BelowOrEqual : Above; 378 } 379 Condition testGCThing(Condition cond, Register tag) { 380 MOZ_ASSERT(cond == Equal || cond == NotEqual); 381 cmp32(tag, ImmTag(JS::detail::ValueLowerInclGCThingTag)); 382 return cond == Equal ? AboveOrEqual : Below; 383 } 384 Condition testGCThing(Condition cond, const Address& address) { 385 MOZ_ASSERT(cond == Equal || cond == NotEqual); 386 cmp32(tagOf(address), ImmTag(JS::detail::ValueLowerInclGCThingTag)); 387 return cond == Equal ? AboveOrEqual : Below; 388 } 389 Condition testMagic(Condition cond, const Address& address) { 390 MOZ_ASSERT(cond == Equal || cond == NotEqual); 391 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 392 return cond; 393 } 394 Condition testMagic(Condition cond, Register tag) { 395 MOZ_ASSERT(cond == Equal || cond == NotEqual); 396 cmp32(tag, ImmTag(JSVAL_TAG_MAGIC)); 397 return cond; 398 } 399 Condition testMagic(Condition cond, const Operand& operand) { 400 MOZ_ASSERT(cond == Equal || cond == NotEqual); 401 cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC)); 402 return cond; 403 } 404 Condition testPrimitive(Condition cond, Register tag) { 405 MOZ_ASSERT(cond == Equal || cond == NotEqual); 406 cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag)); 407 return cond == Equal ? Below : AboveOrEqual; 408 } 409 Condition testError(Condition cond, Register tag) { 410 return testMagic(cond, tag); 411 } 412 Condition testBoolean(Condition cond, const Address& address) { 413 MOZ_ASSERT(cond == Equal || cond == NotEqual); 414 cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN)); 415 return cond; 416 } 417 Condition testInt32(Condition cond, const Operand& operand) { 418 MOZ_ASSERT(cond == Equal || cond == NotEqual); 419 cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32)); 420 return cond; 421 } 422 Condition testInt32(Condition cond, const Address& address) { 423 MOZ_ASSERT(cond == Equal || cond == NotEqual); 424 return testInt32(cond, Operand(address)); 425 } 426 Condition testObject(Condition cond, const Operand& operand) { 427 MOZ_ASSERT(cond == Equal || cond == NotEqual); 428 cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT)); 429 return cond; 430 } 431 Condition testObject(Condition cond, const Address& address) { 432 MOZ_ASSERT(cond == Equal || cond == NotEqual); 433 return testObject(cond, Operand(address)); 434 } 435 Condition testDouble(Condition cond, const Operand& operand) { 436 MOZ_ASSERT(cond == Equal || cond == NotEqual); 437 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 438 cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR)); 439 return actual; 440 } 441 Condition testDouble(Condition cond, const Address& address) { 442 MOZ_ASSERT(cond == Equal || cond == NotEqual); 443 return testDouble(cond, Operand(address)); 444 } 445 446 Condition testUndefined(Condition cond, const Operand& operand) { 447 MOZ_ASSERT(cond == Equal || cond == NotEqual); 448 cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); 449 return cond; 450 } 451 Condition testUndefined(Condition cond, const Address& addr) { 452 return testUndefined(cond, Operand(addr)); 453 } 454 Condition testNull(Condition cond, const Operand& operand) { 455 MOZ_ASSERT(cond == Equal || cond == NotEqual); 456 cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL)); 457 return cond; 458 } 459 Condition testNull(Condition cond, const Address& addr) { 460 return testNull(cond, Operand(addr)); 461 } 462 463 Condition testUndefined(Condition cond, const ValueOperand& value) { 464 return testUndefined(cond, value.typeReg()); 465 } 466 Condition testBoolean(Condition cond, const ValueOperand& value) { 467 return testBoolean(cond, value.typeReg()); 468 } 469 Condition testInt32(Condition cond, const ValueOperand& value) { 470 return testInt32(cond, value.typeReg()); 471 } 472 Condition testDouble(Condition cond, const ValueOperand& value) { 473 return testDouble(cond, value.typeReg()); 474 } 475 Condition testNull(Condition cond, const ValueOperand& value) { 476 return testNull(cond, value.typeReg()); 477 } 478 Condition testString(Condition cond, const ValueOperand& value) { 479 return testString(cond, value.typeReg()); 480 } 481 Condition testSymbol(Condition cond, const ValueOperand& value) { 482 return testSymbol(cond, value.typeReg()); 483 } 484 Condition testBigInt(Condition cond, const ValueOperand& value) { 485 return testBigInt(cond, value.typeReg()); 486 } 487 Condition testObject(Condition cond, const ValueOperand& value) { 488 return testObject(cond, value.typeReg()); 489 } 490 Condition testMagic(Condition cond, const ValueOperand& value) { 491 return testMagic(cond, value.typeReg()); 492 } 493 Condition testError(Condition cond, const ValueOperand& value) { 494 return testMagic(cond, value); 495 } 496 Condition testNumber(Condition cond, const ValueOperand& value) { 497 return testNumber(cond, value.typeReg()); 498 } 499 Condition testGCThing(Condition cond, const ValueOperand& value) { 500 return testGCThing(cond, value.typeReg()); 501 } 502 Condition testPrimitive(Condition cond, const ValueOperand& value) { 503 return testPrimitive(cond, value.typeReg()); 504 } 505 506 Condition testUndefined(Condition cond, const BaseIndex& address) { 507 MOZ_ASSERT(cond == Equal || cond == NotEqual); 508 cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); 509 return cond; 510 } 511 Condition testNull(Condition cond, const BaseIndex& address) { 512 MOZ_ASSERT(cond == Equal || cond == NotEqual); 513 cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL)); 514 return cond; 515 } 516 Condition testBoolean(Condition cond, const BaseIndex& address) { 517 MOZ_ASSERT(cond == Equal || cond == NotEqual); 518 cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); 519 return cond; 520 } 521 Condition testString(Condition cond, const Address& address) { 522 MOZ_ASSERT(cond == Equal || cond == NotEqual); 523 cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING)); 524 return cond; 525 } 526 Condition testString(Condition cond, const BaseIndex& address) { 527 MOZ_ASSERT(cond == Equal || cond == NotEqual); 528 cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING)); 529 return cond; 530 } 531 Condition testSymbol(Condition cond, const Address& address) { 532 MOZ_ASSERT(cond == Equal || cond == NotEqual); 533 cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL)); 534 return cond; 535 } 536 Condition testSymbol(Condition cond, const BaseIndex& address) { 537 MOZ_ASSERT(cond == Equal || cond == NotEqual); 538 cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL)); 539 return cond; 540 } 541 Condition testBigInt(Condition cond, const Address& address) { 542 MOZ_ASSERT(cond == Equal || cond == NotEqual); 543 cmp32(tagOf(address), ImmTag(JSVAL_TAG_BIGINT)); 544 return cond; 545 } 546 Condition testBigInt(Condition cond, const BaseIndex& address) { 547 MOZ_ASSERT(cond == Equal || cond == NotEqual); 548 cmp32(tagOf(address), ImmTag(JSVAL_TAG_BIGINT)); 549 return cond; 550 } 551 Condition testInt32(Condition cond, const BaseIndex& address) { 552 MOZ_ASSERT(cond == Equal || cond == NotEqual); 553 cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32)); 554 return cond; 555 } 556 Condition testObject(Condition cond, const BaseIndex& address) { 557 MOZ_ASSERT(cond == Equal || cond == NotEqual); 558 cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); 559 return cond; 560 } 561 Condition testDouble(Condition cond, const BaseIndex& address) { 562 MOZ_ASSERT(cond == Equal || cond == NotEqual); 563 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 564 cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); 565 return actual; 566 } 567 Condition testMagic(Condition cond, const BaseIndex& address) { 568 MOZ_ASSERT(cond == Equal || cond == NotEqual); 569 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 570 return cond; 571 } 572 Condition testGCThing(Condition cond, const BaseIndex& address) { 573 MOZ_ASSERT(cond == Equal || cond == NotEqual); 574 cmp32(tagOf(address), ImmTag(JS::detail::ValueLowerInclGCThingTag)); 575 return cond == Equal ? AboveOrEqual : Below; 576 } 577 578 void testNullSet(Condition cond, const ValueOperand& value, Register dest) { 579 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 580 cond = testNull(cond, value); 581 emitSet(cond, dest, destIsZero); 582 } 583 584 void testObjectSet(Condition cond, const ValueOperand& value, Register dest) { 585 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 586 cond = testObject(cond, value); 587 emitSet(cond, dest, destIsZero); 588 } 589 590 void testUndefinedSet(Condition cond, const ValueOperand& value, 591 Register dest) { 592 bool destIsZero = maybeEmitSetZeroByteRegister(value, dest); 593 cond = testUndefined(cond, value); 594 emitSet(cond, dest, destIsZero); 595 } 596 597 void cmpPtr(Register lhs, const Imm32 rhs) { cmpl(rhs, lhs); } 598 void cmpPtr(Register lhs, const ImmWord rhs) { cmpl(Imm32(rhs.value), lhs); } 599 void cmpPtr(Register lhs, const ImmPtr imm) { 600 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 601 } 602 void cmpPtr(Register lhs, const ImmGCPtr rhs) { cmpl(rhs, lhs); } 603 void cmpPtr(const Operand& lhs, Imm32 rhs) { cmp32(lhs, rhs); } 604 void cmpPtr(const Operand& lhs, const ImmWord rhs) { 605 cmp32(lhs, Imm32(rhs.value)); 606 } 607 void cmpPtr(const Operand& lhs, const ImmPtr imm) { 608 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 609 } 610 void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { cmpl(rhs, lhs); } 611 void cmpPtr(const Address& lhs, Register rhs) { cmpPtr(Operand(lhs), rhs); } 612 void cmpPtr(const Operand& lhs, Register rhs) { cmp32(lhs, rhs); } 613 void cmpPtr(const Address& lhs, const ImmWord rhs) { 614 cmpPtr(Operand(lhs), rhs); 615 } 616 void cmpPtr(const Address& lhs, const ImmPtr rhs) { 617 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 618 } 619 void cmpPtr(const Address& lhs, const ImmGCPtr rhs) { 620 cmpPtr(Operand(lhs), rhs); 621 } 622 void cmpPtr(Register lhs, Register rhs) { cmp32(lhs, rhs); } 623 void testPtr(Register lhs, Register rhs) { test32(lhs, rhs); } 624 void testPtr(Register lhs, Imm32 rhs) { test32(lhs, rhs); } 625 void testPtr(Register lhs, ImmWord rhs) { test32(lhs, Imm32(rhs.value)); } 626 void testPtr(const Operand& lhs, Imm32 rhs) { test32(lhs, rhs); } 627 void testPtr(const Operand& lhs, ImmWord rhs) { 628 test32(lhs, Imm32(rhs.value)); 629 } 630 631 ///////////////////////////////////////////////////////////////// 632 // Common interface. 633 ///////////////////////////////////////////////////////////////// 634 635 void movePtr(ImmWord imm, Register dest) { movl(Imm32(imm.value), dest); } 636 void movePtr(ImmPtr imm, Register dest) { movl(imm, dest); } 637 void movePtr(wasm::SymbolicAddress imm, Register dest) { mov(imm, dest); } 638 void movePtr(ImmGCPtr imm, Register dest) { movl(imm, dest); } 639 FaultingCodeOffset loadPtr(const Address& address, Register dest) { 640 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 641 movl(Operand(address), dest); 642 return fco; 643 } 644 void loadPtr(const Operand& src, Register dest) { movl(src, dest); } 645 FaultingCodeOffset loadPtr(const BaseIndex& src, Register dest) { 646 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 647 movl(Operand(src), dest); 648 return fco; 649 } 650 void loadPtr(AbsoluteAddress address, Register dest) { 651 movl(Operand(address), dest); 652 } 653 void loadPrivate(const Address& src, Register dest) { 654 movl(payloadOf(src), dest); 655 } 656 void load32(AbsoluteAddress address, Register dest) { 657 movl(Operand(address), dest); 658 } 659 FaultingCodeOffsetPair load64(const Address& address, Register64 dest) { 660 FaultingCodeOffset fco1, fco2; 661 bool highBeforeLow = address.base == dest.low; 662 if (highBeforeLow) { 663 fco1 = FaultingCodeOffset(currentOffset()); 664 movl(Operand(HighWord(address)), dest.high); 665 fco2 = FaultingCodeOffset(currentOffset()); 666 movl(Operand(LowWord(address)), dest.low); 667 } else { 668 fco1 = FaultingCodeOffset(currentOffset()); 669 movl(Operand(LowWord(address)), dest.low); 670 fco2 = FaultingCodeOffset(currentOffset()); 671 movl(Operand(HighWord(address)), dest.high); 672 } 673 return FaultingCodeOffsetPair(fco1, fco2); 674 } 675 FaultingCodeOffsetPair load64(const BaseIndex& address, Register64 dest) { 676 // If you run into this, relax your register allocation constraints. 677 MOZ_RELEASE_ASSERT( 678 !((address.base == dest.low || address.base == dest.high) && 679 (address.index == dest.low || address.index == dest.high))); 680 FaultingCodeOffset fco1, fco2; 681 bool highBeforeLow = address.base == dest.low || address.index == dest.low; 682 if (highBeforeLow) { 683 fco1 = FaultingCodeOffset(currentOffset()); 684 movl(Operand(HighWord(address)), dest.high); 685 fco2 = FaultingCodeOffset(currentOffset()); 686 movl(Operand(LowWord(address)), dest.low); 687 } else { 688 fco1 = FaultingCodeOffset(currentOffset()); 689 movl(Operand(LowWord(address)), dest.low); 690 fco2 = FaultingCodeOffset(currentOffset()); 691 movl(Operand(HighWord(address)), dest.high); 692 } 693 return FaultingCodeOffsetPair(fco1, fco2); 694 } 695 template <typename T> 696 void load64Unaligned(const T& address, Register64 dest) { 697 load64(address, dest); 698 } 699 template <typename T> 700 void storePtr(ImmWord imm, T address) { 701 movl(Imm32(imm.value), Operand(address)); 702 } 703 template <typename T> 704 void storePtr(ImmPtr imm, T address) { 705 storePtr(ImmWord(uintptr_t(imm.value)), address); 706 } 707 template <typename T> 708 void storePtr(ImmGCPtr imm, T address) { 709 movl(imm, Operand(address)); 710 } 711 FaultingCodeOffset storePtr(Register src, const Address& address) { 712 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 713 movl(src, Operand(address)); 714 return fco; 715 } 716 FaultingCodeOffset storePtr(Register src, const BaseIndex& address) { 717 FaultingCodeOffset fco = FaultingCodeOffset(currentOffset()); 718 movl(src, Operand(address)); 719 return fco; 720 } 721 void storePtr(Register src, const Operand& dest) { movl(src, dest); } 722 void storePtr(Register src, AbsoluteAddress address) { 723 movl(src, Operand(address)); 724 } 725 void store32(Register src, AbsoluteAddress address) { 726 movl(src, Operand(address)); 727 } 728 void store16(Register src, AbsoluteAddress address) { 729 movw(src, Operand(address)); 730 } 731 template <typename T> 732 FaultingCodeOffsetPair store64(Register64 src, const T& address) { 733 FaultingCodeOffset fco1 = FaultingCodeOffset(currentOffset()); 734 movl(src.low, Operand(LowWord(address))); 735 FaultingCodeOffset fco2 = FaultingCodeOffset(currentOffset()); 736 movl(src.high, Operand(HighWord(address))); 737 return FaultingCodeOffsetPair(fco1, fco2); 738 } 739 void store64(Imm64 imm, Address address) { 740 movl(imm.low(), Operand(LowWord(address))); 741 movl(imm.hi(), Operand(HighWord(address))); 742 } 743 void store64(Imm64 imm, const BaseIndex& address) { 744 movl(imm.low(), Operand(LowWord(address))); 745 movl(imm.hi(), Operand(HighWord(address))); 746 } 747 template <typename S, typename T> 748 void store64Unaligned(const S& src, const T& dest) { 749 store64(src, dest); 750 } 751 752 void setStackArg(Register reg, uint32_t arg) { 753 movl(reg, Operand(esp, arg * sizeof(intptr_t))); 754 } 755 756 void boxDouble(FloatRegister src, const ValueOperand& dest, 757 FloatRegister temp) { 758 if (Assembler::HasSSE41()) { 759 vmovd(src, dest.payloadReg()); 760 vpextrd(1, src, dest.typeReg()); 761 } else { 762 vmovd(src, dest.payloadReg()); 763 if (src != temp) { 764 moveDouble(src, temp); 765 } 766 vpsrldq(Imm32(4), temp, temp); 767 vmovd(temp, dest.typeReg()); 768 } 769 } 770 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest); 771 void boxNonDouble(Register type, Register src, const ValueOperand& dest); 772 773 void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type, 774 Register scratch = InvalidReg) { 775 unboxNonDouble(Operand(src.typeReg()), Operand(src.payloadReg()), dest, 776 type, scratch); 777 } 778 void unboxNonDouble(const Operand& tag, const Operand& payload, Register dest, 779 JSValueType type, Register scratch = InvalidReg) { 780 auto movPayloadToDest = [&]() { 781 if (payload.kind() != Operand::REG || !payload.containsReg(dest)) { 782 movl(payload, dest); 783 } 784 }; 785 if (!JitOptions.spectreValueMasking) { 786 movPayloadToDest(); 787 return; 788 } 789 790 // Spectre mitigation: We zero the payload if the tag does not match the 791 // expected type and if this is a pointer type. 792 if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 793 movPayloadToDest(); 794 return; 795 } 796 797 if (!tag.containsReg(dest) && !payload.containsReg(dest)) { 798 // We zero the destination register and move the payload into it if 799 // the tag corresponds to the given type. 800 xorl(dest, dest); 801 cmpl(Imm32(JSVAL_TYPE_TO_TAG(type)), tag); 802 cmovCCl(Condition::Equal, payload, dest); 803 return; 804 } 805 806 if (scratch == InvalidReg || scratch == dest || tag.containsReg(scratch) || 807 payload.containsReg(scratch)) { 808 // UnboxedLayout::makeConstructorCode calls extractObject with a 809 // scratch register which aliases the tag register, thus we cannot 810 // assert the above condition. 811 scratch = InvalidReg; 812 } 813 814 // The destination register aliases one of the operands. We create a 815 // zero value either in a scratch register or on the stack and use it 816 // to reset the destination register after reading both the tag and the 817 // payload. 818 Operand zero(Address(esp, 0)); 819 if (scratch == InvalidReg) { 820 push(Imm32(0)); 821 } else { 822 xorl(scratch, scratch); 823 zero = Operand(scratch); 824 } 825 cmpl(Imm32(JSVAL_TYPE_TO_TAG(type)), tag); 826 movPayloadToDest(); 827 cmovCCl(Condition::NotEqual, zero, dest); 828 if (scratch == InvalidReg) { 829 addl(Imm32(sizeof(void*)), esp); 830 } 831 } 832 void unboxNonDouble(const Address& src, Register dest, JSValueType type) { 833 unboxNonDouble(tagOf(src), payloadOf(src), dest, type); 834 } 835 void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) { 836 unboxNonDouble(tagOf(src), payloadOf(src), dest, type); 837 } 838 void unboxInt32(const ValueOperand& src, Register dest) { 839 unboxNonDouble(src, dest, JSVAL_TYPE_INT32); 840 } 841 void unboxInt32(const Address& src, Register dest) { 842 unboxNonDouble(src, dest, JSVAL_TYPE_INT32); 843 } 844 void unboxInt32(const BaseIndex& src, Register dest) { 845 unboxNonDouble(src, dest, JSVAL_TYPE_INT32); 846 } 847 void unboxBoolean(const ValueOperand& src, Register dest) { 848 unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN); 849 } 850 void unboxBoolean(const Address& src, Register dest) { 851 unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN); 852 } 853 void unboxBoolean(const BaseIndex& src, Register dest) { 854 unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN); 855 } 856 void unboxString(const ValueOperand& src, Register dest) { 857 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 858 } 859 void unboxString(const Address& src, Register dest) { 860 unboxNonDouble(src, dest, JSVAL_TYPE_STRING); 861 } 862 void unboxSymbol(const ValueOperand& src, Register dest) { 863 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 864 } 865 void unboxSymbol(const Address& src, Register dest) { 866 unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL); 867 } 868 void unboxBigInt(const ValueOperand& src, Register dest) { 869 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 870 } 871 void unboxBigInt(const Address& src, Register dest) { 872 unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT); 873 } 874 void unboxObject(const ValueOperand& src, Register dest) { 875 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 876 } 877 void unboxObject(const Address& src, Register dest) { 878 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 879 } 880 void unboxObject(const BaseIndex& src, Register dest) { 881 unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT); 882 } 883 template <typename T> 884 void unboxDouble(const T& src, FloatRegister dest) { 885 loadDouble(Operand(src), dest); 886 } 887 void unboxDouble(const ValueOperand& src, FloatRegister dest) { 888 if (Assembler::HasSSE41()) { 889 vmovd(src.payloadReg(), dest); 890 vpinsrd(1, src.typeReg(), dest, dest); 891 } else { 892 ScratchDoubleScope fpscratch(asMasm()); 893 vmovd(src.payloadReg(), dest); 894 vmovd(src.typeReg(), fpscratch); 895 vunpcklps(fpscratch, dest, dest); 896 } 897 } 898 void unboxDouble(const Operand& payload, const Operand& type, 899 Register scratch, FloatRegister dest) { 900 if (Assembler::HasSSE41()) { 901 movl(payload, scratch); 902 vmovd(scratch, dest); 903 movl(type, scratch); 904 vpinsrd(1, scratch, dest, dest); 905 } else { 906 ScratchDoubleScope fpscratch(asMasm()); 907 movl(payload, scratch); 908 vmovd(scratch, dest); 909 movl(type, scratch); 910 vmovd(scratch, fpscratch); 911 vunpcklps(fpscratch, dest, dest); 912 } 913 } 914 inline void unboxValue(const ValueOperand& src, AnyRegister dest, 915 JSValueType type); 916 917 // See comment in MacroAssembler-x64.h. 918 void unboxGCThingForGCBarrier(const Address& src, Register dest) { 919 movl(payloadOf(src), dest); 920 } 921 void unboxGCThingForGCBarrier(const ValueOperand& src, Register dest) { 922 if (src.payloadReg() != dest) { 923 movl(src.payloadReg(), dest); 924 } 925 } 926 927 void unboxWasmAnyRefGCThingForGCBarrier(const Address& src, Register dest) { 928 movl(ImmWord(wasm::AnyRef::GCThingMask), dest); 929 andl(Operand(src), dest); 930 } 931 932 void getWasmAnyRefGCThingChunk(Register src, Register dest) { 933 MOZ_ASSERT(src != dest); 934 movl(ImmWord(wasm::AnyRef::GCThingChunkMask), dest); 935 andl(src, dest); 936 } 937 938 void notBoolean(const ValueOperand& val) { xorl(Imm32(1), val.payloadReg()); } 939 940 template <typename T> 941 void fallibleUnboxPtrImpl(const T& src, Register dest, JSValueType type, 942 Label* fail); 943 944 // Extended unboxing API. If the payload is already in a register, returns 945 // that register. Otherwise, provides a move to the given scratch register, 946 // and returns that. 947 [[nodiscard]] Register extractObject(const Address& address, Register dest) { 948 unboxObject(address, dest); 949 return dest; 950 } 951 [[nodiscard]] Register extractObject(const ValueOperand& value, 952 Register scratch) { 953 unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_OBJECT, scratch); 954 return value.payloadReg(); 955 } 956 [[nodiscard]] Register extractSymbol(const ValueOperand& value, 957 Register scratch) { 958 unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_SYMBOL, scratch); 959 return value.payloadReg(); 960 } 961 [[nodiscard]] Register extractInt32(const ValueOperand& value, 962 Register scratch) { 963 return value.payloadReg(); 964 } 965 [[nodiscard]] Register extractBoolean(const ValueOperand& value, 966 Register scratch) { 967 return value.payloadReg(); 968 } 969 [[nodiscard]] Register extractTag(const Address& address, Register scratch) { 970 movl(tagOf(address), scratch); 971 return scratch; 972 } 973 [[nodiscard]] Register extractTag(const ValueOperand& value, 974 Register scratch) { 975 return value.typeReg(); 976 } 977 978 void convertDoubleToPtr(FloatRegister src, Register dest, Label* fail, 979 bool negativeZeroCheck = true) { 980 convertDoubleToInt32(src, dest, fail, negativeZeroCheck); 981 } 982 983 void loadConstantDouble(double d, FloatRegister dest); 984 void loadConstantFloat32(float f, FloatRegister dest); 985 986 void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest); 987 void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest); 988 void vpaddbSimd128(const SimdConstant& v, FloatRegister lhs, 989 FloatRegister dest); 990 void vpaddwSimd128(const SimdConstant& v, FloatRegister lhs, 991 FloatRegister dest); 992 void vpadddSimd128(const SimdConstant& v, FloatRegister lhs, 993 FloatRegister dest); 994 void vpaddqSimd128(const SimdConstant& v, FloatRegister lhs, 995 FloatRegister dest); 996 void vpsubbSimd128(const SimdConstant& v, FloatRegister lhs, 997 FloatRegister dest); 998 void vpsubwSimd128(const SimdConstant& v, FloatRegister lhs, 999 FloatRegister dest); 1000 void vpsubdSimd128(const SimdConstant& v, FloatRegister lhs, 1001 FloatRegister dest); 1002 void vpsubqSimd128(const SimdConstant& v, FloatRegister lhs, 1003 FloatRegister dest); 1004 void vpmullwSimd128(const SimdConstant& v, FloatRegister lhs, 1005 FloatRegister dest); 1006 void vpmulldSimd128(const SimdConstant& v, FloatRegister lhs, 1007 FloatRegister dest); 1008 void vpaddsbSimd128(const SimdConstant& v, FloatRegister lhs, 1009 FloatRegister dest); 1010 void vpaddusbSimd128(const SimdConstant& v, FloatRegister lhs, 1011 FloatRegister dest); 1012 void vpaddswSimd128(const SimdConstant& v, FloatRegister lhs, 1013 FloatRegister dest); 1014 void vpadduswSimd128(const SimdConstant& v, FloatRegister lhs, 1015 FloatRegister dest); 1016 void vpsubsbSimd128(const SimdConstant& v, FloatRegister lhs, 1017 FloatRegister dest); 1018 void vpsubusbSimd128(const SimdConstant& v, FloatRegister lhs, 1019 FloatRegister dest); 1020 void vpsubswSimd128(const SimdConstant& v, FloatRegister lhs, 1021 FloatRegister dest); 1022 void vpsubuswSimd128(const SimdConstant& v, FloatRegister lhs, 1023 FloatRegister dest); 1024 void vpminsbSimd128(const SimdConstant& v, FloatRegister lhs, 1025 FloatRegister dest); 1026 void vpminubSimd128(const SimdConstant& v, FloatRegister lhs, 1027 FloatRegister dest); 1028 void vpminswSimd128(const SimdConstant& v, FloatRegister lhs, 1029 FloatRegister dest); 1030 void vpminuwSimd128(const SimdConstant& v, FloatRegister lhs, 1031 FloatRegister dest); 1032 void vpminsdSimd128(const SimdConstant& v, FloatRegister lhs, 1033 FloatRegister dest); 1034 void vpminudSimd128(const SimdConstant& v, FloatRegister lhs, 1035 FloatRegister dest); 1036 void vpmaxsbSimd128(const SimdConstant& v, FloatRegister lhs, 1037 FloatRegister dest); 1038 void vpmaxubSimd128(const SimdConstant& v, FloatRegister lhs, 1039 FloatRegister dest); 1040 void vpmaxswSimd128(const SimdConstant& v, FloatRegister lhs, 1041 FloatRegister dest); 1042 void vpmaxuwSimd128(const SimdConstant& v, FloatRegister lhs, 1043 FloatRegister dest); 1044 void vpmaxsdSimd128(const SimdConstant& v, FloatRegister lhs, 1045 FloatRegister dest); 1046 void vpmaxudSimd128(const SimdConstant& v, FloatRegister lhs, 1047 FloatRegister dest); 1048 void vpandSimd128(const SimdConstant& v, FloatRegister lhs, 1049 FloatRegister dest); 1050 void vpxorSimd128(const SimdConstant& v, FloatRegister lhs, 1051 FloatRegister dest); 1052 void vporSimd128(const SimdConstant& v, FloatRegister lhs, 1053 FloatRegister dest); 1054 void vaddpsSimd128(const SimdConstant& v, FloatRegister lhs, 1055 FloatRegister dest); 1056 void vaddpdSimd128(const SimdConstant& v, FloatRegister lhs, 1057 FloatRegister dest); 1058 void vsubpsSimd128(const SimdConstant& v, FloatRegister lhs, 1059 FloatRegister dest); 1060 void vsubpdSimd128(const SimdConstant& v, FloatRegister lhs, 1061 FloatRegister dest); 1062 void vdivpsSimd128(const SimdConstant& v, FloatRegister lhs, 1063 FloatRegister dest); 1064 void vdivpdSimd128(const SimdConstant& v, FloatRegister lhs, 1065 FloatRegister dest); 1066 void vmulpsSimd128(const SimdConstant& v, FloatRegister lhs, 1067 FloatRegister dest); 1068 void vmulpdSimd128(const SimdConstant& v, FloatRegister lhs, 1069 FloatRegister dest); 1070 void vandpsSimd128(const SimdConstant& v, FloatRegister lhs, 1071 FloatRegister dest); 1072 void vandpdSimd128(const SimdConstant& v, FloatRegister lhs, 1073 FloatRegister dest); 1074 void vxorpsSimd128(const SimdConstant& v, FloatRegister lhs, 1075 FloatRegister dest); 1076 void vxorpdSimd128(const SimdConstant& v, FloatRegister lhs, 1077 FloatRegister dest); 1078 void vminpdSimd128(const SimdConstant& v, FloatRegister lhs, 1079 FloatRegister dest); 1080 void vpacksswbSimd128(const SimdConstant& v, FloatRegister lhs, 1081 FloatRegister dest); 1082 void vpackuswbSimd128(const SimdConstant& v, FloatRegister lhs, 1083 FloatRegister dest); 1084 void vpackssdwSimd128(const SimdConstant& v, FloatRegister lhs, 1085 FloatRegister dest); 1086 void vpackusdwSimd128(const SimdConstant& v, FloatRegister lhs, 1087 FloatRegister dest); 1088 void vpunpckldqSimd128(const SimdConstant& v, FloatRegister lhs, 1089 FloatRegister dest); 1090 void vunpcklpsSimd128(const SimdConstant& v, FloatRegister lhs, 1091 FloatRegister dest); 1092 void vpshufbSimd128(const SimdConstant& v, FloatRegister lhs, 1093 FloatRegister dest); 1094 void vptestSimd128(const SimdConstant& v, FloatRegister lhs); 1095 void vpmaddwdSimd128(const SimdConstant& v, FloatRegister lhs, 1096 FloatRegister dest); 1097 void vpcmpeqbSimd128(const SimdConstant& v, FloatRegister lhs, 1098 FloatRegister dest); 1099 void vpcmpgtbSimd128(const SimdConstant& v, FloatRegister lhs, 1100 FloatRegister dest); 1101 void vpcmpeqwSimd128(const SimdConstant& v, FloatRegister lhs, 1102 FloatRegister dest); 1103 void vpcmpgtwSimd128(const SimdConstant& v, FloatRegister lhs, 1104 FloatRegister dest); 1105 void vpcmpeqdSimd128(const SimdConstant& v, FloatRegister lhs, 1106 FloatRegister dest); 1107 void vpcmpgtdSimd128(const SimdConstant& v, FloatRegister lhs, 1108 FloatRegister dest); 1109 void vcmpeqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1110 FloatRegister dest); 1111 void vcmpneqpsSimd128(const SimdConstant& v, FloatRegister lhs, 1112 FloatRegister dest); 1113 void vcmpltpsSimd128(const SimdConstant& v, FloatRegister lhs, 1114 FloatRegister dest); 1115 void vcmplepsSimd128(const SimdConstant& v, FloatRegister lhs, 1116 FloatRegister dest); 1117 void vcmpgepsSimd128(const SimdConstant& v, FloatRegister lhs, 1118 FloatRegister dest); 1119 void vcmpeqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1120 FloatRegister dest); 1121 void vcmpneqpdSimd128(const SimdConstant& v, FloatRegister lhs, 1122 FloatRegister dest); 1123 void vcmpltpdSimd128(const SimdConstant& v, FloatRegister lhs, 1124 FloatRegister dest); 1125 void vcmplepdSimd128(const SimdConstant& v, FloatRegister lhs, 1126 FloatRegister dest); 1127 void vpmaddubswSimd128(const SimdConstant& v, FloatRegister lhs, 1128 FloatRegister dest); 1129 void vpmuludqSimd128(const SimdConstant& v, FloatRegister lhs, 1130 FloatRegister dest); 1131 1132 Condition testInt32Truthy(bool truthy, const ValueOperand& operand) { 1133 test32(operand.payloadReg(), operand.payloadReg()); 1134 return truthy ? NonZero : Zero; 1135 } 1136 Condition testStringTruthy(bool truthy, const ValueOperand& value); 1137 Condition testBigIntTruthy(bool truthy, const ValueOperand& value); 1138 1139 template <typename T> 1140 inline void loadInt32OrDouble(const T& src, FloatRegister dest); 1141 1142 template <typename T> 1143 inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest); 1144 1145 // Note: this function clobbers the source register. 1146 inline void convertUInt32ToDouble(Register src, FloatRegister dest); 1147 1148 // Note: this function clobbers the source register. 1149 inline void convertUInt32ToFloat32(Register src, FloatRegister dest); 1150 1151 void incrementInt32Value(const Address& addr) { 1152 addl(Imm32(1), payloadOf(addr)); 1153 } 1154 1155 void minMax32(Register lhs, Register rhs, Register dest, bool isMax); 1156 void minMax32(Register lhs, Imm32 rhs, Register dest, bool isMax); 1157 1158 public: 1159 // Used from within an Exit frame to handle a pending exception. 1160 void handleFailureWithHandlerTail(Label* profilerExitTail, Label* bailoutTail, 1161 uint32_t* returnValueCheckOffset); 1162 1163 // Instrumentation for entering and leaving the profiler. 1164 void profilerEnterFrame(Register framePtr, Register scratch); 1165 void profilerExitFrame(); 1166 }; 1167 1168 using MacroAssemblerSpecific = MacroAssemblerX86; 1169 1170 } // namespace jit 1171 } // namespace js 1172 1173 #endif /* jit_x86_MacroAssembler_x86_h */