Bug 1432479 - Use XOR for Value unboxing on 64-bit to mitigate certain Spectre attacks. r=luke

--HG--
extra : rebase_source : e0825f48994b4556db2f71d04d3c0971de5275ac
This commit is contained in:
Jan de Mooij 2018-01-24 12:33:53 +01:00
Родитель 6adca5400a
Коммит 93e1e4e3d9
20 изменённых файлов: 345 добавлений и 160 удалений

Просмотреть файл

@ -49,9 +49,9 @@ JS_ENUM_HEADER(JSValueType, uint8_t)
{
JSVAL_TYPE_DOUBLE = 0x00,
JSVAL_TYPE_INT32 = 0x01,
JSVAL_TYPE_UNDEFINED = 0x02,
JSVAL_TYPE_NULL = 0x03,
JSVAL_TYPE_BOOLEAN = 0x04,
JSVAL_TYPE_BOOLEAN = 0x02,
JSVAL_TYPE_UNDEFINED = 0x03,
JSVAL_TYPE_NULL = 0x04,
JSVAL_TYPE_MAGIC = 0x05,
JSVAL_TYPE_STRING = 0x06,
JSVAL_TYPE_SYMBOL = 0x07,
@ -143,7 +143,9 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
#elif defined(JS_PUNBOX64)
#define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL
// This should only be used in toGCThing, see the 'Spectre mitigations' comment.
#define JSVAL_PAYLOAD_MASK_GCTHING 0x00007FFFFFFFFFFFLL
#define JSVAL_TAG_MASK 0xFFFF800000000000LL
#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type)))
#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT)
@ -153,9 +155,15 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING
#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT
#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED
#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_BOOLEAN
#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING
// JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to
// implement toObjectOrNull more efficiently.
#define JSVAL_OBJECT_OR_NULL_BIT (uint64_t(0x8) << JSVAL_TAG_SHIFT)
static_assert((JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == JSVAL_OBJECT_OR_NULL_BIT,
"JSVAL_OBJECT_OR_NULL_BIT must be consistent with object and null tags");
#endif /* JS_PUNBOX64 */
typedef enum JSWhyMagic
@ -287,11 +295,19 @@ CanonicalizeNaN(double d)
* Value::setObject takes a JSObject&. (Conversely, Value::toObject returns a
* JSObject&.) A convenience member Value::setObjectOrNull is provided.
*
* - JSVAL_VOID is the same as the singleton value of the Undefined type.
*
* - Note that JS::Value is 8 bytes on 32 and 64-bit architectures. Thus, on
* 32-bit user code should avoid copying jsval/JS::Value as much as possible,
* preferring to pass by const Value&.
*
* Spectre mitigations
* ===================
* To mitigate Spectre attacks, we do the following:
*
* - On 64-bit platforms, when unboxing a Value, we XOR the bits with the
* expected type tag (instead of masking the payload bits). This guarantees
* that toString, toObject, toSymbol will return an invalid pointer (because
* some high bits will be set) when called on a Value with a different type
* tag.
*/
class MOZ_NON_PARAM alignas(8) Value
{
@ -628,7 +644,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return data.s.payload.str;
#elif defined(JS_PUNBOX64)
return reinterpret_cast<JSString*>(data.asBits & JSVAL_PAYLOAD_MASK);
return reinterpret_cast<JSString*>(data.asBits ^ JSVAL_SHIFTED_TAG_STRING);
#endif
}
@ -637,7 +653,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return data.s.payload.sym;
#elif defined(JS_PUNBOX64)
return reinterpret_cast<JS::Symbol*>(data.asBits & JSVAL_PAYLOAD_MASK);
return reinterpret_cast<JS::Symbol*>(data.asBits ^ JSVAL_SHIFTED_TAG_SYMBOL);
#endif
}
@ -646,7 +662,10 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return *data.s.payload.obj;
#elif defined(JS_PUNBOX64)
return *toObjectOrNull();
uint64_t ptrBits = data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT;
MOZ_ASSERT(ptrBits);
MOZ_ASSERT((ptrBits & 0x7) == 0);
return *reinterpret_cast<JSObject*>(ptrBits);
#endif
}
@ -655,7 +674,9 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return data.s.payload.obj;
#elif defined(JS_PUNBOX64)
uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
// Note: the 'Spectre mitigations' comment at the top of this class
// explains why we use XOR here and in other to* methods.
uint64_t ptrBits = (data.asBits ^ JSVAL_SHIFTED_TAG_OBJECT) & ~JSVAL_OBJECT_OR_NULL_BIT;
MOZ_ASSERT((ptrBits & 0x7) == 0);
return reinterpret_cast<JSObject*>(ptrBits);
#endif
@ -666,7 +687,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return data.s.payload.cell;
#elif defined(JS_PUNBOX64)
uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK;
uint64_t ptrBits = data.asBits & JSVAL_PAYLOAD_MASK_GCTHING;
MOZ_ASSERT((ptrBits & 0x7) == 0);
return reinterpret_cast<js::gc::Cell*>(ptrBits);
#endif
@ -681,7 +702,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return bool(data.s.payload.boo);
#elif defined(JS_PUNBOX64)
return bool(data.asBits & JSVAL_PAYLOAD_MASK);
return bool(int32_t(data.asBits));
#endif
}

Просмотреть файл

@ -4800,8 +4800,9 @@ BaselineCompiler::emit_JSOP_RESUME()
// Store the arguments object if there is one.
Label noArgsObj;
masm.unboxObject(Address(genObj, GeneratorObject::offsetOfArgsObjSlot()), scratch2);
masm.branchTestPtr(Assembler::Zero, scratch2, scratch2, &noArgsObj);
Address argsObjSlot(genObj, GeneratorObject::offsetOfArgsObjSlot());
masm.branchTestUndefined(Assembler::Equal, argsObjSlot, &noArgsObj);
masm.unboxObject(argsObjSlot, scratch2);
{
masm.storePtr(scratch2, frame.addressOfArgsObj());
masm.or32(Imm32(BaselineFrame::HAS_ARGS_OBJ), frame.addressOfFlags());

Просмотреть файл

@ -4431,7 +4431,8 @@ jit::LoadShapeWrapperContents(MacroAssembler& masm, Register obj, Register dst,
Address privateAddr(dst, detail::ProxyReservedSlots::offsetOfPrivateSlot());
masm.branchTestObject(Assembler::NotEqual, privateAddr, failure);
masm.unboxObject(privateAddr, dst);
masm.unboxNonDouble(Address(dst, NativeObject::getFixedSlotOffset(SHAPE_CONTAINER_SLOT)), dst);
masm.unboxNonDouble(Address(dst, NativeObject::getFixedSlotOffset(SHAPE_CONTAINER_SLOT)), dst,
JSVAL_TYPE_PRIVATE_GCTHING);
}
void

Просмотреть файл

@ -143,7 +143,7 @@ CacheRegisterAllocator::useRegister(MacroAssembler& masm, TypedOperandId typedId
availableRegs_.add(val);
Register reg = val.scratchReg();
availableRegs_.take(reg);
masm.unboxObject(val, reg);
masm.unboxNonDouble(val, reg, typedId.type());
loc.setPayloadReg(reg, typedId.type());
currentOpRegs_.add(reg);
return reg;
@ -160,14 +160,14 @@ CacheRegisterAllocator::useRegister(MacroAssembler& masm, TypedOperandId typedId
// unbox it and then remove it from the stack, else we just unbox.
Register reg = allocateRegister(masm);
if (loc.valueStack() == stackPushed_) {
masm.unboxObject(Address(masm.getStackPointer(), 0), reg);
masm.unboxNonDouble(Address(masm.getStackPointer(), 0), reg, typedId.type());
masm.addToStackPtr(Imm32(sizeof(js::Value)));
MOZ_ASSERT(stackPushed_ >= sizeof(js::Value));
stackPushed_ -= sizeof(js::Value);
} else {
MOZ_ASSERT(loc.valueStack() < stackPushed_);
masm.unboxObject(Address(masm.getStackPointer(), stackPushed_ - loc.valueStack()),
reg);
masm.unboxNonDouble(Address(masm.getStackPointer(), stackPushed_ - loc.valueStack()),
reg, typedId.type());
}
loc.setPayloadReg(reg, typedId.type());
return reg;
@ -176,7 +176,7 @@ CacheRegisterAllocator::useRegister(MacroAssembler& masm, TypedOperandId typedId
case OperandLocation::BaselineFrame: {
Register reg = allocateRegister(masm);
Address addr = addressOf(masm, loc.baselineFrameSlot());
masm.unboxNonDouble(addr, reg);
masm.unboxNonDouble(addr, reg, typedId.type());
loc.setPayloadReg(reg, typedId.type());
return reg;
};
@ -742,7 +742,7 @@ CacheRegisterAllocator::restoreInputState(MacroAssembler& masm, bool shouldDisca
switch (cur.kind()) {
case OperandLocation::ValueReg:
MOZ_ASSERT(dest.payloadType() != JSVAL_TYPE_DOUBLE);
masm.unboxNonDouble(cur.valueReg(), dest.payloadReg());
masm.unboxNonDouble(cur.valueReg(), dest.payloadReg(), dest.payloadType());
continue;
case OperandLocation::PayloadReg:
MOZ_ASSERT(cur.payloadType() == dest.payloadType());
@ -758,7 +758,7 @@ CacheRegisterAllocator::restoreInputState(MacroAssembler& masm, bool shouldDisca
MOZ_ASSERT(cur.valueStack() <= stackPushed_);
MOZ_ASSERT(dest.payloadType() != JSVAL_TYPE_DOUBLE);
masm.unboxNonDouble(Address(masm.getStackPointer(), stackPushed_ - cur.valueStack()),
dest.payloadReg());
dest.payloadReg(), dest.payloadType());
continue;
case OperandLocation::Constant:
case OperandLocation::BaselineFrame:

Просмотреть файл

@ -1183,12 +1183,15 @@ CodeGenerator::visitValueToObjectOrNull(LValueToObjectOrNull* lir)
OutOfLineCode* ool = oolCallVM(ToObjectInfo, lir, ArgList(input, Imm32(0)),
StoreRegisterTo(output));
Label done;
masm.branchTestObject(Assembler::Equal, input, &done);
Label isObject;
masm.branchTestObject(Assembler::Equal, input, &isObject);
masm.branchTestNull(Assembler::NotEqual, input, ool->entry());
masm.bind(&done);
masm.unboxNonDouble(input, output);
masm.movePtr(ImmWord(0), output);
masm.jump(ool->rejoin());
masm.bind(&isObject);
masm.unboxObject(input, output);
masm.bind(ool->rejoin());
}

Просмотреть файл

@ -1753,12 +1753,7 @@ SnapshotIterator::maybeRead(const RValueAllocation& a, MaybeReadFallback& fallba
void
SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, const Value& v)
{
uintptr_t payload = *v.payloadUIntPtr();
#if defined(JS_PUNBOX64)
// Do not write back the tag, as this will trigger an assertion when we will
// reconstruct the JS Value while tracing again or when bailing out.
payload &= JSVAL_PAYLOAD_MASK;
#endif
MOZ_ASSERT(v.isGCThing());
switch (alloc.mode()) {
case RValueAllocation::CONSTANT:
@ -1774,7 +1769,7 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, con
break;
case RValueAllocation::TYPED_REG:
machine_->write(alloc.reg2(), payload);
machine_->write(alloc.reg2(), uintptr_t(v.toGCThing()));
break;
case RValueAllocation::TYPED_STACK:
@ -1785,7 +1780,7 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, con
case JSVAL_TYPE_STRING:
case JSVAL_TYPE_SYMBOL:
case JSVAL_TYPE_OBJECT:
WriteFrameSlot(fp_, alloc.stackOffset2(), payload);
WriteFrameSlot(fp_, alloc.stackOffset2(), uintptr_t(v.toGCThing()));
break;
}
break;
@ -1793,12 +1788,12 @@ SnapshotIterator::writeAllocationValuePayload(const RValueAllocation& alloc, con
#if defined(JS_NUNBOX32)
case RValueAllocation::UNTYPED_REG_REG:
case RValueAllocation::UNTYPED_STACK_REG:
machine_->write(alloc.reg2(), payload);
machine_->write(alloc.reg2(), uintptr_t(v.toGCThing()));
break;
case RValueAllocation::UNTYPED_REG_STACK:
case RValueAllocation::UNTYPED_STACK_STACK:
WriteFrameSlot(fp_, alloc.stackOffset2(), payload);
WriteFrameSlot(fp_, alloc.stackOffset2(), uintptr_t(v.toGCThing()));
break;
#elif defined(JS_PUNBOX64)
case RValueAllocation::UNTYPED_REG:

Просмотреть файл

@ -811,9 +811,9 @@ MacroAssembler::storeCallInt32Result(Register reg)
}
void
MacroAssembler::storeCallResultValue(AnyRegister dest)
MacroAssembler::storeCallResultValue(AnyRegister dest, JSValueType type)
{
unboxValue(JSReturnOperand, dest);
unboxValue(JSReturnOperand, dest, type);
}
void
@ -822,7 +822,7 @@ MacroAssembler::storeCallResultValue(TypedOrValueRegister dest)
if (dest.hasValue())
storeCallResultValue(dest.valueReg());
else
storeCallResultValue(dest.typedReg());
storeCallResultValue(dest.typedReg(), ValueTypeFromMIRType(dest.type()));
}
} // namespace jit

Просмотреть файл

@ -596,7 +596,7 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
} else {
if (failure)
branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1, type);
}
break;
@ -614,7 +614,7 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
} else {
if (failure)
branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4, type);
}
break;
@ -669,7 +669,8 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure);
bind(&ok);
}
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t),
type);
}
break;
@ -687,7 +688,8 @@ MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
} else {
if (failure)
branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t),
type);
}
break;
@ -3143,7 +3145,7 @@ MacroAssembler::emitPreBarrierFastPath(JSRuntime* rt, MIRType type, Register tem
// Load the GC thing in temp1.
if (type == MIRType::Value) {
unboxNonDouble(Address(PreBarrierReg, 0), temp1);
unboxGCThingForPreBarrierTrampoline(Address(PreBarrierReg, 0), temp1);
} else {
MOZ_ASSERT(type == MIRType::Object ||
type == MIRType::String ||

Просмотреть файл

@ -1873,7 +1873,7 @@ class MacroAssembler : public MacroAssemblerSpecific
moveDouble(ReturnDoubleReg, reg);
}
inline void storeCallResultValue(AnyRegister dest);
inline void storeCallResultValue(AnyRegister dest, JSValueType type);
void storeCallResultValue(ValueOperand dest) {
#if defined(JS_NUNBOX32)
@ -1998,16 +1998,6 @@ class MacroAssembler : public MacroAssemblerSpecific
void storeUnboxedProperty(T address, JSValueType type,
const ConstantOrRegister& value, Label* failure);
template <typename T>
Register extractString(const T& source, Register scratch) {
return extractObject(source, scratch);
}
template <typename T>
Register extractSymbol(const T& source, Register scratch) {
return extractObject(source, scratch);
}
void debugAssertIsObject(const ValueOperand& val);
using MacroAssemblerSpecific::extractTag;

Просмотреть файл

@ -3040,21 +3040,21 @@ MacroAssemblerARMCompat::testGCThing(Condition cond, const BaseIndex& address)
// Unboxing code.
void
MacroAssemblerARMCompat::unboxNonDouble(const ValueOperand& operand, Register dest)
MacroAssemblerARMCompat::unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType)
{
if (operand.payloadReg() != dest)
ma_mov(operand.payloadReg(), dest);
}
void
MacroAssemblerARMCompat::unboxNonDouble(const Address& src, Register dest)
MacroAssemblerARMCompat::unboxNonDouble(const Address& src, Register dest, JSValueType)
{
ScratchRegisterScope scratch(asMasm());
ma_ldr(ToPayload(src), dest, scratch);
}
void
MacroAssemblerARMCompat::unboxNonDouble(const BaseIndex& src, Register dest)
MacroAssemblerARMCompat::unboxNonDouble(const BaseIndex& src, Register dest, JSValueType)
{
ScratchRegisterScope scratch(asMasm());
SecondScratchRegisterScope scratch2(asMasm());
@ -3079,7 +3079,7 @@ MacroAssemblerARMCompat::unboxDouble(const Address& src, FloatRegister dest)
}
void
MacroAssemblerARMCompat::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerARMCompat::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type)
{
if (dest.isFloat()) {
Label notInt32, end;

Просмотреть файл

@ -757,25 +757,52 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testGCThing(Condition cond, const BaseIndex& src);
// Unboxing code.
void unboxNonDouble(const ValueOperand& operand, Register dest);
void unboxNonDouble(const Address& src, Register dest);
void unboxNonDouble(const BaseIndex& src, Register dest);
void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
void unboxNonDouble(const ValueOperand& operand, Register dest, JSValueType type);
void unboxNonDouble(const Address& src, Register dest, JSValueType type);
void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type);
void unboxInt32(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
}
void unboxInt32(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
}
void unboxBoolean(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
}
void unboxBoolean(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
}
void unboxString(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxString(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxSymbol(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxSymbol(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxObject(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const BaseIndex& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxDouble(const ValueOperand& src, FloatRegister dest);
void unboxDouble(const Address& src, FloatRegister dest);
void unboxValue(const ValueOperand& src, AnyRegister dest);
void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
void unboxPrivate(const ValueOperand& src, Register dest);
// See comment in MacroAssembler-x64.h.
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
load32(ToPayload(src), dest);
}
void notBoolean(const ValueOperand& val) {
as_eor(val.payloadReg(), val.payloadReg(), Imm8(1));
}
@ -791,6 +818,12 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Register extractObject(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractString(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractInt32(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
@ -843,7 +876,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
}
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType) {
switch (nbytes) {
case 4:
storePtr(value.payloadReg(), address);

Просмотреть файл

@ -1880,7 +1880,7 @@ MacroAssemblerCompat::ensureDouble(const ValueOperand& source, FloatRegister des
}
void
MacroAssemblerCompat::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerCompat::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type)
{
if (dest.isFloat()) {
Label notInt32, end;
@ -1891,7 +1891,7 @@ MacroAssemblerCompat::unboxValue(const ValueOperand& src, AnyRegister dest)
unboxDouble(src, dest.fpu());
bind(&end);
} else {
unboxNonDouble(src, dest.gpr());
unboxNonDouble(src, dest.gpr(), type);
}
}

Просмотреть файл

@ -330,12 +330,15 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
push(scratch);
}
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType type) {
switch (nbytes) {
case 8: {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
unboxNonDouble(value, scratch);
if (type == JSVAL_TYPE_OBJECT)
unboxObjectOrNull(value, scratch);
else
unboxNonDouble(value, scratch, type);
storePtr(scratch, address);
return;
}
@ -401,6 +404,14 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
unboxObject(value, scratch);
return scratch;
}
Register extractString(const ValueOperand& value, Register scratch) {
unboxString(value, scratch);
return scratch;
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
unboxSymbol(value, scratch);
return scratch;
}
Register extractInt32(const ValueOperand& value, Register scratch) {
unboxInt32(value, scratch);
return scratch;
@ -1343,18 +1354,28 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void unboxMagic(const ValueOperand& src, Register dest) {
move32(src.valueReg(), dest);
}
// Unbox any non-double value into dest. Prefer unboxInt32 or unboxBoolean
// instead if the source type is known.
void unboxNonDouble(const ValueOperand& src, Register dest) {
unboxNonDouble(src.valueReg(), dest);
}
void unboxNonDouble(Address src, Register dest) {
loadPtr(src, dest);
unboxNonDouble(dest, dest);
void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type) {
unboxNonDouble(src.valueReg(), dest, type);
}
void unboxNonDouble(Register src, Register dest) {
And(ARMRegister(dest, 64), ARMRegister(src, 64), Operand((1ULL << JSVAL_TAG_SHIFT) - 1ULL));
template <typename T>
void unboxNonDouble(T src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
load32(src, dest);
return;
}
loadPtr(src, dest);
unboxNonDouble(dest, dest, type);
}
void unboxNonDouble(Register src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
move32(src, dest);
return;
}
Eor(ARMRegister(dest, 64), ARMRegister(src, 64), Operand(JSVAL_TYPE_TO_SHIFTED_TAG(type)));
}
void unboxPrivate(const ValueOperand& src, Register dest) {
@ -1366,33 +1387,45 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
eor(r, r, Operand(1));
}
void unboxObject(const ValueOperand& src, Register dest) {
unboxNonDouble(src.valueReg(), dest);
unboxNonDouble(src.valueReg(), dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(Register src, Register dest) {
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const Address& src, Register dest) {
loadPtr(src, dest);
unboxNonDouble(dest, dest);
unboxNonDouble(dest, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const BaseIndex& src, Register dest) {
doBaseIndex(ARMRegister(dest, 64), src, vixl::LDR_x);
unboxNonDouble(dest, dest);
unboxNonDouble(dest, dest, JSVAL_TYPE_OBJECT);
}
inline void unboxValue(const ValueOperand& src, AnyRegister dest);
template <typename T>
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(~JSVAL_OBJECT_OR_NULL_BIT));
}
// See comment in MacroAssembler-x64.h.
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
loadPtr(src, dest);
And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(JSVAL_PAYLOAD_MASK_GCTHING));
}
inline void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
void unboxString(const ValueOperand& operand, Register dest) {
unboxNonDouble(operand, dest);
unboxNonDouble(operand, dest, JSVAL_TYPE_STRING);
}
void unboxString(const Address& src, Register dest) {
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxSymbol(const ValueOperand& operand, Register dest) {
unboxNonDouble(operand, dest);
unboxNonDouble(operand, dest, JSVAL_TYPE_SYMBOL);
}
void unboxSymbol(const Address& src, Register dest) {
unboxNonDouble(src, dest);
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
// These two functions use the low 32-bits of the full value register.
void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
@ -1794,11 +1827,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
MOZ_ASSERT(scratch64.asUnsized() != address.base);
Ldr(scratch64, toMemOperand(address));
int32OrDouble(scratch64.asUnsized(), ARMFPRegister(dest.fpu(), 64));
} else if (type == MIRType::Int32 || type == MIRType::Boolean) {
load32(address, dest.gpr());
} else if (type == MIRType::ObjectOrNull) {
unboxObjectOrNull(address, dest.gpr());
} else {
loadPtr(address, dest.gpr());
unboxNonDouble(dest.gpr(), dest.gpr());
unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type));
}
}
@ -1810,11 +1842,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
MOZ_ASSERT(scratch64.asUnsized() != address.index);
doBaseIndex(scratch64, address, vixl::LDR_x);
int32OrDouble(scratch64.asUnsized(), ARMFPRegister(dest.fpu(), 64));
} else if (type == MIRType::Int32 || type == MIRType::Boolean) {
load32(address, dest.gpr());
} else if (type == MIRType::ObjectOrNull) {
unboxObjectOrNull(address, dest.gpr());
} else {
loadPtr(address, dest.gpr());
unboxNonDouble(dest.gpr(), dest.gpr());
unboxNonDouble(address, dest.gpr(), ValueTypeFromMIRType(type));
}
}
@ -2033,7 +2064,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void movePayload(Register src, Register dest) {
// Bfxil cannot be used with the zero register as a source.
if (src == rzr)
And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(~int64_t(JSVAL_PAYLOAD_MASK)));
And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(JSVAL_TAG_MASK));
else
Bfxil(ARMRegister(dest, 64), ARMRegister(src, 64), 0, JSVAL_TAG_SHIFT);
}

Просмотреть файл

@ -320,12 +320,15 @@ class MacroAssemblerNone : public Assembler
template <typename T> void unboxSymbol(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxObject(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxDouble(T, FloatRegister) { MOZ_CRASH(); }
void unboxValue(const ValueOperand&, AnyRegister) { MOZ_CRASH(); }
void unboxNonDouble(const ValueOperand&, Register ) { MOZ_CRASH();}
void unboxNonDouble(const Address&, Register ) { MOZ_CRASH();}
void unboxValue(const ValueOperand&, AnyRegister, JSValueType) { MOZ_CRASH(); }
void unboxNonDouble(const ValueOperand&, Register, JSValueType) { MOZ_CRASH();}
void unboxNonDouble(const Address&, Register, JSValueType) { MOZ_CRASH();}
void unboxGCThingForPreBarrierTrampoline(const Address&, Register) { MOZ_CRASH(); }
void notBoolean(ValueOperand) { MOZ_CRASH(); }
Register extractObject(Address, Register) { MOZ_CRASH(); }
Register extractObject(ValueOperand, Register) { MOZ_CRASH(); }
Register extractString(ValueOperand, Register) { MOZ_CRASH(); }
Register extractSymbol(ValueOperand, Register) { MOZ_CRASH(); }
Register extractInt32(ValueOperand, Register) { MOZ_CRASH(); }
Register extractBoolean(ValueOperand, Register) { MOZ_CRASH(); }
template <typename T> Register extractTag(T, Register) { MOZ_CRASH(); }
@ -354,7 +357,7 @@ class MacroAssemblerNone : public Assembler
template <typename T> void loadUnboxedValue(T, MIRType, AnyRegister) { MOZ_CRASH(); }
template <typename T> void storeUnboxedValue(const ConstantOrRegister&, MIRType, T, MIRType) { MOZ_CRASH(); }
template <typename T> void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); }
template <typename T> void storeUnboxedPayload(ValueOperand value, T, size_t, JSValueType) { MOZ_CRASH(); }
void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); }
void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); }

Просмотреть файл

@ -823,6 +823,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.xorq_mr(src.disp(), src.base(), dest.encoding());
break;
case Operand::MEM_SCALE:
masm.xorq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.encoding());
break;
case Operand::MEM_ADDRESS32:
masm.xorq_mr(src.address(), dest.encoding());
break;

Просмотреть файл

@ -166,6 +166,12 @@ class BaseAssemblerX64 : public BaseAssembler
m_formatter.oneByteOp64(OP_XOR_GvEv, offset, base, dst);
}
void xorq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
spew("xorq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst));
m_formatter.oneByteOp64(OP_XOR_GvEv, offset, base, index, scale, dst);
}
void xorq_mr(const void* addr, RegisterID dst)
{
spew("xorq %p, %s", addr, GPReg64Name(dst));

Просмотреть файл

@ -890,7 +890,7 @@ MacroAssemblerX64::incrementInt32Value(const Address& addr)
}
void
MacroAssemblerX64::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerX64::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type)
{
if (dest.isFloat()) {
Label notInt32, end;
@ -901,7 +901,7 @@ MacroAssemblerX64::unboxValue(const ValueOperand& src, AnyRegister dest)
unboxDouble(src, dest.fpu());
bind(&end);
} else {
unboxNonDouble(src, dest.gpr());
unboxNonDouble(src, dest.gpr(), type);
}
}

Просмотреть файл

@ -755,49 +755,95 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
xorq(Imm32(1), val.valueReg());
}
// Unbox any non-double value into dest. Prefer unboxInt32 or unboxBoolean
// instead if the source type is known.
void unboxNonDouble(const ValueOperand& src, Register dest) {
void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
movl(src.valueReg(), dest);
return;
}
if (src.valueReg() == dest) {
ScratchRegisterScope scratch(asMasm());
mov(ImmWord(JSVAL_PAYLOAD_MASK), scratch);
andq(scratch, dest);
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
xorq(scratch, dest);
} else {
mov(ImmWord(JSVAL_PAYLOAD_MASK), dest);
andq(src.valueReg(), dest);
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
xorq(src.valueReg(), dest);
}
}
void unboxNonDouble(const Operand& src, Register dest) {
void unboxNonDouble(const Operand& src, Register dest, JSValueType type) {
MOZ_ASSERT(type != JSVAL_TYPE_DOUBLE);
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
movl(src, dest);
return;
}
// Explicitly permits |dest| to be used in |src|.
ScratchRegisterScope scratch(asMasm());
MOZ_ASSERT(dest != scratch);
if (src.containsReg(dest)) {
mov(ImmWord(JSVAL_PAYLOAD_MASK), scratch);
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
// If src is already a register, then src and dest are the same
// thing and we don't need to move anything into dest.
if (src.kind() != Operand::REG)
movq(src, dest);
andq(scratch, dest);
xorq(scratch, dest);
} else {
mov(ImmWord(JSVAL_PAYLOAD_MASK), dest);
andq(src, dest);
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), dest);
xorq(src, dest);
}
}
void unboxNonDouble(const Address& src, Register dest) {
unboxNonDouble(Operand(src), dest);
void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
unboxNonDouble(Operand(src), dest, type);
}
void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
unboxNonDouble(Operand(src), dest, type);
}
void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxString(const Operand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxString(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxSymbol(const Operand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(Operand(src), dest); }
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(Operand(src), dest); }
void unboxObject(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const Operand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const Address& src, Register dest) {
unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const BaseIndex& src, Register dest) {
unboxNonDouble(Operand(src), dest, JSVAL_TYPE_OBJECT);
}
template <typename T>
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
ScratchRegisterScope scratch(asMasm());
mov(ImmWord(~JSVAL_OBJECT_OR_NULL_BIT), scratch);
andq(scratch, dest);
}
// This should only be used for the pre-barrier trampoline, to unbox a
// string/symbol/object Value. It's fine there because we don't depend on
// the actual Value type. In almost all other cases, this would be
// Spectre-unsafe - use unboxNonDouble and friends instead.
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
movq(ImmWord(JSVAL_PAYLOAD_MASK_GCTHING), dest);
andq(Operand(src), dest);
}
// Extended unboxing API. If the payload is already in a register, returns
// that register. Otherwise, provides a move to the given scratch register,
@ -812,6 +858,16 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
unboxObject(value, scratch);
return scratch;
}
Register extractString(const ValueOperand& value, Register scratch) {
MOZ_ASSERT(scratch != ScratchReg);
unboxString(value, scratch);
return scratch;
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
MOZ_ASSERT(scratch != ScratchReg);
unboxSymbol(value, scratch);
return scratch;
}
Register extractInt32(const ValueOperand& value, Register scratch) {
MOZ_ASSERT(scratch != ScratchReg);
unboxInt32(value, scratch);
@ -834,7 +890,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
return scratch;
}
inline void unboxValue(const ValueOperand& src, AnyRegister dest);
inline void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
// These two functions use the low 32-bits of the full value register.
void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
@ -899,19 +955,26 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
if (dest.isFloat())
loadInt32OrDouble(src, dest.fpu());
else if (type == MIRType::Int32 || type == MIRType::Boolean)
movl(Operand(src), dest.gpr());
else if (type == MIRType::ObjectOrNull)
unboxObjectOrNull(src, dest.gpr());
else
unboxNonDouble(Operand(src), dest.gpr());
unboxNonDouble(Operand(src), dest.gpr(), ValueTypeFromMIRType(type));
}
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType type) {
switch (nbytes) {
case 8: {
ScratchRegisterScope scratch(asMasm());
unboxNonDouble(value, scratch);
unboxNonDouble(value, scratch, type);
storePtr(scratch, address);
if (type == JSVAL_TYPE_OBJECT) {
// Ideally we would call unboxObjectOrNull, but we need an extra
// scratch register for that. So unbox as object, then clear the
// object-or-null bit.
mov(ImmWord(~JSVAL_OBJECT_OR_NULL_BIT), scratch);
andq(scratch, Operand(address));
}
return;
}
case 4:

Просмотреть файл

@ -1115,7 +1115,7 @@ MacroAssemblerX86::convertUInt32ToFloat32(Register src, FloatRegister dest)
}
void
MacroAssemblerX86::unboxValue(const ValueOperand& src, AnyRegister dest)
MacroAssemblerX86::unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType)
{
if (dest.isFloat()) {
Label notInt32, end;

Просмотреть файл

@ -680,27 +680,49 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
movl(ImmType(type), dest.typeReg());
}
void unboxNonDouble(const ValueOperand& src, Register dest) {
void unboxNonDouble(const ValueOperand& src, Register dest, JSValueType type) {
if (src.payloadReg() != dest)
movl(src.payloadReg(), dest);
}
void unboxNonDouble(const Address& src, Register dest) {
void unboxNonDouble(const Address& src, Register dest, JSValueType type) {
movl(payloadOf(src), dest);
}
void unboxNonDouble(const BaseIndex& src, Register dest) {
void unboxNonDouble(const BaseIndex& src, Register dest, JSValueType type) {
movl(payloadOf(src), dest);
}
void unboxInt32(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxInt32(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBoolean(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
void unboxInt32(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
}
void unboxInt32(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_INT32);
}
void unboxBoolean(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
}
void unboxBoolean(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_BOOLEAN);
}
void unboxString(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxString(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_STRING);
}
void unboxSymbol(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxSymbol(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_SYMBOL);
}
void unboxObject(const ValueOperand& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const Address& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxObject(const BaseIndex& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
}
void unboxDouble(const Address& src, FloatRegister dest) {
loadDouble(Operand(src), dest);
}
@ -731,12 +753,17 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
vunpcklps(ScratchDoubleReg, dest, dest);
}
}
inline void unboxValue(const ValueOperand& src, AnyRegister dest);
inline void unboxValue(const ValueOperand& src, AnyRegister dest, JSValueType type);
void unboxPrivate(const ValueOperand& src, Register dest) {
if (src.payloadReg() != dest)
movl(src.payloadReg(), dest);
}
// See comment in MacroAssembler-x64.h.
void unboxGCThingForPreBarrierTrampoline(const Address& src, Register dest) {
movl(payloadOf(src), dest);
}
void notBoolean(const ValueOperand& val) {
xorl(Imm32(1), val.payloadReg());
}
@ -751,6 +778,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
Register extractObject(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractString(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractSymbol(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
Register extractInt32(const ValueOperand& value, Register scratch) {
return value.payloadReg();
}
@ -801,7 +834,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
inline void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes, JSValueType) {
switch (nbytes) {
case 4:
storePtr(value.payloadReg(), address);