зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
6adca5400a
Коммит
93e1e4e3d9
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче