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::branch32; 54 using MacroAssemblerX86Shared::branchTest32; 55 using MacroAssemblerX86Shared::load32; 56 using MacroAssemblerX86Shared::store32; 57 using MacroAssemblerX86Shared::call; 58 MacroAssemblerX86()59 MacroAssemblerX86() 60 { 61 } 62 63 // The buffer is about to be linked, make sure any constant pools or excess 64 // bookkeeping has been flushed to the instruction stream. 65 void finish(); 66 67 ///////////////////////////////////////////////////////////////// 68 // X86-specific interface. 69 ///////////////////////////////////////////////////////////////// 70 ToPayload(Operand base)71 Operand ToPayload(Operand base) { 72 return base; 73 } ToPayload(Address base)74 Address ToPayload(Address base) { 75 return base; 76 } ToType(Operand base)77 Operand ToType(Operand base) { 78 switch (base.kind()) { 79 case Operand::MEM_REG_DISP: 80 return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void*)); 81 82 case Operand::MEM_SCALE: 83 return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), 84 base.scale(), base.disp() + sizeof(void*)); 85 86 default: 87 MOZ_CRASH("unexpected operand kind"); 88 } 89 } ToType(Address base)90 Address ToType(Address base) { 91 return ToType(Operand(base)).toAddress(); 92 } moveValue(const Value & val,Register type,Register data)93 void moveValue(const Value& val, Register type, Register data) { 94 jsval_layout jv = JSVAL_TO_IMPL(val); 95 movl(Imm32(jv.s.tag), type); 96 if (val.isMarkable()) 97 movl(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing())), data); 98 else 99 movl(Imm32(jv.s.payload.i32), data); 100 } moveValue(const Value & val,const ValueOperand & dest)101 void moveValue(const Value& val, const ValueOperand& dest) { 102 moveValue(val, dest.typeReg(), dest.payloadReg()); 103 } moveValue(const ValueOperand & src,const ValueOperand & dest)104 void moveValue(const ValueOperand& src, const ValueOperand& dest) { 105 Register s0 = src.typeReg(), d0 = dest.typeReg(), 106 s1 = src.payloadReg(), d1 = dest.payloadReg(); 107 108 // Either one or both of the source registers could be the same as a 109 // destination register. 110 if (s1 == d0) { 111 if (s0 == d1) { 112 // If both are, this is just a swap of two registers. 113 xchgl(d0, d1); 114 return; 115 } 116 // If only one is, copy that source first. 117 mozilla::Swap(s0, s1); 118 mozilla::Swap(d0, d1); 119 } 120 121 if (s0 != d0) 122 movl(s0, d0); 123 if (s1 != d1) 124 movl(s1, d1); 125 } 126 127 ///////////////////////////////////////////////////////////////// 128 // X86/X64-common interface. 129 ///////////////////////////////////////////////////////////////// storeValue(ValueOperand val,Operand dest)130 void storeValue(ValueOperand val, Operand dest) { 131 movl(val.payloadReg(), ToPayload(dest)); 132 movl(val.typeReg(), ToType(dest)); 133 } storeValue(ValueOperand val,const Address & dest)134 void storeValue(ValueOperand val, const Address& dest) { 135 storeValue(val, Operand(dest)); 136 } 137 template <typename T> storeValue(JSValueType type,Register reg,const T & dest)138 void storeValue(JSValueType type, Register reg, const T& dest) { 139 storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest)); 140 storePayload(reg, Operand(dest)); 141 } 142 template <typename T> storeValue(const Value & val,const T & dest)143 void storeValue(const Value& val, const T& dest) { 144 jsval_layout jv = JSVAL_TO_IMPL(val); 145 storeTypeTag(ImmTag(jv.s.tag), 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 } loadValue(Operand src,ValueOperand val)151 void loadValue(Operand src, ValueOperand val) { 152 Operand payload = ToPayload(src); 153 Operand type = ToType(src); 154 155 // Ensure that loading the payload does not erase the pointer to the 156 // Value in memory or the index. 157 Register baseReg = Register::FromCode(src.base()); 158 Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg; 159 160 if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) { 161 MOZ_ASSERT(baseReg != val.typeReg()); 162 MOZ_ASSERT(indexReg != val.typeReg()); 163 164 movl(type, val.typeReg()); 165 movl(payload, val.payloadReg()); 166 } else { 167 MOZ_ASSERT(baseReg != val.payloadReg()); 168 MOZ_ASSERT(indexReg != val.payloadReg()); 169 170 movl(payload, val.payloadReg()); 171 movl(type, val.typeReg()); 172 } 173 } loadValue(Address src,ValueOperand val)174 void loadValue(Address src, ValueOperand val) { 175 loadValue(Operand(src), val); 176 } loadValue(const BaseIndex & src,ValueOperand val)177 void loadValue(const BaseIndex& src, ValueOperand val) { 178 loadValue(Operand(src), val); 179 } tagValue(JSValueType type,Register payload,ValueOperand dest)180 void tagValue(JSValueType type, Register payload, ValueOperand dest) { 181 MOZ_ASSERT(dest.typeReg() != dest.payloadReg()); 182 if (payload != dest.payloadReg()) 183 movl(payload, dest.payloadReg()); 184 movl(ImmType(type), dest.typeReg()); 185 } pushValue(ValueOperand val)186 void pushValue(ValueOperand val) { 187 push(val.typeReg()); 188 push(val.payloadReg()); 189 } popValue(ValueOperand val)190 void popValue(ValueOperand val) { 191 pop(val.payloadReg()); 192 pop(val.typeReg()); 193 } pushValue(const Value & val)194 void pushValue(const Value& val) { 195 jsval_layout jv = JSVAL_TO_IMPL(val); 196 push(Imm32(jv.s.tag)); 197 if (val.isMarkable()) 198 push(ImmGCPtr(reinterpret_cast<gc::Cell*>(val.toGCThing()))); 199 else 200 push(Imm32(jv.s.payload.i32)); 201 } pushValue(JSValueType type,Register reg)202 void pushValue(JSValueType type, Register reg) { 203 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); 204 push(reg); 205 } pushValue(const Address & addr)206 void pushValue(const Address& addr) { 207 push(tagOf(addr)); 208 push(payloadOfAfterStackPush(addr)); 209 } push64(Register64 src)210 void push64(Register64 src) { 211 push(src.high); 212 push(src.low); 213 } pop64(Register64 dest)214 void pop64(Register64 dest) { 215 pop(dest.low); 216 pop(dest.high); 217 } storePayload(const Value & val,Operand dest)218 void storePayload(const Value& val, Operand dest) { 219 jsval_layout jv = JSVAL_TO_IMPL(val); 220 if (val.isMarkable()) 221 movl(ImmGCPtr((gc::Cell*)jv.s.payload.ptr), ToPayload(dest)); 222 else 223 movl(Imm32(jv.s.payload.i32), ToPayload(dest)); 224 } storePayload(Register src,Operand dest)225 void storePayload(Register src, Operand dest) { 226 movl(src, ToPayload(dest)); 227 } storeTypeTag(ImmTag tag,Operand dest)228 void storeTypeTag(ImmTag tag, Operand dest) { 229 movl(tag, ToType(dest)); 230 } 231 movePtr(Register src,Register dest)232 void movePtr(Register src, Register dest) { 233 movl(src, dest); 234 } movePtr(Register src,const Operand & dest)235 void movePtr(Register src, const Operand& dest) { 236 movl(src, dest); 237 } 238 239 // Returns the register containing the type tag. splitTagForTest(const ValueOperand & value)240 Register splitTagForTest(const ValueOperand& value) { 241 return value.typeReg(); 242 } 243 testUndefined(Condition cond,Register tag)244 Condition testUndefined(Condition cond, Register tag) { 245 MOZ_ASSERT(cond == Equal || cond == NotEqual); 246 cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 247 return cond; 248 } testBoolean(Condition cond,Register tag)249 Condition testBoolean(Condition cond, Register tag) { 250 MOZ_ASSERT(cond == Equal || cond == NotEqual); 251 cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 252 return cond; 253 } testInt32(Condition cond,Register tag)254 Condition testInt32(Condition cond, Register tag) { 255 MOZ_ASSERT(cond == Equal || cond == NotEqual); 256 cmp32(tag, ImmTag(JSVAL_TAG_INT32)); 257 return cond; 258 } testDouble(Condition cond,Register tag)259 Condition testDouble(Condition cond, Register tag) { 260 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); 261 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 262 cmp32(tag, ImmTag(JSVAL_TAG_CLEAR)); 263 return actual; 264 } testNull(Condition cond,Register tag)265 Condition testNull(Condition cond, Register tag) { 266 MOZ_ASSERT(cond == Equal || cond == NotEqual); 267 cmp32(tag, ImmTag(JSVAL_TAG_NULL)); 268 return cond; 269 } testString(Condition cond,Register tag)270 Condition testString(Condition cond, Register tag) { 271 MOZ_ASSERT(cond == Equal || cond == NotEqual); 272 cmp32(tag, ImmTag(JSVAL_TAG_STRING)); 273 return cond; 274 } testSymbol(Condition cond,Register tag)275 Condition testSymbol(Condition cond, Register tag) { 276 MOZ_ASSERT(cond == Equal || cond == NotEqual); 277 cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL)); 278 return cond; 279 } testObject(Condition cond,Register tag)280 Condition testObject(Condition cond, Register tag) { 281 MOZ_ASSERT(cond == Equal || cond == NotEqual); 282 cmp32(tag, ImmTag(JSVAL_TAG_OBJECT)); 283 return cond; 284 } testNumber(Condition cond,Register tag)285 Condition testNumber(Condition cond, Register tag) { 286 MOZ_ASSERT(cond == Equal || cond == NotEqual); 287 cmp32(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); 288 return cond == Equal ? BelowOrEqual : Above; 289 } testGCThing(Condition cond,Register tag)290 Condition testGCThing(Condition cond, Register tag) { 291 MOZ_ASSERT(cond == Equal || cond == NotEqual); 292 cmp32(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 293 return cond == Equal ? AboveOrEqual : Below; 294 } testGCThing(Condition cond,const Address & address)295 Condition testGCThing(Condition cond, const Address& address) { 296 MOZ_ASSERT(cond == Equal || cond == NotEqual); 297 cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 298 return cond == Equal ? AboveOrEqual : Below; 299 } testMagic(Condition cond,const Address & address)300 Condition testMagic(Condition cond, const Address& address) { 301 MOZ_ASSERT(cond == Equal || cond == NotEqual); 302 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 303 return cond; 304 } testMagic(Condition cond,Register tag)305 Condition testMagic(Condition cond, Register tag) { 306 MOZ_ASSERT(cond == Equal || cond == NotEqual); 307 cmp32(tag, ImmTag(JSVAL_TAG_MAGIC)); 308 return cond; 309 } testMagic(Condition cond,const Operand & operand)310 Condition testMagic(Condition cond, const Operand& operand) { 311 MOZ_ASSERT(cond == Equal || cond == NotEqual); 312 cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC)); 313 return cond; 314 } testPrimitive(Condition cond,Register tag)315 Condition testPrimitive(Condition cond, Register tag) { 316 MOZ_ASSERT(cond == Equal || cond == NotEqual); 317 cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); 318 return cond == Equal ? Below : AboveOrEqual; 319 } testError(Condition cond,Register tag)320 Condition testError(Condition cond, Register tag) { 321 return testMagic(cond, tag); 322 } testBoolean(Condition cond,const Address & address)323 Condition testBoolean(Condition cond, const Address& address) { 324 MOZ_ASSERT(cond == Equal || cond == NotEqual); 325 cmp32(Operand(ToType(address)), ImmTag(JSVAL_TAG_BOOLEAN)); 326 return cond; 327 } testInt32(Condition cond,const Operand & operand)328 Condition testInt32(Condition cond, const Operand& operand) { 329 MOZ_ASSERT(cond == Equal || cond == NotEqual); 330 cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32)); 331 return cond; 332 } testInt32(Condition cond,const Address & address)333 Condition testInt32(Condition cond, const Address& address) { 334 MOZ_ASSERT(cond == Equal || cond == NotEqual); 335 return testInt32(cond, Operand(address)); 336 } testObject(Condition cond,const Operand & operand)337 Condition testObject(Condition cond, const Operand& operand) { 338 MOZ_ASSERT(cond == Equal || cond == NotEqual); 339 cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT)); 340 return cond; 341 } testObject(Condition cond,const Address & address)342 Condition testObject(Condition cond, const Address& address) { 343 MOZ_ASSERT(cond == Equal || cond == NotEqual); 344 return testObject(cond, Operand(address)); 345 } testDouble(Condition cond,const Operand & operand)346 Condition testDouble(Condition cond, const Operand& operand) { 347 MOZ_ASSERT(cond == Equal || cond == NotEqual); 348 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 349 cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR)); 350 return actual; 351 } testDouble(Condition cond,const Address & address)352 Condition testDouble(Condition cond, const Address& address) { 353 MOZ_ASSERT(cond == Equal || cond == NotEqual); 354 return testDouble(cond, Operand(address)); 355 } 356 357 testUndefined(Condition cond,const Operand & operand)358 Condition testUndefined(Condition cond, const Operand& operand) { 359 MOZ_ASSERT(cond == Equal || cond == NotEqual); 360 cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); 361 return cond; 362 } testUndefined(Condition cond,const Address & addr)363 Condition testUndefined(Condition cond, const Address& addr) { 364 return testUndefined(cond, Operand(addr)); 365 } testNull(Condition cond,const Operand & operand)366 Condition testNull(Condition cond, const Operand& operand) { 367 MOZ_ASSERT(cond == Equal || cond == NotEqual); 368 cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL)); 369 return cond; 370 } testNull(Condition cond,const Address & addr)371 Condition testNull(Condition cond, const Address& addr) { 372 return testNull(cond, Operand(addr)); 373 } 374 testUndefined(Condition cond,const ValueOperand & value)375 Condition testUndefined(Condition cond, const ValueOperand& value) { 376 return testUndefined(cond, value.typeReg()); 377 } testBoolean(Condition cond,const ValueOperand & value)378 Condition testBoolean(Condition cond, const ValueOperand& value) { 379 return testBoolean(cond, value.typeReg()); 380 } testInt32(Condition cond,const ValueOperand & value)381 Condition testInt32(Condition cond, const ValueOperand& value) { 382 return testInt32(cond, value.typeReg()); 383 } testDouble(Condition cond,const ValueOperand & value)384 Condition testDouble(Condition cond, const ValueOperand& value) { 385 return testDouble(cond, value.typeReg()); 386 } testNull(Condition cond,const ValueOperand & value)387 Condition testNull(Condition cond, const ValueOperand& value) { 388 return testNull(cond, value.typeReg()); 389 } testString(Condition cond,const ValueOperand & value)390 Condition testString(Condition cond, const ValueOperand& value) { 391 return testString(cond, value.typeReg()); 392 } testSymbol(Condition cond,const ValueOperand & value)393 Condition testSymbol(Condition cond, const ValueOperand& value) { 394 return testSymbol(cond, value.typeReg()); 395 } testObject(Condition cond,const ValueOperand & value)396 Condition testObject(Condition cond, const ValueOperand& value) { 397 return testObject(cond, value.typeReg()); 398 } testMagic(Condition cond,const ValueOperand & value)399 Condition testMagic(Condition cond, const ValueOperand& value) { 400 return testMagic(cond, value.typeReg()); 401 } testError(Condition cond,const ValueOperand & value)402 Condition testError(Condition cond, const ValueOperand& value) { 403 return testMagic(cond, value); 404 } testNumber(Condition cond,const ValueOperand & value)405 Condition testNumber(Condition cond, const ValueOperand& value) { 406 return testNumber(cond, value.typeReg()); 407 } testGCThing(Condition cond,const ValueOperand & value)408 Condition testGCThing(Condition cond, const ValueOperand& value) { 409 return testGCThing(cond, value.typeReg()); 410 } testPrimitive(Condition cond,const ValueOperand & value)411 Condition testPrimitive(Condition cond, const ValueOperand& value) { 412 return testPrimitive(cond, value.typeReg()); 413 } 414 415 testUndefined(Condition cond,const BaseIndex & address)416 Condition testUndefined(Condition cond, const BaseIndex& address) { 417 MOZ_ASSERT(cond == Equal || cond == NotEqual); 418 cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); 419 return cond; 420 } testNull(Condition cond,const BaseIndex & address)421 Condition testNull(Condition cond, const BaseIndex& address) { 422 MOZ_ASSERT(cond == Equal || cond == NotEqual); 423 cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL)); 424 return cond; 425 } testBoolean(Condition cond,const BaseIndex & address)426 Condition testBoolean(Condition cond, const BaseIndex& address) { 427 MOZ_ASSERT(cond == Equal || cond == NotEqual); 428 cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); 429 return cond; 430 } testString(Condition cond,const BaseIndex & address)431 Condition testString(Condition cond, const BaseIndex& address) { 432 MOZ_ASSERT(cond == Equal || cond == NotEqual); 433 cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING)); 434 return cond; 435 } testSymbol(Condition cond,const BaseIndex & address)436 Condition testSymbol(Condition cond, const BaseIndex& address) { 437 MOZ_ASSERT(cond == Equal || cond == NotEqual); 438 cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL)); 439 return cond; 440 } testInt32(Condition cond,const BaseIndex & address)441 Condition testInt32(Condition cond, const BaseIndex& address) { 442 MOZ_ASSERT(cond == Equal || cond == NotEqual); 443 cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32)); 444 return cond; 445 } testObject(Condition cond,const BaseIndex & address)446 Condition testObject(Condition cond, const BaseIndex& address) { 447 MOZ_ASSERT(cond == Equal || cond == NotEqual); 448 cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); 449 return cond; 450 } testDouble(Condition cond,const BaseIndex & address)451 Condition testDouble(Condition cond, const BaseIndex& address) { 452 MOZ_ASSERT(cond == Equal || cond == NotEqual); 453 Condition actual = (cond == Equal) ? Below : AboveOrEqual; 454 cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); 455 return actual; 456 } testMagic(Condition cond,const BaseIndex & address)457 Condition testMagic(Condition cond, const BaseIndex& address) { 458 MOZ_ASSERT(cond == Equal || cond == NotEqual); 459 cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); 460 return cond; 461 } testGCThing(Condition cond,const BaseIndex & address)462 Condition testGCThing(Condition cond, const BaseIndex& address) { 463 MOZ_ASSERT(cond == Equal || cond == NotEqual); 464 cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 465 return cond == Equal ? AboveOrEqual : Below; 466 } 467 468 469 470 void branchTestValue(Condition cond, const ValueOperand& value, const Value& v, Label* label); branchTestValue(Condition cond,const Address & valaddr,const ValueOperand & value,Label * label)471 void branchTestValue(Condition cond, const Address& valaddr, const ValueOperand& value, 472 Label* label) 473 { 474 MOZ_ASSERT(cond == Equal || cond == NotEqual); 475 // Check payload before tag, since payload is more likely to differ. 476 if (cond == NotEqual) { 477 branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), label); 478 branchPtr(NotEqual, tagOf(valaddr), value.typeReg(), label); 479 480 } else { 481 Label fallthrough; 482 branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), &fallthrough); 483 branchPtr(Equal, tagOf(valaddr), value.typeReg(), label); 484 bind(&fallthrough); 485 } 486 } 487 testNullSet(Condition cond,const ValueOperand & value,Register dest)488 void testNullSet(Condition cond, const ValueOperand& value, Register dest) { 489 cond = testNull(cond, value); 490 emitSet(cond, dest); 491 } 492 testObjectSet(Condition cond,const ValueOperand & value,Register dest)493 void testObjectSet(Condition cond, const ValueOperand& value, Register dest) { 494 cond = testObject(cond, value); 495 emitSet(cond, dest); 496 } 497 testUndefinedSet(Condition cond,const ValueOperand & value,Register dest)498 void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) { 499 cond = testUndefined(cond, value); 500 emitSet(cond, dest); 501 } 502 cmpPtr(Register lhs,const ImmWord rhs)503 void cmpPtr(Register lhs, const ImmWord rhs) { 504 cmpl(Imm32(rhs.value), lhs); 505 } cmpPtr(Register lhs,const ImmPtr imm)506 void cmpPtr(Register lhs, const ImmPtr imm) { 507 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 508 } cmpPtr(Register lhs,const ImmGCPtr rhs)509 void cmpPtr(Register lhs, const ImmGCPtr rhs) { 510 cmpl(rhs, lhs); 511 } cmpPtr(const Operand & lhs,Imm32 rhs)512 void cmpPtr(const Operand& lhs, Imm32 rhs) { 513 cmp32(lhs, rhs); 514 } cmpPtr(const Operand & lhs,const ImmWord rhs)515 void cmpPtr(const Operand& lhs, const ImmWord rhs) { 516 cmp32(lhs, Imm32(rhs.value)); 517 } cmpPtr(const Operand & lhs,const ImmPtr imm)518 void cmpPtr(const Operand& lhs, const ImmPtr imm) { 519 cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); 520 } cmpPtr(const Operand & lhs,const ImmGCPtr rhs)521 void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) { 522 cmpl(rhs, lhs); 523 } cmpPtr(const Address & lhs,Register rhs)524 void cmpPtr(const Address& lhs, Register rhs) { 525 cmpPtr(Operand(lhs), rhs); 526 } cmpPtr(const Operand & lhs,Register rhs)527 void cmpPtr(const Operand& lhs, Register rhs) { 528 cmp32(lhs, rhs); 529 } cmpPtr(const Address & lhs,const ImmWord rhs)530 void cmpPtr(const Address& lhs, const ImmWord rhs) { 531 cmpPtr(Operand(lhs), rhs); 532 } cmpPtr(const Address & lhs,const ImmPtr rhs)533 void cmpPtr(const Address& lhs, const ImmPtr rhs) { 534 cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 535 } cmpPtr(const Address & lhs,const ImmGCPtr rhs)536 void cmpPtr(const Address& lhs, const ImmGCPtr rhs) { 537 cmpPtr(Operand(lhs), rhs); 538 } cmpPtr(Register lhs,Register rhs)539 void cmpPtr(Register lhs, Register rhs) { 540 cmp32(lhs, rhs); 541 } testPtr(Register lhs,Register rhs)542 void testPtr(Register lhs, Register rhs) { 543 test32(lhs, rhs); 544 } testPtr(Register lhs,Imm32 rhs)545 void testPtr(Register lhs, Imm32 rhs) { 546 test32(lhs, rhs); 547 } testPtr(Register lhs,ImmWord rhs)548 void testPtr(Register lhs, ImmWord rhs) { 549 test32(lhs, Imm32(rhs.value)); 550 } testPtr(const Operand & lhs,Imm32 rhs)551 void testPtr(const Operand& lhs, Imm32 rhs) { 552 test32(lhs, rhs); 553 } testPtr(const Operand & lhs,ImmWord rhs)554 void testPtr(const Operand& lhs, ImmWord rhs) { 555 test32(lhs, Imm32(rhs.value)); 556 } 557 558 template <typename T1, typename T2> cmpPtrSet(Assembler::Condition cond,T1 lhs,T2 rhs,Register dest)559 void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest) 560 { 561 cmpPtr(lhs, rhs); 562 emitSet(cond, dest); 563 } 564 565 ///////////////////////////////////////////////////////////////// 566 // Common interface. 567 ///////////////////////////////////////////////////////////////// 568 addPtr(Register src,Register dest)569 void addPtr(Register src, Register dest) { 570 add32(src, dest); 571 } addPtr(Imm32 imm,Register dest)572 void addPtr(Imm32 imm, Register dest) { 573 add32(imm, dest); 574 } addPtr(ImmWord imm,Register dest)575 void addPtr(ImmWord imm, Register dest) { 576 add32(Imm32(imm.value), dest); 577 } addPtr(ImmPtr imm,Register dest)578 void addPtr(ImmPtr imm, Register dest) { 579 addPtr(ImmWord(uintptr_t(imm.value)), dest); 580 } addPtr(Imm32 imm,const Address & dest)581 void addPtr(Imm32 imm, const Address& dest) { 582 add32(imm, Operand(dest)); 583 } addPtr(Imm32 imm,const Operand & dest)584 void addPtr(Imm32 imm, const Operand& dest) { 585 add32(imm, dest); 586 } addPtr(const Address & src,Register dest)587 void addPtr(const Address& src, Register dest) { 588 addl(Operand(src), dest); 589 } add64(Imm32 imm,Register64 dest)590 void add64(Imm32 imm, Register64 dest) { 591 addl(imm, dest.low); 592 adcl(Imm32(0), dest.high); 593 } subPtr(Imm32 imm,Register dest)594 void subPtr(Imm32 imm, Register dest) { 595 subl(imm, dest); 596 } subPtr(Register src,Register dest)597 void subPtr(Register src, Register dest) { 598 subl(src, dest); 599 } subPtr(const Address & addr,Register dest)600 void subPtr(const Address& addr, Register dest) { 601 subl(Operand(addr), dest); 602 } subPtr(Register src,const Address & dest)603 void subPtr(Register src, const Address& dest) { 604 subl(src, Operand(dest)); 605 } mulBy3(const Register & src,const Register & dest)606 void mulBy3(const Register& src, const Register& dest) { 607 lea(Operand(src, src, TimesTwo), dest); 608 } 609 // Note: this function clobbers eax and edx. mul64(Imm64 imm,const Register64 & dest)610 void mul64(Imm64 imm, const Register64& dest) { 611 // LOW32 = LOW(LOW(dest) * LOW(imm)); 612 // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] 613 // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] 614 // + HIGH(LOW(dest) * LOW(imm)) [carry] 615 616 MOZ_ASSERT(dest.low != eax && dest.low != edx); 617 MOZ_ASSERT(dest.high != eax && dest.high != edx); 618 619 // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); 620 movl(Imm32(imm.value & 0xFFFFFFFFL), edx); 621 imull(edx, dest.high); 622 623 // edx:eax = LOW(dest) * LOW(imm); 624 movl(Imm32(imm.value & 0xFFFFFFFFL), edx); 625 movl(dest.low, eax); 626 mull(edx); 627 628 // HIGH(dest) += edx; 629 addl(edx, dest.high); 630 631 // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); 632 if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) 633 leal(Operand(dest.low, dest.low, TimesFour), edx); 634 else 635 MOZ_CRASH("Unsupported imm"); 636 addl(edx, dest.high); 637 638 // LOW(dest) = eax; 639 movl(eax, dest.low); 640 } 641 branch32(Condition cond,AbsoluteAddress lhs,Imm32 rhs,Label * label)642 void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) { 643 cmp32(Operand(lhs), rhs); 644 j(cond, label); 645 } branch32(Condition cond,wasm::SymbolicAddress lhs,Imm32 rhs,Label * label)646 void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label) { 647 cmpl(rhs, lhs); 648 j(cond, label); 649 } branch32(Condition cond,AbsoluteAddress lhs,Register rhs,Label * label)650 void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label* label) { 651 cmp32(Operand(lhs), rhs); 652 j(cond, label); 653 } branchTest32(Condition cond,AbsoluteAddress address,Imm32 imm,Label * label)654 void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) { 655 test32(Operand(address), imm); 656 j(cond, label); 657 } 658 branchPtr(Condition cond,wasm::SymbolicAddress lhs,Register ptr,Label * label)659 void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register ptr, Label* label) { 660 cmpl(ptr, lhs); 661 j(cond, label); 662 } 663 664 template <typename T, typename S> branchPtr(Condition cond,T lhs,S ptr,Label * label)665 void branchPtr(Condition cond, T lhs, S ptr, Label* label) { 666 cmpPtr(Operand(lhs), ptr); 667 j(cond, label); 668 } 669 branchPrivatePtr(Condition cond,const Address & lhs,ImmPtr ptr,Label * label)670 void branchPrivatePtr(Condition cond, const Address& lhs, ImmPtr ptr, Label* label) { 671 branchPtr(cond, lhs, ptr, label); 672 } 673 branchPrivatePtr(Condition cond,const Address & lhs,Register ptr,Label * label)674 void branchPrivatePtr(Condition cond, const Address& lhs, Register ptr, Label* label) { 675 branchPtr(cond, lhs, ptr, label); 676 } 677 678 template <typename T, typename S> branchPtr(Condition cond,T lhs,S ptr,RepatchLabel * label)679 void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel* label) { 680 cmpPtr(Operand(lhs), ptr); 681 j(cond, label); 682 } 683 684 CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) { 685 jump(label); 686 return CodeOffsetJump(size()); 687 } 688 689 CodeOffsetJump jumpWithPatch(RepatchLabel* label, Assembler::Condition cond, 690 Label* documentation = nullptr) 691 { 692 j(cond, label); 693 return CodeOffsetJump(size()); 694 } 695 696 CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) { 697 return jumpWithPatch(label); 698 } 699 700 template <typename S, typename T> branchPtrWithPatch(Condition cond,S lhs,T ptr,RepatchLabel * label)701 CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) { 702 branchPtr(cond, lhs, ptr, label); 703 return CodeOffsetJump(size()); 704 } branchPtr(Condition cond,Register lhs,Register rhs,RepatchLabel * label)705 void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) { 706 cmpPtr(lhs, rhs); 707 j(cond, label); 708 } branchPtr(Condition cond,Register lhs,Register rhs,Label * label)709 void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) { 710 cmpPtr(lhs, rhs); 711 j(cond, label); 712 } branchTestPtr(Condition cond,Register lhs,Register rhs,Label * label)713 void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) { 714 testPtr(lhs, rhs); 715 j(cond, label); 716 } branchTestPtr(Condition cond,Register lhs,Imm32 imm,Label * label)717 void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { 718 testPtr(lhs, imm); 719 j(cond, label); 720 } branchTestPtr(Condition cond,const Address & lhs,Imm32 imm,Label * label)721 void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) { 722 testPtr(Operand(lhs), imm); 723 j(cond, label); 724 } decBranchPtr(Condition cond,Register lhs,Imm32 imm,Label * label)725 void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) { 726 subPtr(imm, lhs); 727 j(cond, label); 728 } 729 branchTest64(Condition cond,Register64 lhs,Register64 rhs,Register temp,Label * label)730 void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) { 731 if (cond == Assembler::Zero) { 732 MOZ_ASSERT(lhs.low == rhs.low); 733 MOZ_ASSERT(lhs.high == rhs.high); 734 movl(lhs.low, temp); 735 orl(lhs.high, temp); 736 branchTestPtr(cond, temp, temp, label); 737 } else { 738 MOZ_CRASH("Unsupported condition"); 739 } 740 } 741 movePtr(ImmWord imm,Register dest)742 void movePtr(ImmWord imm, Register dest) { 743 movl(Imm32(imm.value), dest); 744 } movePtr(ImmPtr imm,Register dest)745 void movePtr(ImmPtr imm, Register dest) { 746 movl(imm, dest); 747 } movePtr(wasm::SymbolicAddress imm,Register dest)748 void movePtr(wasm::SymbolicAddress imm, Register dest) { 749 mov(imm, dest); 750 } movePtr(ImmGCPtr imm,Register dest)751 void movePtr(ImmGCPtr imm, Register dest) { 752 movl(imm, dest); 753 } move64(Register64 src,Register64 dest)754 void move64(Register64 src, Register64 dest) { 755 movl(src.low, dest.low); 756 movl(src.high, dest.high); 757 } loadPtr(const Address & address,Register dest)758 void loadPtr(const Address& address, Register dest) { 759 movl(Operand(address), dest); 760 } loadPtr(const Operand & src,Register dest)761 void loadPtr(const Operand& src, Register dest) { 762 movl(src, dest); 763 } loadPtr(const BaseIndex & src,Register dest)764 void loadPtr(const BaseIndex& src, Register dest) { 765 movl(Operand(src), dest); 766 } loadPtr(AbsoluteAddress address,Register dest)767 void loadPtr(AbsoluteAddress address, Register dest) { 768 movl(Operand(address), dest); 769 } loadPrivate(const Address & src,Register dest)770 void loadPrivate(const Address& src, Register dest) { 771 movl(payloadOf(src), dest); 772 } load32(AbsoluteAddress address,Register dest)773 void load32(AbsoluteAddress address, Register dest) { 774 movl(Operand(address), dest); 775 } load64(const Address & address,Register64 dest)776 void load64(const Address& address, Register64 dest) { 777 movl(Operand(address), dest.low); 778 movl(Operand(Address(address.base, address.offset + 4)), dest.high); 779 } 780 branch64(Condition cond,const Address & lhs,Imm64 val,Label * label)781 void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) { 782 MOZ_ASSERT(cond == Assembler::NotEqual, 783 "other condition codes not supported"); 784 785 branch32(cond, lhs, val.firstHalf(), label); 786 branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), val.secondHalf(), label); 787 } 788 branch64(Condition cond,const Address & lhs,const Address & rhs,Register scratch,Label * label)789 void branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch, 790 Label* label) 791 { 792 MOZ_ASSERT(cond == Assembler::NotEqual, 793 "other condition codes not supported"); 794 MOZ_ASSERT(lhs.base != scratch); 795 MOZ_ASSERT(rhs.base != scratch); 796 797 load32(rhs, scratch); 798 branch32(cond, lhs, scratch, label); 799 800 load32(Address(rhs.base, rhs.offset + sizeof(uint32_t)), scratch); 801 branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), scratch, label); 802 } 803 804 template <typename T> storePtr(ImmWord imm,T address)805 void storePtr(ImmWord imm, T address) { 806 movl(Imm32(imm.value), Operand(address)); 807 } 808 template <typename T> storePtr(ImmPtr imm,T address)809 void storePtr(ImmPtr imm, T address) { 810 storePtr(ImmWord(uintptr_t(imm.value)), address); 811 } 812 template <typename T> storePtr(ImmGCPtr imm,T address)813 void storePtr(ImmGCPtr imm, T address) { 814 movl(imm, Operand(address)); 815 } storePtr(Register src,const Address & address)816 void storePtr(Register src, const Address& address) { 817 movl(src, Operand(address)); 818 } storePtr(Register src,const BaseIndex & address)819 void storePtr(Register src, const BaseIndex& address) { 820 movl(src, Operand(address)); 821 } storePtr(Register src,const Operand & dest)822 void storePtr(Register src, const Operand& dest) { 823 movl(src, dest); 824 } storePtr(Register src,AbsoluteAddress address)825 void storePtr(Register src, AbsoluteAddress address) { 826 movl(src, Operand(address)); 827 } store32(Register src,AbsoluteAddress address)828 void store32(Register src, AbsoluteAddress address) { 829 movl(src, Operand(address)); 830 } store64(Register64 src,Address address)831 void store64(Register64 src, Address address) { 832 movl(src.low, Operand(address)); 833 movl(src.high, Operand(Address(address.base, address.offset + 4))); 834 } 835 setStackArg(Register reg,uint32_t arg)836 void setStackArg(Register reg, uint32_t arg) { 837 movl(reg, Operand(esp, arg * sizeof(intptr_t))); 838 } 839 840 // Type testing instructions can take a tag in a register or a 841 // ValueOperand. 842 template <typename T> branchTestUndefined(Condition cond,const T & t,Label * label)843 void branchTestUndefined(Condition cond, const T& t, Label* label) { 844 cond = testUndefined(cond, t); 845 j(cond, label); 846 } 847 template <typename T> branchTestInt32(Condition cond,const T & t,Label * label)848 void branchTestInt32(Condition cond, const T& t, Label* label) { 849 cond = testInt32(cond, t); 850 j(cond, label); 851 } 852 template <typename T> branchTestBoolean(Condition cond,const T & t,Label * label)853 void branchTestBoolean(Condition cond, const T& t, Label* label) { 854 cond = testBoolean(cond, t); 855 j(cond, label); 856 } 857 template <typename T> branchTestDouble(Condition cond,const T & t,Label * label)858 void branchTestDouble(Condition cond, const T& t, Label* label) { 859 cond = testDouble(cond, t); 860 j(cond, label); 861 } 862 template <typename T> branchTestNull(Condition cond,const T & t,Label * label)863 void branchTestNull(Condition cond, const T& t, Label* label) { 864 cond = testNull(cond, t); 865 j(cond, label); 866 } 867 template <typename T> branchTestString(Condition cond,const T & t,Label * label)868 void branchTestString(Condition cond, const T& t, Label* label) { 869 cond = testString(cond, t); 870 j(cond, label); 871 } 872 template <typename T> branchTestSymbol(Condition cond,const T & t,Label * label)873 void branchTestSymbol(Condition cond, const T& t, Label* label) { 874 cond = testSymbol(cond, t); 875 j(cond, label); 876 } 877 template <typename T> branchTestObject(Condition cond,const T & t,Label * label)878 void branchTestObject(Condition cond, const T& t, Label* label) { 879 cond = testObject(cond, t); 880 j(cond, label); 881 } 882 template <typename T> branchTestNumber(Condition cond,const T & t,Label * label)883 void branchTestNumber(Condition cond, const T& t, Label* label) { 884 cond = testNumber(cond, t); 885 j(cond, label); 886 } 887 template <typename T> branchTestGCThing(Condition cond,const T & t,Label * label)888 void branchTestGCThing(Condition cond, const T& t, Label* label) { 889 cond = testGCThing(cond, t); 890 j(cond, label); 891 } 892 template <typename T> branchTestPrimitive(Condition cond,const T & t,Label * label)893 void branchTestPrimitive(Condition cond, const T& t, Label* label) { 894 cond = testPrimitive(cond, t); 895 j(cond, label); 896 } 897 template <typename T> branchTestMagic(Condition cond,const T & t,Label * label)898 void branchTestMagic(Condition cond, const T& t, Label* label) { 899 cond = testMagic(cond, t); 900 j(cond, label); 901 } branchTestMagicValue(Condition cond,const ValueOperand & val,JSWhyMagic why,Label * label)902 void branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why, 903 Label* label) 904 { 905 MOZ_ASSERT(cond == Equal || cond == NotEqual); 906 branchTestValue(cond, val, MagicValue(why), label); 907 } 908 909 // Note: this function clobbers the source register. boxDouble(FloatRegister src,const ValueOperand & dest)910 void boxDouble(FloatRegister src, const ValueOperand& dest) { 911 if (Assembler::HasSSE41()) { 912 vmovd(src, dest.payloadReg()); 913 vpextrd(1, src, dest.typeReg()); 914 } else { 915 vmovd(src, dest.payloadReg()); 916 vpsrldq(Imm32(4), src, src); 917 vmovd(src, dest.typeReg()); 918 } 919 } boxNonDouble(JSValueType type,Register src,const ValueOperand & dest)920 void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) { 921 if (src != dest.payloadReg()) 922 movl(src, dest.payloadReg()); 923 movl(ImmType(type), dest.typeReg()); 924 } 925 unboxNonDouble(const ValueOperand & src,Register dest)926 void unboxNonDouble(const ValueOperand& src, Register dest) { 927 if (src.payloadReg() != dest) 928 movl(src.payloadReg(), dest); 929 } unboxNonDouble(const Address & src,Register dest)930 void unboxNonDouble(const Address& src, Register dest) { 931 movl(payloadOf(src), dest); 932 } unboxNonDouble(const BaseIndex & src,Register dest)933 void unboxNonDouble(const BaseIndex& src, Register dest) { 934 movl(payloadOf(src), dest); 935 } unboxInt32(const ValueOperand & src,Register dest)936 void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxInt32(const Address & src,Register dest)937 void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxBoolean(const ValueOperand & src,Register dest)938 void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxBoolean(const Address & src,Register dest)939 void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxString(const ValueOperand & src,Register dest)940 void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxString(const Address & src,Register dest)941 void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxSymbol(const ValueOperand & src,Register dest)942 void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxSymbol(const Address & src,Register dest)943 void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const ValueOperand & src,Register dest)944 void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const Address & src,Register dest)945 void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); } unboxObject(const BaseIndex & src,Register dest)946 void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); } unboxDouble(const Address & src,FloatRegister dest)947 void unboxDouble(const Address& src, FloatRegister dest) { 948 loadDouble(Operand(src), dest); 949 } unboxDouble(const ValueOperand & src,FloatRegister dest)950 void unboxDouble(const ValueOperand& src, FloatRegister dest) { 951 MOZ_ASSERT(dest != ScratchDoubleReg); 952 if (Assembler::HasSSE41()) { 953 vmovd(src.payloadReg(), dest); 954 vpinsrd(1, src.typeReg(), dest, dest); 955 } else { 956 vmovd(src.payloadReg(), dest); 957 vmovd(src.typeReg(), ScratchDoubleReg); 958 vunpcklps(ScratchDoubleReg, dest, dest); 959 } 960 } unboxDouble(const Operand & payload,const Operand & type,Register scratch,FloatRegister dest)961 void unboxDouble(const Operand& payload, const Operand& type, 962 Register scratch, FloatRegister dest) { 963 MOZ_ASSERT(dest != ScratchDoubleReg); 964 if (Assembler::HasSSE41()) { 965 movl(payload, scratch); 966 vmovd(scratch, dest); 967 movl(type, scratch); 968 vpinsrd(1, scratch, dest, dest); 969 } else { 970 movl(payload, scratch); 971 vmovd(scratch, dest); 972 movl(type, scratch); 973 vmovd(scratch, ScratchDoubleReg); 974 vunpcklps(ScratchDoubleReg, dest, dest); 975 } 976 } unboxValue(const ValueOperand & src,AnyRegister dest)977 void unboxValue(const ValueOperand& src, AnyRegister dest) { 978 if (dest.isFloat()) { 979 Label notInt32, end; 980 branchTestInt32(Assembler::NotEqual, src, ¬Int32); 981 convertInt32ToDouble(src.payloadReg(), dest.fpu()); 982 jump(&end); 983 bind(¬Int32); 984 unboxDouble(src, dest.fpu()); 985 bind(&end); 986 } else { 987 if (src.payloadReg() != dest.gpr()) 988 movl(src.payloadReg(), dest.gpr()); 989 } 990 } unboxPrivate(const ValueOperand & src,Register dest)991 void unboxPrivate(const ValueOperand& src, Register dest) { 992 if (src.payloadReg() != dest) 993 movl(src.payloadReg(), dest); 994 } 995 notBoolean(const ValueOperand & val)996 void notBoolean(const ValueOperand& val) { 997 xorl(Imm32(1), val.payloadReg()); 998 } 999 1000 // Extended unboxing API. If the payload is already in a register, returns 1001 // that register. Otherwise, provides a move to the given scratch register, 1002 // and returns that. extractObject(const Address & address,Register scratch)1003 Register extractObject(const Address& address, Register scratch) { 1004 movl(payloadOf(address), scratch); 1005 return scratch; 1006 } extractObject(const ValueOperand & value,Register scratch)1007 Register extractObject(const ValueOperand& value, Register scratch) { 1008 return value.payloadReg(); 1009 } extractInt32(const ValueOperand & value,Register scratch)1010 Register extractInt32(const ValueOperand& value, Register scratch) { 1011 return value.payloadReg(); 1012 } extractBoolean(const ValueOperand & value,Register scratch)1013 Register extractBoolean(const ValueOperand& value, Register scratch) { 1014 return value.payloadReg(); 1015 } extractTag(const Address & address,Register scratch)1016 Register extractTag(const Address& address, Register scratch) { 1017 movl(tagOf(address), scratch); 1018 return scratch; 1019 } extractTag(const ValueOperand & value,Register scratch)1020 Register extractTag(const ValueOperand& value, Register scratch) { 1021 return value.typeReg(); 1022 } 1023 boolValueToDouble(const ValueOperand & operand,FloatRegister dest)1024 void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) { 1025 convertInt32ToDouble(operand.payloadReg(), dest); 1026 } boolValueToFloat32(const ValueOperand & operand,FloatRegister dest)1027 void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 1028 convertInt32ToFloat32(operand.payloadReg(), dest); 1029 } int32ValueToDouble(const ValueOperand & operand,FloatRegister dest)1030 void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) { 1031 convertInt32ToDouble(operand.payloadReg(), dest); 1032 } int32ValueToFloat32(const ValueOperand & operand,FloatRegister dest)1033 void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) { 1034 convertInt32ToFloat32(operand.payloadReg(), dest); 1035 } 1036 1037 void loadConstantDouble(double d, FloatRegister dest); 1038 void addConstantDouble(double d, FloatRegister dest); 1039 void loadConstantFloat32(float f, FloatRegister dest); 1040 void addConstantFloat32(float f, FloatRegister dest); 1041 void loadConstantInt32x4(const SimdConstant& v, FloatRegister dest); 1042 void loadConstantFloat32x4(const SimdConstant& v, FloatRegister dest); 1043 branchTruncateDouble(FloatRegister src,Register dest,Label * fail)1044 void branchTruncateDouble(FloatRegister src, Register dest, Label* fail) { 1045 vcvttsd2si(src, dest); 1046 1047 // vcvttsd2si returns 0x80000000 on failure. Test for it by 1048 // subtracting 1 and testing overflow (this permits the use of a 1049 // smaller immediate field). 1050 cmp32(dest, Imm32(1)); 1051 j(Assembler::Overflow, fail); 1052 } branchTruncateFloat32(FloatRegister src,Register dest,Label * fail)1053 void branchTruncateFloat32(FloatRegister src, Register dest, Label* fail) { 1054 vcvttss2si(src, dest); 1055 1056 // vcvttss2si returns 0x80000000 on failure. Test for it by 1057 // subtracting 1 and testing overflow (this permits the use of a 1058 // smaller immediate field). 1059 cmp32(dest, Imm32(1)); 1060 j(Assembler::Overflow, fail); 1061 } 1062 testInt32Truthy(bool truthy,const ValueOperand & operand)1063 Condition testInt32Truthy(bool truthy, const ValueOperand& operand) { 1064 test32(operand.payloadReg(), operand.payloadReg()); 1065 return truthy ? NonZero : Zero; 1066 } branchTestInt32Truthy(bool truthy,const ValueOperand & operand,Label * label)1067 void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label) { 1068 Condition cond = testInt32Truthy(truthy, operand); 1069 j(cond, label); 1070 } branchTestBooleanTruthy(bool truthy,const ValueOperand & operand,Label * label)1071 void branchTestBooleanTruthy(bool truthy, const ValueOperand& operand, Label* label) { 1072 test32(operand.payloadReg(), operand.payloadReg()); 1073 j(truthy ? NonZero : Zero, label); 1074 } testStringTruthy(bool truthy,const ValueOperand & value)1075 Condition testStringTruthy(bool truthy, const ValueOperand& value) { 1076 Register string = value.payloadReg(); 1077 cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0)); 1078 return truthy ? Assembler::NotEqual : Assembler::Equal; 1079 } branchTestStringTruthy(bool truthy,const ValueOperand & value,Label * label)1080 void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label) { 1081 Condition cond = testStringTruthy(truthy, value); 1082 j(cond, label); 1083 } 1084 loadInt32OrDouble(const Operand & operand,FloatRegister dest)1085 void loadInt32OrDouble(const Operand& operand, FloatRegister dest) { 1086 Label notInt32, end; 1087 branchTestInt32(Assembler::NotEqual, operand, ¬Int32); 1088 convertInt32ToDouble(ToPayload(operand), dest); 1089 jump(&end); 1090 bind(¬Int32); 1091 loadDouble(operand, dest); 1092 bind(&end); 1093 } 1094 1095 template <typename T> loadUnboxedValue(const T & src,MIRType type,AnyRegister dest)1096 void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) { 1097 if (dest.isFloat()) 1098 loadInt32OrDouble(Operand(src), dest.fpu()); 1099 else 1100 movl(Operand(src), dest.gpr()); 1101 } 1102 1103 template <typename T> 1104 void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, 1105 MIRType slotType); 1106 1107 template <typename T> storeUnboxedPayload(ValueOperand value,T address,size_t nbytes)1108 void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) { 1109 switch (nbytes) { 1110 case 4: 1111 storePtr(value.payloadReg(), address); 1112 return; 1113 case 1: 1114 store8(value.payloadReg(), address); 1115 return; 1116 default: MOZ_CRASH("Bad payload width"); 1117 } 1118 } 1119 loadInstructionPointerAfterCall(Register dest)1120 void loadInstructionPointerAfterCall(Register dest) { 1121 movl(Operand(StackPointer, 0x0), dest); 1122 } 1123 1124 // Note: this function clobbers the source register. convertUInt32ToDouble(Register src,FloatRegister dest)1125 void convertUInt32ToDouble(Register src, FloatRegister dest) { 1126 // src is [0, 2^32-1] 1127 subl(Imm32(0x80000000), src); 1128 1129 // Now src is [-2^31, 2^31-1] - int range, but not the same value. 1130 convertInt32ToDouble(src, dest); 1131 1132 // dest is now a double with the int range. 1133 // correct the double value by adding 0x80000000. 1134 addConstantDouble(2147483648.0, dest); 1135 } 1136 1137 // Note: this function clobbers the source register. convertUInt32ToFloat32(Register src,FloatRegister dest)1138 void convertUInt32ToFloat32(Register src, FloatRegister dest) { 1139 convertUInt32ToDouble(src, dest); 1140 convertDoubleToFloat32(dest, dest); 1141 } 1142 1143 void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); 1144 mulDoublePtr(ImmPtr imm,Register temp,FloatRegister dest)1145 void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { 1146 movl(imm, temp); 1147 vmulsd(Operand(temp, 0), dest, dest); 1148 } 1149 inc64(AbsoluteAddress dest)1150 void inc64(AbsoluteAddress dest) { 1151 addl(Imm32(1), Operand(dest)); 1152 Label noOverflow; 1153 j(NonZero, &noOverflow); 1154 addl(Imm32(1), Operand(dest.offset(4))); 1155 bind(&noOverflow); 1156 } 1157 incrementInt32Value(const Address & addr)1158 void incrementInt32Value(const Address& addr) { 1159 addl(Imm32(1), payloadOf(addr)); 1160 } 1161 1162 // If source is a double, load it into dest. If source is int32, 1163 // convert it to double. Else, branch to failure. ensureDouble(const ValueOperand & source,FloatRegister dest,Label * failure)1164 void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure) { 1165 Label isDouble, done; 1166 branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); 1167 branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); 1168 1169 convertInt32ToDouble(source.payloadReg(), dest); 1170 jump(&done); 1171 1172 bind(&isDouble); 1173 unboxDouble(source, dest); 1174 1175 bind(&done); 1176 } 1177 1178 public: 1179 // Used from within an Exit frame to handle a pending exception. 1180 void handleFailureWithHandlerTail(void* handler); 1181 1182 void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label); 1183 void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label); 1184 1185 // Instrumentation for entering and leaving the profiler. 1186 void profilerEnterFrame(Register framePtr, Register scratch); 1187 void profilerExitFrame(); 1188 }; 1189 1190 typedef MacroAssemblerX86 MacroAssemblerSpecific; 1191 1192 } // namespace jit 1193 } // namespace js 1194 1195 #endif /* jit_x86_MacroAssembler_x86_h */ 1196