1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_x86_MacroAssembler_x86_h 8 #define jit_x86_MacroAssembler_x86_h 9 10 #include "jscompartment.h" 11 12 #include "jit/JitFrames.h" 13 #include "jit/MoveResolver.h" 14 #include "jit/x86-shared/MacroAssembler-x86-shared.h" 15 16 namespace js { 17 namespace jit { 18 19 class MacroAssemblerX86 : public MacroAssemblerX86Shared 20 { 21 private: 22 // Perform a downcast. Should be removed by Bug 996602. 23 MacroAssembler& asMasm(); 24 const MacroAssembler& asMasm() const; 25 26 protected: 27 MoveResolver moveResolver_; 28 29 private: payloadOfAfterStackPush(const Address & address)30 Operand payloadOfAfterStackPush(const Address& address) { 31 // If we are basing off %esp, the address will be invalid after the 32 // first push. 33 if (address.base == StackPointer) 34 return Operand(address.base, address.offset + 4); 35 return payloadOf(address); 36 } payloadOf(const Address & address)37 Operand payloadOf(const Address& address) { 38 return Operand(address.base, address.offset); 39 } payloadOf(const BaseIndex & address)40 Operand payloadOf(const BaseIndex& address) { 41 return Operand(address.base, address.index, address.scale, address.offset); 42 } tagOf(const Address & address)43 Operand tagOf(const Address& address) { 44 return Operand(address.base, address.offset + 4); 45 } tagOf(const BaseIndex & address)46 Operand tagOf(const BaseIndex& address) { 47 return Operand(address.base, address.index, address.scale, address.offset + 4); 48 } 49 50 void setupABICall(uint32_t args); 51 52 public: 53 using MacroAssemblerX86Shared::load32; 54 using MacroAssemblerX86Shared::store32; 55 using MacroAssemblerX86Shared::store16; 56 using MacroAssemblerX86Shared::call; 57 MacroAssemblerX86()58 MacroAssemblerX86() 59 { 60 } 61 62 // The buffer is about to be linked, make sure any constant pools or excess 63 // bookkeeping has been flushed to the instruction stream. 64 void finish(); 65 66 ///////////////////////////////////////////////////////////////// 67 // X86-specific interface. 68 ///////////////////////////////////////////////////////////////// 69 ToPayload(Operand base)70 Operand ToPayload(Operand base) { 71 return base; 72 } ToPayload(Address base)73 Address ToPayload(Address base) { 74 return base; 75 } ToPayload(BaseIndex base)76 BaseIndex ToPayload(BaseIndex base) { 77 return base; 78 } ToType(Operand base)79 Operand ToType(Operand base) { 80 switch (base.kind()) { 81 case Operand::MEM_REG_DISP: 82 return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void*)); 83 84 case Operand::MEM_SCALE: 85 return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), 86 base.scale(), base.disp() + sizeof(void*)); 87 88 default: 89 MOZ_CRASH("unexpected operand kind"); 90 } 91 } ToType(Address base)92 Address ToType(Address base) { 93 return ToType(Operand(base)).toAddress(); 94 } moveValue(const Value & val,Register type,Register data)95 void moveValue(const Value& val, Register type, Register data) { 96 movl(Imm32(val.toNunboxTag()), type); 97 if (val.isMarkable()) 98 movl(ImmGCPtr(val.toMarkablePointer()), data); 99 else 100 movl(Imm32(val.toNunboxPayload()), data); 101 } moveValue(const Value & val,const ValueOperand & dest)102 void moveValue(const Value& val, const ValueOperand& dest) { 103 moveValue(val, dest.typeReg(), dest.payloadReg()); 104 } moveValue(const ValueOperand & src,const ValueOperand & dest)105 void moveValue(const ValueOperand& src, const ValueOperand& dest) { 106 Register s0 = src.typeReg(), d0 = dest.typeReg(), 107 s1 = src.payloadReg(), d1 = dest.payloadReg(); 108 109 // Either one or both of the source registers could be the same as a 110 // destination register. 111 if (s1 == d0) { 112 if (s0 == d1) { 113 // If both are, this is just a swap of two registers. 114 xchgl(d0, d1); 115 return; 116 } 117 // If only one is, copy that source first. 118 mozilla::Swap(s0, s1); 119 mozilla::Swap(d0, d1); 120 } 121 122 if (s0 != d0) 123 movl(s0, d0); 124 if (s1 != d1) 125 movl(s1, d1); 126 } 127 128 ///////////////////////////////////////////////////////////////// 129 // X86/X64-common interface. 130 ///////////////////////////////////////////////////////////////// storeValue(ValueOperand val,Operand dest)131 void storeValue(ValueOperand val, Operand dest) { 132 movl(val.payloadReg(), ToPayload(dest)); 133 movl(val.typeReg(), ToType(dest)); 134 } storeValue(ValueOperand val,const Address & dest)135 void storeValue(ValueOperand val, const Address& dest) { 136 storeValue(val, Operand(dest)); 137 } 138 template <typename T> storeValue(JSValueType type,Register reg,const T & dest)139 void storeValue(JSValueType type, Register reg, const T& dest) { 140 storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest)); 141 storePayload(reg, Operand(dest)); 142 } 143 template <typename T> storeValue(const Value & val,const T & dest)144 void storeValue(const Value& val, const T& dest) { 145 storeTypeTag(ImmTag(val.toNunboxTag()), Operand(dest)); 146 storePayload(val, Operand(dest)); 147 } storeValue(ValueOperand val,BaseIndex dest)148 void storeValue(ValueOperand val, BaseIndex dest) { 149 storeValue(val, Operand(dest)); 150 } storeValue(const Address & src,const Address & dest,Register temp)151 void storeValue(const Address& src, const Address& dest, Register temp) { 152 MOZ_ASSERT(src.base != temp); 153 MOZ_ASSERT(dest.base != temp); 154 155 load32(ToType(src), temp); 156 store32(temp, ToType(dest)); 157 158 load32(ToPayload(src), temp); 159 store32(temp, ToPayload(dest)); 160 } loadValue(Operand src,ValueOperand val)161 void loadValue(Operand src, ValueOperand val) { 162 Operand payload = ToPayload(src); 163 Operand type = ToType(src); 164 165 // Ensure that loading the payload does not erase the pointer to the 166 // Value in memory or the index. 167 Register baseReg = Register::FromCode(src.base()); 168 Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg; 169 170 // If we have a BaseIndex that uses both result registers, first compute 171 // the address and then load the Value from there. 172 if ((baseReg == val.payloadReg() && indexReg == val.typeReg()) || 173 (baseReg == val.typeReg() && indexReg == val.payloadReg())) 174 { 175 computeEffectiveAddress(src, val.scratchReg()); 176 loadValue(Address(val.scratchReg(), 0), val); 177 return; 178 } 179 180 if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) { 181 MOZ_ASSERT(baseReg != val.typeReg()); 182 MOZ_ASSERT(indexReg != val.typeReg()); 183 184 movl(type, val.typeReg()); 185 movl(payload, val.payloadReg()); 186 } else { 187 MOZ_ASSERT(baseReg != val.payloadReg()); 188 MOZ_ASSERT(indexReg != val.payloadReg()); 189 190 movl(payload, val.payloadReg()); 191 movl(type, val.typeReg()); 192 } 193 } loadValue(Address src,ValueOperand val)194 void loadValue(Address src, ValueOperand val) { 195 loadValue(Operand(src), val); 196 } loadValue(const BaseIndex & src,ValueOperand val)197 void loadValue(const BaseIndex& src, ValueOperand val) { 198 loadValue(Operand(src), val); 199 } tagValue(JSValueType type,Register payload,ValueOperand dest)200 void tagValue(JSValueType type, Register payload, ValueOperand dest) { 201 MOZ_ASSERT(dest.typeReg() != dest.payloadReg()); 202 if (payload != dest.payloadReg()) 203 movl(payload, dest.payloadReg()); 204 movl(ImmType(type), dest.typeReg()); 205 } pushValue(ValueOperand val)206 void pushValue(ValueOperand val) { 207 push(val.typeReg()); 208 push(val.payloadReg()); 209 } popValue(ValueOperand val)210 void popValue(ValueOperand val) { 211 pop(val.payloadReg()); 212 pop(val.typeReg()); 213 } pushValue(const Value & val)214 void pushValue(const Value& val) { 215 push(Imm32(val.toNunboxTag())); 216 if (val.isMarkable()) 217 push(ImmGCPtr(val.toMarkablePointer())); 218 else 219 push(Imm32(val.toNunboxPayload())); 220 } pushValue(JSValueType type,Register reg)221 void pushValue(JSValueType type, Register reg) { 222 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); 223 push(reg); 224 } pushValue(const Address & addr)225 void pushValue(const Address& addr) { 226 push(tagOf(addr)); 227 push(payloadOfAfterStackPush(addr)); 228 } push64(Register64 src)229 void push64(Register64 src) { 230 push(src.high); 231 push(src.low); 232 } pop64(Register64 dest)233 void pop64(Register64 dest) { 234 pop(dest.low); 235 pop(dest.high); 236 } storePayload(const Value & val,Operand dest)237 void storePayload(const Value& val, Operand dest) { 238 if (val.isMarkable()) 239 movl(ImmGCPtr(val.toMarkablePointer()), ToPayload(dest)); 240 else 241 movl(Imm32(val.toNunboxPayload()), ToPayload(dest)); 242 } storePayload(Register src,Operand dest)243 void storePayload(Register src, Operand dest) { 244 movl(src, ToPayload(dest)); 245 } storeTypeTag(ImmTag tag,Operand dest)246 void storeTypeTag(ImmTag tag, Operand dest) { 247 movl(tag, ToType(dest)); 248 } 249 movePtr(Register src,Register dest)250 void movePtr(Register src, Register dest) { 251 movl(src, dest); 252 } movePtr(Register src,const Operand & dest)253 void movePtr(Register src, const Operand& dest) { 254 movl(src, dest); 255 } 256 257 // Returns the register containing the type tag. splitTagForTest(const ValueOperand & value)258 Register splitTagForTest(const ValueOperand& value) { 259 return value.typeReg(); 260 } 261 testUndefined(Condition cond,Register tag)262 Condition testUndefined(Condition cond, Register tag) { 263 MOZ_ASSERT(cond == Equal || cond == NotEqual); 264 cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 265 return cond; 266 } testBoolean(Condition cond,Register tag)267 Condition testBoolean(Condition cond, Register tag) { 268 MOZ_ASSERT(cond == Equal || cond == NotEqual); 269 cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 270 return cond; 271 } testInt32(Condition cond,Register tag)272 Condition testInt32(Condition cond, Register tag) { 273 MOZ_ASSERT(cond == Equal || cond == NotEqual); 274 cmp32(tag, ImmTag(JSVAL_TAG_INT32)); 275 return cond; 276 } testDouble(Condition cond,Register tag)277 Condition testDouble(Condition cond, Register tag) { 278 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 279 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 280 cmp32(tag, ImmTag(JSVAL_TAG_CLEAR)); 281 return actual; 282 } testNull(Condition cond,Register tag)283 Condition testNull(Condition cond, Register tag) { 284 MOZ_ASSERT(cond == Equal || cond == NotEqual); 285 cmp32(tag, ImmTag(JSVAL_TAG_NULL)); 286 return cond; 287 } testString(Condition cond,Register tag)288 Condition testString(Condition cond, Register tag) { 289 MOZ_ASSERT(cond == Equal || cond == NotEqual); 290 cmp32(tag, ImmTag(JSVAL_TAG_STRING)); 291 return cond; 292 } testSymbol(Condition cond,Register tag)293 Condition testSymbol(Condition cond, Register tag) { 294 MOZ_ASSERT(cond == Equal || cond == NotEqual); 295 cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL)); 296 return cond; 297 } testObject(Condition cond,Register tag)298 Condition testObject(Condition cond, Register tag) { 299 MOZ_ASSERT(cond == Equal || cond == NotEqual); 300 cmp32(tag, ImmTag(JSVAL_TAG_OBJECT)); 301 return cond; 302 } testNumber(Condition cond,Register tag)303 Condition testNumber(Condition cond, Register tag) { 304 MOZ_ASSERT(cond == Equal || cond == NotEqual); 305 cmp32(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); 306 return cond == Equal ? BelowOrEqual : Above; 307 } testGCThing(Condition cond,Register tag)308 Condition testGCThing(Condition cond, Register tag) { 309 MOZ_ASSERT(cond == Equal || cond == NotEqual); 310 cmp32(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 311 return cond == Equal ? AboveOrEqual : Below; 312 } testGCThing(Condition cond,const Address & address)313 Condition testGCThing(Condition cond, const Address& address) { 314 MOZ_ASSERT(cond == Equal || cond == NotEqual); 315 cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 316 return cond == Equal ? AboveOrEqual : Below; 317 } testMagic(Condition cond,const Address & address)318 Condition testMagic(Condition cond, const Address& address) { 319 MOZ_ASSERT(cond == Equal || cond == NotEqual); 320 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 321 return cond; 322 } testMagic(Condition cond,Register tag)323 Condition testMagic(Condition cond, Register tag) { 324 MOZ_ASSERT(cond == Equal || cond == NotEqual); 325 cmp32(tag, ImmTag(JSVAL_TAG_MAGIC)); 326 return cond; 327 } testMagic(Condition cond,const Operand & operand)328 Condition testMagic(Condition cond, const Operand& operand) { 329 MOZ_ASSERT(cond == Equal || cond == NotEqual); 330 cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC)); 331 return cond; 332 } testPrimitive(Condition cond,Register tag)333 Condition testPrimitive(Condition cond, Register tag) { 334 MOZ_ASSERT(cond == Equal || cond == NotEqual); 335 cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); 336 return cond == Equal ? Below : AboveOrEqual; 337 } testError(Condition cond,Register tag)338 Condition testError(Condition cond, Register tag) { 339 return testMagic(cond, tag); 340 } testBoolean(Condition cond,const Address & address)341 Condition testBoolean(Condition cond, const Address& address) { 342 MOZ_ASSERT(cond == Equal || cond == NotEqual); 343 cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN)); 344 return cond; 345 } testInt32(Condition cond,const Operand & operand)346 Condition testInt32(Condition cond, const Operand& operand) { 347 MOZ_ASSERT(cond == Equal || cond == NotEqual); 348 cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32)); 349 return cond; 350 } testInt32(Condition cond,const Address & address)351 Condition testInt32(Condition cond, const Address& address) { 352 MOZ_ASSERT(cond == Equal || cond == NotEqual); 353 return testInt32(cond, Operand(address)); 354 } testObject(Condition cond,const Operand & operand)355 Condition testObject(Condition cond, const Operand& operand) { 356 MOZ_ASSERT(cond == Equal || cond == NotEqual); 357 cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT)); 358 return cond; 359 } testObject(Condition cond,const Address & address)360 Condition testObject(Condition cond, const Address& address) { 361 MOZ_ASSERT(cond == Equal || cond == NotEqual); 362 return testObject(cond, Operand(address)); 363 } testDouble(Condition cond,const Operand & operand)364 Condition testDouble(Condition cond, const Operand& operand) { 365 MOZ_ASSERT(cond == Equal || cond == NotEqual); 366 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 367 cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR)); 368 return actual; 369 } testDouble(Condition cond,const Address & address)370 Condition testDouble(Condition cond, const Address& address) { 371 MOZ_ASSERT(cond == Equal || cond == NotEqual); 372 return testDouble(cond, Operand(address)); 373 } 374 375 testUndefined(Condition cond,const Operand & operand)376 Condition testUndefined(Condition cond, const Operand& operand) { 377 MOZ_ASSERT(cond == Equal || cond == NotEqual); 378 cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); 379 return cond; 380 } testUndefined(Condition cond,const Address & addr)381 Condition testUndefined(Condition cond, const Address& addr) { 382 return testUndefined(cond, Operand(addr)); 383 } testNull(Condition cond,const Operand & operand)384 Condition testNull(Condition cond, const Operand& operand) { 385 MOZ_ASSERT(cond == Equal || cond == NotEqual); 386 cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL)); 387 return cond; 388 } testNull(Condition cond,const Address & addr)389 Condition testNull(Condition cond, const Address& addr) { 390 return testNull(cond, Operand(addr)); 391 } 392 testUndefined(Condition cond,const ValueOperand & value)393 Condition testUndefined(Condition cond, const ValueOperand& value) { 394 return testUndefined(cond, value.typeReg()); 395 } testBoolean(Condition cond,const ValueOperand & value)396 Condition testBoolean(Condition cond, const ValueOperand& value) { 397 return testBoolean(cond, value.typeReg()); 398 } testInt32(Condition cond,const ValueOperand & value)399 Condition testInt32(Condition cond, const ValueOperand& value) { 400 return testInt32(cond, value.typeReg()); 401 } testDouble(Condition cond,const ValueOperand & value)402 Condition testDouble(Condition cond, const ValueOperand& value) { 403 return testDouble(cond, value.typeReg()); 404 } testNull(Condition cond,const ValueOperand & value)405 Condition testNull(Condition cond, const ValueOperand& value) { 406 return testNull(cond, value.typeReg()); 407 } testString(Condition cond,const ValueOperand & value)408 Condition testString(Condition cond, const ValueOperand& value) { 409 return testString(cond, value.typeReg()); 410 } testSymbol(Condition cond,const ValueOperand & value)411 Condition testSymbol(Condition cond, const ValueOperand& value) { 412 return testSymbol(cond, value.typeReg()); 413 } testObject(Condition cond,const ValueOperand & value)414 Condition testObject(Condition cond, const ValueOperand& value) { 415 return testObject(cond, value.typeReg()); 416 } testMagic(Condition cond,const ValueOperand & value)417 Condition testMagic(Condition cond, const ValueOperand& value) { 418 return testMagic(cond, value.typeReg()); 419 } testError(Condition cond,const ValueOperand & value)420 Condition testError(Condition cond, const ValueOperand& value) { 421 return testMagic(cond, value); 422 } testNumber(Condition cond,const ValueOperand & value)423 Condition testNumber(Condition cond, const ValueOperand& value) { 424 return testNumber(cond, value.typeReg()); 425 } testGCThing(Condition cond,const ValueOperand & value)426 Condition testGCThing(Condition cond, const ValueOperand& value) { 427 return testGCThing(cond, value.typeReg()); 428 } testPrimitive(Condition cond,const ValueOperand & value)429 Condition testPrimitive(Condition cond, const ValueOperand& value) { 430 return testPrimitive(cond, value.typeReg()); 431 } 432 433 testUndefined(Condition cond,const BaseIndex & address)434 Condition testUndefined(Condition cond, const BaseIndex& address) { 435 MOZ_ASSERT(cond == Equal || cond == NotEqual); 436 cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); 437 return cond; 438 } testNull(Condition cond,const BaseIndex & address)439 Condition testNull(Condition cond, const BaseIndex& address) { 440 MOZ_ASSERT(cond == Equal || cond == NotEqual); 441 cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL)); 442 return cond; 443 } testBoolean(Condition cond,const BaseIndex & address)444 Condition testBoolean(Condition cond, const BaseIndex& address) { 445 MOZ_ASSERT(cond == Equal || cond == NotEqual); 446 cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); 447 return cond; 448 } testString(Condition cond,const BaseIndex & address)449 Condition testString(Condition cond, const BaseIndex& address) { 450 MOZ_ASSERT(cond == Equal || cond == NotEqual); 451 cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING)); 452 return cond; 453 } testSymbol(Condition cond,const BaseIndex & address)454 Condition testSymbol(Condition cond, const BaseIndex& address) { 455 MOZ_ASSERT(cond == Equal || cond == NotEqual); 456 cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL)); 457 return cond; 458 } testInt32(Condition cond,const BaseIndex & address)459 Condition testInt32(Condition cond, const BaseIndex& address) { 460 MOZ_ASSERT(cond == Equal || cond == NotEqual); 461 cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32)); 462 return cond; 463 } testObject(Condition cond,const BaseIndex & address)464 Condition testObject(Condition cond, const BaseIndex& address) { 465 MOZ_ASSERT(cond == Equal || cond == NotEqual); 466 cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); 467 return cond; 468 } testDouble(Condition cond,const BaseIndex & address)469 Condition testDouble(Condition cond, const BaseIndex& address) { 470 MOZ_ASSERT(cond == Equal || cond == NotEqual); 471 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 472 cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); 473 return actual; 474 } testMagic(Condition cond,const BaseIndex & address)475 Condition testMagic(Condition cond, const BaseIndex& address) { 476 MOZ_ASSERT(cond == Equal || cond == NotEqual); 477 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 478 return cond; 479 } testGCThing(Condition cond,const BaseIndex & address)480 Condition testGCThing(Condition cond, const BaseIndex& address) { 481 MOZ_ASSERT(cond == Equal || cond == NotEqual); 482 cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 483 return cond == Equal ? AboveOrEqual : Below; 484 } 485 testNullSet(Condition cond,const ValueOperand & value,Register dest)486 void testNullSet(Condition cond, const ValueOperand& value, Register dest) { 487 cond = testNull(cond, value); 488 emitSet(cond, dest); 489 } 490 testObjectSet(Condition cond,const ValueOperand & value,Register dest)491 void testObjectSet(Condition cond, const ValueOperand& value, Register dest) { 492 cond = testObject(cond, value); 493 emitSet(cond, dest); 494 } 495 testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)496 void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) { 497 cond = testUndefined(cond, value); 498 emitSet(cond, dest); 499 } 500 cmpPtr(Register lhs,const ImmWord rhs)501 void cmpPtr(Register lhs, const ImmWord rhs) { 502 cmpl(Imm32(rhs.value), lhs); 503 } cmpPtr(Register lhs,const ImmPtr imm)504 void cmpPtr(Register lhs, const ImmPtr imm) { 505 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 506 } cmpPtr(Register lhs,const ImmGCPtr rhs)507 void cmpPtr(Register lhs, const ImmGCPtr rhs) { 508 cmpl(rhs, lhs); 509 } cmpPtr(const Operand & lhs,Imm32 rhs)510 void cmpPtr(const Operand& lhs, Imm32 rhs) { 511 cmp32(lhs, rhs); 512 } cmpPtr(const Operand & lhs,const ImmWord rhs)513 void cmpPtr(const Operand& lhs, const ImmWord rhs) { 514 cmp32(lhs, Imm32(rhs.value)); 515 } cmpPtr(const Operand & lhs,const ImmPtr imm)516 void cmpPtr(const Operand& lhs, const ImmPtr imm) { 517 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 518 } cmpPtr(const Operand & lhs,const ImmGCPtr rhs)519 void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { 520 cmpl(rhs, lhs); 521 } cmpPtr(const Address & lhs,Register rhs)522 void cmpPtr(const Address& lhs, Register rhs) { 523 cmpPtr(Operand(lhs), rhs); 524 } cmpPtr(const Operand & lhs,Register rhs)525 void cmpPtr(const Operand& lhs, Register rhs) { 526 cmp32(lhs, rhs); 527 } cmpPtr(const Address & lhs,const ImmWord rhs)528 void cmpPtr(const Address& lhs, const ImmWord rhs) { 529 cmpPtr(Operand(lhs), rhs); 530 } cmpPtr(const Address & lhs,const ImmPtr rhs)531 void cmpPtr(const Address& lhs, const ImmPtr rhs) { 532 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 533 } cmpPtr(const Address & lhs,const ImmGCPtr rhs)534 void cmpPtr(const Address& lhs, const ImmGCPtr rhs) { 535 cmpPtr(Operand(lhs), rhs); 536 } cmpPtr(Register lhs,Register rhs)537 void cmpPtr(Register lhs, Register rhs) { 538 cmp32(lhs, rhs); 539 } testPtr(Register lhs,Register rhs)540 void testPtr(Register lhs, Register rhs) { 541 test32(lhs, rhs); 542 } testPtr(Register lhs,Imm32 rhs)543 void testPtr(Register lhs, Imm32 rhs) { 544 test32(lhs, rhs); 545 } testPtr(Register lhs,ImmWord rhs)546 void testPtr(Register lhs, ImmWord rhs) { 547 test32(lhs, Imm32(rhs.value)); 548 } testPtr(const Operand & lhs,Imm32 rhs)549 void testPtr(const Operand& lhs, Imm32 rhs) { 550 test32(lhs, rhs); 551 } testPtr(const Operand & lhs,ImmWord rhs)552 void testPtr(const Operand& lhs, ImmWord rhs) { 553 test32(lhs, Imm32(rhs.value)); 554 } 555 556 ///////////////////////////////////////////////////////////////// 557 // Common interface. 558 ///////////////////////////////////////////////////////////////// 559 560 template <typename T, typename S> branchPtr(Condition cond,T lhs,S ptr,RepatchLabel * label)561 void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel* label) { 562 cmpPtr(Operand(lhs), ptr); 563 j(cond, label); 564 } 565 566 CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) { 567 jump(label); 568 return CodeOffsetJump(size()); 569 } 570 571 CodeOffsetJump jumpWithPatch(RepatchLabel* label, Assembler::Condition cond, 572 Label* documentation = nullptr) 573 { 574 j(cond, label); 575 return CodeOffsetJump(size()); 576 } 577 578 CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) { 579 return jumpWithPatch(label); 580 } 581 branchPtr(Condition cond,Register lhs,Register rhs,RepatchLabel * label)582 void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) { 583 cmpPtr(lhs, rhs); 584 j(cond, label); 585 } 586 movePtr(ImmWord imm,Register dest)587 void movePtr(ImmWord imm, Register dest) { 588 movl(Imm32(imm.value), dest); 589 } movePtr(ImmPtr imm,Register dest)590 void movePtr(ImmPtr imm, Register dest) { 591 movl(imm, dest); 592 } movePtr(wasm::SymbolicAddress imm,Register dest)593 void movePtr(wasm::SymbolicAddress imm, Register dest) { 594 mov(imm, dest); 595 } movePtr(ImmGCPtr imm,Register dest)596 void movePtr(ImmGCPtr imm, Register dest) { 597 movl(imm, dest); 598 } loadPtr(const Address & address,Register dest)599 void loadPtr(const Address& address, Register dest) { 600 movl(Operand(address), dest); 601 } loadPtr(const Operand & src,Register dest)602 void loadPtr(const Operand& src, Register dest) { 603 movl(src, dest); 604 } loadPtr(const BaseIndex & src,Register dest)605 void loadPtr(const BaseIndex& src, Register dest) { 606 movl(Operand(src), dest); 607 } loadPtr(AbsoluteAddress address,Register dest)608 void loadPtr(AbsoluteAddress address, Register dest) { 609 movl(Operand(address), dest); 610 } loadPrivate(const Address & src,Register dest)611 void loadPrivate(const Address& src, Register dest) { 612 movl(payloadOf(src), dest); 613 } load32(AbsoluteAddress address,Register dest)614 void load32(AbsoluteAddress address, Register dest) { 615 movl(Operand(address), dest); 616 } load64(const Address & address,Register64 dest)617 void load64(const Address& address, Register64 dest) { 618 movl(Operand(Address(address.base, address.offset + INT64LOW_OFFSET)), dest.low); 619 int32_t highOffset = (address.offset < 0) ? -int32_t(INT64HIGH_OFFSET) : INT64HIGH_OFFSET; 620 movl(Operand(Address(address.base, address.offset + highOffset)), dest.high); 621 } 622 template <typename T> storePtr(ImmWord imm,T address)623 void storePtr(ImmWord imm, T address) { 624 movl(Imm32(imm.value), Operand(address)); 625 } 626 template <typename T> storePtr(ImmPtr imm,T address)627 void storePtr(ImmPtr imm, T address) { 628 storePtr(ImmWord(uintptr_t(imm.value)), address); 629 } 630 template <typename T> storePtr(ImmGCPtr imm,T address)631 void storePtr(ImmGCPtr imm, T address) { 632 movl(imm, Operand(address)); 633 } storePtr(Register src,const Address & address)634 void storePtr(Register src, const Address& address) { 635 movl(src, Operand(address)); 636 } storePtr(Register src,const BaseIndex & address)637 void storePtr(Register src, const BaseIndex& address) { 638 movl(src, Operand(address)); 639 } storePtr(Register src,const Operand & dest)640 void storePtr(Register src, const Operand& dest) { 641 movl(src, dest); 642 } storePtr(Register src,AbsoluteAddress address)643 void storePtr(Register src, AbsoluteAddress address) { 644 movl(src, Operand(address)); 645 } store32(Register src,AbsoluteAddress address)646 void store32(Register src, AbsoluteAddress address) { 647 movl(src, Operand(address)); 648 } store16(Register src,AbsoluteAddress address)649 void store16(Register src, AbsoluteAddress address) { 650 movw(src, Operand(address)); 651 } store64(Register64 src,Address address)652 void store64(Register64 src, Address address) { 653 movl(src.low, Operand(Address(address.base, address.offset + INT64LOW_OFFSET))); 654 movl(src.high, Operand(Address(address.base, address.offset + INT64HIGH_OFFSET))); 655 } store64(Imm64 imm,Address address)656 void store64(Imm64 imm, Address address) { 657 movl(imm.low(), Operand(Address(address.base, address.offset + INT64LOW_OFFSET))); 658 movl(imm.hi(), Operand(Address(address.base, address.offset + INT64HIGH_OFFSET))); 659 } 660 setStackArg(Register reg,uint32_t arg)661 void setStackArg(Register reg, uint32_t arg) { 662 movl(reg, Operand(esp, arg * sizeof(intptr_t))); 663 } 664 665 // Note: this function clobbers the source register. boxDouble(FloatRegister src,const ValueOperand & dest)666 void boxDouble(FloatRegister src, const ValueOperand& dest) { 667 if (Assembler::HasSSE41()) { 668 vmovd(src, dest.payloadReg()); 669 vpextrd(1, src, dest.typeReg()); 670 } else { 671 vmovd(src, dest.payloadReg()); 672 vpsrldq(Imm32(4), src, src); 673 vmovd(src, dest.typeReg()); 674 } 675 } boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)676 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) { 677 if (src != dest.payloadReg()) 678 movl(src, dest.payloadReg()); 679 movl(ImmType(type), dest.typeReg()); 680 } 681 unboxNonDouble(const ValueOperand & src,Register dest)682 void unboxNonDouble(const ValueOperand& src, Register dest) { 683 if (src.payloadReg() != dest) 684 movl(src.payloadReg(), dest); 685 } unboxNonDouble(const Address & src,Register dest)686 void unboxNonDouble(const Address& src, Register dest) { 687 movl(payloadOf(src), dest); 688 } unboxNonDouble(const BaseIndex & src,Register dest)689 void unboxNonDouble(const BaseIndex& src, Register dest) { 690 movl(payloadOf(src), dest); 691 } unboxInt32(const ValueOperand & src,Register dest)692 void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxInt32(const Address & src,Register dest)693 void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxBoolean(const ValueOperand & src,Register dest)694 void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxBoolean(const Address & src,Register dest)695 void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxString(const ValueOperand & src,Register dest)696 void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxString(const Address & src,Register dest)697 void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxSymbol(const ValueOperand & src,Register dest)698 void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxSymbol(const Address & src,Register dest)699 void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const ValueOperand & src,Register dest)700 void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const Address & src,Register dest)701 void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const BaseIndex & src,Register dest)702 void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); } unboxDouble(const Address & src,FloatRegister dest)703 void unboxDouble(const Address& src, FloatRegister dest) { 704 loadDouble(Operand(src), dest); 705 } unboxDouble(const ValueOperand & src,FloatRegister dest)706 void unboxDouble(const ValueOperand& src, FloatRegister dest) { 707 MOZ_ASSERT(dest != ScratchDoubleReg); 708 if (Assembler::HasSSE41()) { 709 vmovd(src.payloadReg(), dest); 710 vpinsrd(1, src.typeReg(), dest, dest); 711 } else { 712 vmovd(src.payloadReg(), dest); 713 vmovd(src.typeReg(), ScratchDoubleReg); 714 vunpcklps(ScratchDoubleReg, dest, dest); 715 } 716 } unboxDouble(const Operand & payload,const Operand & type,Register scratch,FloatRegister dest)717 void unboxDouble(const Operand& payload, const Operand& type, 718 Register scratch, FloatRegister dest) { 719 MOZ_ASSERT(dest != ScratchDoubleReg); 720 if (Assembler::HasSSE41()) { 721 movl(payload, scratch); 722 vmovd(scratch, dest); 723 movl(type, scratch); 724 vpinsrd(1, scratch, dest, dest); 725 } else { 726 movl(payload, scratch); 727 vmovd(scratch, dest); 728 movl(type, scratch); 729 vmovd(scratch, ScratchDoubleReg); 730 vunpcklps(ScratchDoubleReg, dest, dest); 731 } 732 } 733 inline void unboxValue(const ValueOperand& src, AnyRegister dest); unboxPrivate(const ValueOperand & src,Register dest)734 void unboxPrivate(const ValueOperand& src, Register dest) { 735 if (src.payloadReg() != dest) 736 movl(src.payloadReg(), dest); 737 } 738 notBoolean(const ValueOperand & val)739 void notBoolean(const ValueOperand& val) { 740 xorl(Imm32(1), val.payloadReg()); 741 } 742 743 // Extended unboxing API. If the payload is already in a register, returns 744 // that register. Otherwise, provides a move to the given scratch register, 745 // and returns that. extractObject(const Address & address,Register scratch)746 Register extractObject(const Address& address, Register scratch) { 747 movl(payloadOf(address), scratch); 748 return scratch; 749 } extractObject(const ValueOperand & value,Register scratch)750 Register extractObject(const ValueOperand& value, Register scratch) { 751 return value.payloadReg(); 752 } extractInt32(const ValueOperand & value,Register scratch)753 Register extractInt32(const ValueOperand& value, Register scratch) { 754 return value.payloadReg(); 755 } extractBoolean(const ValueOperand & value,Register scratch)756 Register extractBoolean(const ValueOperand& value, Register scratch) { 757 return value.payloadReg(); 758 } extractTag(const Address & address,Register scratch)759 Register extractTag(const Address& address, Register scratch) { 760 movl(tagOf(address), scratch); 761 return scratch; 762 } extractTag(const ValueOperand & value,Register scratch)763 Register extractTag(const ValueOperand& value, Register scratch) { 764 return value.typeReg(); 765 } 766 boolValueToDouble(const ValueOperand & operand,FloatRegister dest)767 void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) { 768 convertInt32ToDouble(operand.payloadReg(), dest); 769 } boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)770 void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 771 convertInt32ToFloat32(operand.payloadReg(), dest); 772 } int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)773 void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) { 774 convertInt32ToDouble(operand.payloadReg(), dest); 775 } int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)776 void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 777 convertInt32ToFloat32(operand.payloadReg(), dest); 778 } 779 780 void loadConstantDouble(double d, FloatRegister dest); 781 void loadConstantFloat32(float f, FloatRegister dest); 782 void loadConstantDouble(wasm::RawF64 d, FloatRegister dest); 783 void loadConstantFloat32(wasm::RawF32 f, FloatRegister dest); 784 785 void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest); 786 void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest); 787 testInt32Truthy(bool truthy,const ValueOperand & operand)788 Condition testInt32Truthy(bool truthy, const ValueOperand& operand) { 789 test32(operand.payloadReg(), operand.payloadReg()); 790 return truthy ? NonZero : Zero; 791 } testStringTruthy(bool truthy,const ValueOperand & value)792 Condition testStringTruthy(bool truthy, const ValueOperand& value) { 793 Register string = value.payloadReg(); 794 cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0)); 795 return truthy ? Assembler::NotEqual : Assembler::Equal; 796 } 797 798 template <typename T> 799 inline void loadInt32OrDouble(const T& src, FloatRegister dest); 800 801 template <typename T> 802 inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest); 803 804 template <typename T> storeUnboxedPayload(ValueOperand value,T address,size_t nbytes)805 void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) { 806 switch (nbytes) { 807 case 4: 808 storePtr(value.payloadReg(), address); 809 return; 810 case 1: 811 store8(value.payloadReg(), address); 812 return; 813 default: MOZ_CRASH("Bad payload width"); 814 } 815 } 816 loadInstructionPointerAfterCall(Register dest)817 void loadInstructionPointerAfterCall(Register dest) { 818 movl(Operand(StackPointer, 0x0), dest); 819 } 820 821 // Note: this function clobbers the source register. 822 inline void convertUInt32ToDouble(Register src, FloatRegister dest); 823 824 // Note: this function clobbers the source register. 825 inline void convertUInt32ToFloat32(Register src, FloatRegister dest); 826 827 void convertUInt64ToFloat32(Register64 src, FloatRegister dest, Register temp); 828 void convertInt64ToFloat32(Register64 src, FloatRegister dest); 829 static bool convertUInt64ToDoubleNeedsTemp(); 830 void convertUInt64ToDouble(Register64 src, FloatRegister dest, Register temp); 831 void convertInt64ToDouble(Register64 src, FloatRegister dest); 832 833 void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry, 834 Label* oolRejoin, FloatRegister tempDouble); 835 void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry, 836 Label* oolRejoin, FloatRegister tempDouble); 837 void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry, 838 Label* oolRejoin, FloatRegister tempDouble); 839 void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry, 840 Label* oolRejoin, FloatRegister tempDouble); 841 incrementInt32Value(const Address & addr)842 void incrementInt32Value(const Address& addr) { 843 addl(Imm32(1), payloadOf(addr)); 844 } 845 846 inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); 847 loadWasmGlobalPtr(uint32_t globalDataOffset,Register dest)848 void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { 849 CodeOffset label = movlWithPatch(PatchedAbsoluteAddress(), dest); 850 append(wasm::GlobalAccess(label, globalDataOffset)); 851 } loadWasmPinnedRegsFromTls()852 void loadWasmPinnedRegsFromTls() { 853 // x86 doesn't have any pinned registers. 854 } 855 856 public: 857 // Used from within an Exit frame to handle a pending exception. 858 void handleFailureWithHandlerTail(void* handler); 859 860 // Instrumentation for entering and leaving the profiler. 861 void profilerEnterFrame(Register framePtr, Register scratch); 862 void profilerExitFrame(); 863 }; 864 865 typedef MacroAssemblerX86 MacroAssemblerSpecific; 866 867 } // namespace jit 868 } // namespace js 869 870 #endif /* jit_x86_MacroAssembler_x86_h */ 871