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