Bug 1559072: Revert to old boxing format r=djvj

Differential Revision: https://phabricator.services.mozilla.com/D35547

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Iain Ireland 2019-06-25 17:34:50 +00:00
parent 7e04db4516
commit 5cd03cc9d2
6 changed files with 194 additions and 401 deletions

View File

@ -99,100 +99,26 @@ static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
#elif defined(JS_PUNBOX64)
/**
* On 64-bit, we want the encoding of a JSObject* and its Value to be
* identical so interconversion is free. x86-64 pointers presently
* must have their high 17 bits all set or all unset -- with current
* OSes, these bits in user-mode pointers must be unset -- so the
* encoding of an object must have the high 17 bits all zero.
*
* To make room, we adjust double values by the bit value 0x0007_ffff_ffff_ffff.
*
* Consider the values Zero, NaN, -Nan, +Inf, and -Inf with this adjustment:
* Zero: 0x0000_0000_0000_0000 => 0x0007_ffff_ffff_ffff
* +Inf: 0x7ff0_0000_0000_0000 => 0x7ff7_ffff_ffff_ffff
* NaN: 0x7ff8_0000_0000_0000 => 0x7fff_ffff_ffff_ffff
* -Inf: 0xfff0_0000_0000_0000 => 0xfff7_ffff_ffff_ffff
* -NaN: 0xfff8_0000_0000_0000 => 0xffff_ffff_ffff_ffff
*
* We assume that pointers have 47 significant low bits, and use bits 47-50
* as type signifiers. The value tag, then, is stored in the high 17
* bits of a value.
*
* Thus, boxing for doubles becomes:
* ADJ = 0x0007_ffff_ffff_ffff
* box(double d) = uint64_t(d) + ADJ
* unbox(uint64_t b) = as_double(b - ADJ)
*
* Boxing for object pointers is:
* box(object_ptr p) = uint64_t(p)
* unbox(u64 w) = object_ptr(w)
*
* Boxing for other values is:
* box_value<Type>(u64 val) = val ^ SHIFTED_TAG<Type>
* unbox_value<Type>(u64 w) = val ^ SHIFTED_TAG<Type>
*
* (The 'Spectre Mitigations' comment for Value explains why we use
* XOR here.)
*
* Note some subtleties of the tag ordering that let us
* efficiently test membership in certain classes:
* 1. As described above, Object is zero-tagged. Therefore,
* anything with a non-zero tag is primitive.
* 3. All GC tags are < Undefined.
* 4. All numbers are >= Int32.
* See ValueTestIsPrimitive and friends.
*/
enum JSValueTag : uint32_t {
JSVAL_TAG_OBJECT = 0x0,
JSVAL_TAG_PRIVATE_GCTHING = 0x1,
JSVAL_TAG_STRING = 0x2,
JSVAL_TAG_SYMBOL = 0x3,
JSVAL_TAG_BIGINT = 0x4,
JSVAL_TAG_UNDEFINED = 0x5,
JSVAL_TAG_NULL = 0x6,
JSVAL_TAG_BOOLEAN = 0x7,
JSVAL_TAG_MAGIC = 0x8,
JSVAL_TAG_INT32 = 0x9,
JSVAL_TAG_MAX_NON_DOUBLE = 0xE,
JSVAL_TAG_UNKNOWN = 0xF
JSVAL_TAG_MAX_DOUBLE = 0x1FFF0,
JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
};
constexpr JSValueType JSValueTagToType(JSValueTag tag) {
switch (tag) {
case JSVAL_TAG_OBJECT:
return JSVAL_TYPE_OBJECT;
case JSVAL_TAG_PRIVATE_GCTHING:
return JSVAL_TYPE_PRIVATE_GCTHING;
case JSVAL_TAG_STRING:
return JSVAL_TYPE_STRING;
case JSVAL_TAG_SYMBOL:
return JSVAL_TYPE_SYMBOL;
case JSVAL_TAG_BIGINT:
return JSVAL_TYPE_BIGINT;
case JSVAL_TAG_UNDEFINED:
return JSVAL_TYPE_UNDEFINED;
case JSVAL_TAG_NULL:
return JSVAL_TYPE_NULL;
case JSVAL_TAG_BOOLEAN:
return JSVAL_TYPE_BOOLEAN;
case JSVAL_TAG_MAGIC:
return JSVAL_TYPE_MAGIC;
case JSVAL_TAG_INT32:
return JSVAL_TYPE_INT32;
default:
MOZ_ASSERT_UNREACHABLE("Tag does not have corresponding type");
return JSVAL_TYPE_UNKNOWN;
}
}
static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
"compiler typed enum support is apparently buggy");
enum JSValueShiftedTag : uint64_t {
JSVAL_SHIFTED_TAG_MAX_DOUBLE =
((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_UNDEFINED =
(((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT),
@ -211,9 +137,6 @@ enum JSValueShiftedTag : uint64_t {
static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
"compiler typed enum support is apparently buggy");
static_assert(static_cast<uint64_t>(JSVAL_SHIFTED_TAG_OBJECT) == 0,
"The object tag must be zero.");
#endif
namespace JS {
@ -231,71 +154,35 @@ constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
#elif defined(JS_PUNBOX64)
constexpr JSValueTag ValueTypeToTag(JSValueType type) {
return static_cast<JSValueTag>(JSVAL_TAG_MAX_DOUBLE | type);
}
constexpr uint64_t ValueTagMask = 0xFFFF'8000'0000'0000;
// This should only be used in toGCThing. See the 'Spectre mitigations' comment.
constexpr uint64_t ValueGCThingPayloadMask = 0x0000'7FFF'FFFF'FFFF;
constexpr JSValueTag ValueTypeToTag(JSValueType type) {
switch (type) {
case JSVAL_TYPE_OBJECT:
return JSVAL_TAG_OBJECT;
case JSVAL_TYPE_PRIVATE_GCTHING:
return JSVAL_TAG_PRIVATE_GCTHING;
case JSVAL_TYPE_STRING:
return JSVAL_TAG_STRING;
case JSVAL_TYPE_SYMBOL:
return JSVAL_TAG_SYMBOL;
case JSVAL_TYPE_BIGINT:
return JSVAL_TAG_BIGINT;
case JSVAL_TYPE_UNDEFINED:
return JSVAL_TAG_UNDEFINED;
case JSVAL_TYPE_NULL:
return JSVAL_TAG_NULL;
case JSVAL_TYPE_BOOLEAN:
return JSVAL_TAG_BOOLEAN;
case JSVAL_TYPE_MAGIC:
return JSVAL_TAG_MAGIC;
case JSVAL_TYPE_INT32:
return JSVAL_TAG_INT32;
default:
MOZ_ASSERT_UNREACHABLE("Type does not have corresponding tag");
return JSVAL_TAG_UNKNOWN;
}
}
constexpr uint64_t ValueTypeToShiftedTag(JSValueType type) {
return static_cast<uint64_t>(ValueTypeToTag(type)) << JSVAL_TAG_SHIFT;
}
# define JSVAL_TYPE_TO_SHIFTED_TAG(type) \
(JS::detail::ValueTypeToShiftedTag(type))
constexpr uint64_t ValueDoubleAdjust = 0x0007'FFFF'FFFF'FFFF;
constexpr uint64_t ValueBoxedMaxObjPtr = 0x0000'7FFF'FFFF'FFFF;
constexpr uint64_t ValuePrivateDoubleBit = 0x8000'0000'0000'0000;
constexpr JSValueTag ValueUpperExclPrimitiveTag = JSVAL_TAG_OBJECT;
constexpr JSValueTag ValueUpperInclNumberTag = JSVAL_TAG_INT32;
constexpr JSValueTag ValueLowerInclGCThingTag = JSVAL_TAG_STRING;
constexpr uint64_t ValueBoxedUndefined =
static_cast<uint64_t>(JSVAL_SHIFTED_TAG_UNDEFINED);
constexpr uint64_t ValueBoxedMinInt32 =
static_cast<uint64_t>(JSVAL_SHIFTED_TAG_INT32);
constexpr uint64_t ValueBoxedMinDouble = ValueDoubleAdjust;
constexpr uint64_t ValueUpperExclShiftedPrimitiveTag = JSVAL_SHIFTED_TAG_OBJECT;
constexpr uint64_t ValueUpperExclShiftedNumberTag = JSVAL_SHIFTED_TAG_BOOLEAN;
constexpr uint64_t ValueLowerInclShiftedGCThingTag = JSVAL_SHIFTED_TAG_STRING;
constexpr bool ValueTestIsObject(uint64_t bits) {
return bits <= ValueBoxedMaxObjPtr;
}
constexpr bool ValueTestIsPrimitive(uint64_t bits) {
return !ValueTestIsObject(bits);
}
constexpr bool ValueTestIsNumber(uint64_t bits) {
return bits >= ValueBoxedMinInt32;
}
constexpr bool ValueTestIsDouble(uint64_t bits) {
return bits >= ValueBoxedMinDouble;
}
constexpr bool ValueTestIsGCThing(uint64_t bits) {
return bits < ValueBoxedUndefined;
}
// JSVAL_TYPE_OBJECT and JSVAL_TYPE_NULL differ by one bit. We can use this to
// implement toObjectOrNull more efficiently.
constexpr uint64_t ValueObjectOrNullBit = 0x8ULL << JSVAL_TAG_SHIFT;
static_assert(
(JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == ValueObjectOrNullBit,
"ValueObjectOrNullBit must be consistent with object and null tags");
#endif /* JS_PUNBOX64 */
@ -492,12 +379,7 @@ union alignas(8) Value {
#if defined(JS_NONCANONICAL_HARDWARE_NAN)
d = CanonicalizeNaN(d);
#endif
#if defined(JS_NUNBOX32)
return mozilla::BitwiseCast<uint64_t>(d);
#elif defined(JS_PUNBOX64)
return mozilla::BitwiseCast<uint64_t>(d) + detail::ValueDoubleAdjust;
#endif
}
static_assert(sizeof(JSValueType) == 1,
@ -596,14 +478,7 @@ union alignas(8) Value {
private:
void setObjectNoCheck(JSObject* obj) {
#if defined(JS_NUNBOX32)
asBits_ = bitsFromTagAndPayload(JSVAL_TAG_OBJECT, PayloadType(obj));
#elif defined(JS_PUNBOX64)
static_assert(JSVAL_SHIFTED_TAG_OBJECT == 0,
"Object pointer tag should be 0.");
asBits_ = reinterpret_cast<uint64_t>(obj);
MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) == 0);
#endif
}
friend inline Value js::PoisonedObjectValue(uintptr_t poison);
@ -719,7 +594,8 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
#elif defined(JS_PUNBOX64)
return detail::ValueTestIsDouble(asBits_);
return (asBits_ | mozilla::FloatingPoint<double>::kSignBit) <=
JSVAL_SHIFTED_TAG_MAX_DOUBLE;
#endif
}
@ -728,7 +604,7 @@ union alignas(8) Value {
MOZ_ASSERT(toTag() != JSVAL_TAG_CLEAR);
return uint32_t(toTag()) <= uint32_t(detail::ValueUpperInclNumberTag);
#elif defined(JS_PUNBOX64)
return detail::ValueTestIsNumber(asBits_);
return asBits_ < detail::ValueUpperExclShiftedNumberTag;
#endif
}
@ -742,7 +618,8 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return toTag() == JSVAL_TAG_OBJECT;
#elif defined(JS_PUNBOX64)
return detail::ValueTestIsObject(asBits_);
MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
return asBits_ >= JSVAL_SHIFTED_TAG_OBJECT;
#endif
}
@ -750,7 +627,7 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return uint32_t(toTag()) < uint32_t(detail::ValueUpperExclPrimitiveTag);
#elif defined(JS_PUNBOX64)
return detail::ValueTestIsPrimitive(asBits_);
return asBits_ < detail::ValueUpperExclShiftedPrimitiveTag;
#endif
}
@ -761,7 +638,7 @@ union alignas(8) Value {
/* gcc sometimes generates signed < without explicit casts. */
return uint32_t(toTag()) >= uint32_t(detail::ValueLowerInclGCThingTag);
#elif defined(JS_PUNBOX64)
return detail::ValueTestIsGCThing(asBits_);
return asBits_ >= detail::ValueLowerInclShiftedGCThingTag;
#endif
}
@ -833,11 +710,7 @@ union alignas(8) Value {
double toDouble() const {
MOZ_ASSERT(isDouble());
#if defined(JS_NUNBOX32)
return mozilla::BitwiseCast<double>(asBits_);
#elif defined(JS_PUNBOX64)
return mozilla::BitwiseCast<double>(asBits_ - detail::ValueDoubleAdjust);
#endif
}
double toNumber() const {
@ -879,9 +752,10 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return *s_.payload_.obj_;
#elif defined(JS_PUNBOX64)
static_assert(JSVAL_SHIFTED_TAG_OBJECT == 0, "Object tag should be zero");
MOZ_ASSERT((asBits_ & 0x7) == 0);
return *reinterpret_cast<JSObject*>(asBits_);
uint64_t ptrBits = asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT;
MOZ_ASSERT(ptrBits);
MOZ_ASSERT((ptrBits & 0x7) == 0);
return *reinterpret_cast<JSObject*>(ptrBits);
#endif
}
@ -890,12 +764,10 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return s_.payload_.obj_;
#elif defined(JS_PUNBOX64)
static_assert(JSVAL_SHIFTED_TAG_OBJECT == 0, "Object tag should be zero");
// Since the object tag is zero, we simply need to zero out
// the set bits in the `null` tag to get this. This is not
// a SPECTRE issue as only the set bits in the NULL tag are
// cleared, and any other tag bits are left.
uint64_t ptrBits = asBits_ & ~JSVAL_SHIFTED_TAG_NULL;
// 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 =
(asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT) & ~detail::ValueObjectOrNullBit;
MOZ_ASSERT((ptrBits & 0x7) == 0);
return reinterpret_cast<JSObject*>(ptrBits);
#endif
@ -931,11 +803,7 @@ union alignas(8) Value {
uint64_t asRawBits() const { return asBits_; }
JSValueType extractNonDoubleType() const {
#if defined(JS_NUNBOX32)
uint32_t type = toTag() & 0xF;
#elif defined(JS_PUNBOX64)
uint32_t type = JSValueTagToType(toTag());
#endif
MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
return JSValueType(type);
}
@ -956,8 +824,7 @@ union alignas(8) Value {
* Private setters/getters allow the caller to read/write arbitrary types
* that fit in the 64-bit payload. It is the caller's responsibility, after
* storing to a value with setPrivateX to read only using getPrivateX.
* Private values are munged to look like double values to ensure they are
* not marked by the GC.
* Private values are given a type which ensures they aren't marked by the GC.
*/
void setPrivate(void* ptr) {
@ -966,8 +833,7 @@ union alignas(8) Value {
s_.tag_ = JSValueTag(0);
s_.payload_.ptr_ = ptr;
#elif defined(JS_PUNBOX64)
// Set high bit so this will always masquerade as a DoubleValue.
asBits_ = (uintptr_t(ptr) >> 1) | detail::ValuePrivateDoubleBit;
asBits_ = uintptr_t(ptr) >> 1;
#endif
MOZ_ASSERT(isDouble());
}
@ -977,7 +843,7 @@ union alignas(8) Value {
#if defined(JS_NUNBOX32)
return s_.payload_.ptr_;
#elif defined(JS_PUNBOX64)
MOZ_ASSERT((asBits_ & detail::ValuePrivateDoubleBit) != 0);
MOZ_ASSERT((asBits_ & 0x8000000000000000ULL) == 0);
return reinterpret_cast<void*>(asBits_ << 1);
#endif
}
@ -1073,19 +939,11 @@ static inline Value CanonicalizedDoubleValue(double d) {
}
static inline constexpr Value NaNValue() {
uint64_t rawBits = detail::CanonicalizedNaNBits;
#if defined(JS_PUNBOX64)
rawBits += detail::ValueDoubleAdjust;
#endif
return Value::fromRawBits(rawBits);
return Value::fromRawBits(detail::CanonicalizedNaNBits);
}
static inline Value InfinityValue() {
uint64_t rawBits = detail::InfinityBits;
#if defined(JS_PUNBOX64)
rawBits += detail::ValueDoubleAdjust;
#endif
return Value::fromRawBits(rawBits);
return Value::fromRawBits(detail::InfinityBits);
}
static inline Value Float32Value(float f) {

View File

@ -746,11 +746,7 @@ template void MacroAssembler::storeDouble(FloatRegister src,
template <class T>
void MacroAssembler::boxDouble(FloatRegister src, const T& dest) {
#if defined(JS_NUNBOX32)
storeDouble(src, dest);
#elif defined(JS_PUNBOX64)
MacroAssemblerSpecific::boxDouble(src, dest);
#endif
}
template <class T>

View File

@ -397,17 +397,18 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
Orr(ARMRegister(dest, 64), ARMRegister(src, 64),
Operand(ImmShiftedTag(type).value));
}
void splitTag(Register src, Register dest) {
Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), JSVAL_TAG_SHIFT);
void splitSignExtTag(Register src, Register dest) {
sbfx(ARMRegister(dest, 64), ARMRegister(src, 64), JSVAL_TAG_SHIFT,
(64 - JSVAL_TAG_SHIFT));
}
MOZ_MUST_USE Register extractTag(const Address& address, Register scratch) {
loadPtr(address, scratch);
splitTag(scratch, scratch);
splitSignExtTag(scratch, scratch);
return scratch;
}
MOZ_MUST_USE Register extractTag(const ValueOperand& value,
Register scratch) {
splitTag(value.valueReg(), scratch);
splitSignExtTag(value.valueReg(), scratch);
return scratch;
}
MOZ_MUST_USE Register extractObject(const Address& address,
@ -1163,16 +1164,16 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
MOZ_CRASH("moveFloatAsDouble");
}
void splitTag(const ValueOperand& operand, Register dest) {
splitTag(operand.valueReg(), dest);
void splitSignExtTag(const ValueOperand& operand, Register dest) {
splitSignExtTag(operand.valueReg(), dest);
}
void splitTag(const Address& operand, Register dest) {
void splitSignExtTag(const Address& operand, Register dest) {
loadPtr(operand, dest);
splitTag(dest, dest);
splitSignExtTag(dest, dest);
}
void splitTag(const BaseIndex& operand, Register dest) {
void splitSignExtTag(const BaseIndex& operand, Register dest) {
loadPtr(operand, dest);
splitTag(dest, dest);
splitSignExtTag(dest, dest);
}
// Extracts the tag of a value and places it in tag
@ -1312,35 +1313,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
MOZ_CRASH("branchNegativeZeroFloat32");
}
void BoxDouble(ARMRegister dest, ARMRegister src) {
// Allowed for `src` and `dest.valueReg()` to overlap here.
Add(dest, src, Operand(int64_t(JS::detail::ValueDoubleAdjust)));
}
void BoxDouble(ARMRegister dest, ARMFPRegister src) {
// Allowed for `src` and `dest.valueReg()` to overlap here.
Fmov(dest, src);
BoxDouble(dest, dest);
}
void boxDouble(Register src, Register dest) {
// Allowed for `src` and `dest.valueReg()` to overlap here.
BoxDouble(ARMRegister(dest, 64), ARMRegister(src, 64));
}
void boxDouble(FloatRegister src, Register dest) {
BoxDouble(ARMRegister(dest, 64), ARMFPRegister(src, 64));
}
void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) {
BoxDouble(ARMRegister(dest.valueReg(), 64), ARMFPRegister(src, 64));
}
void boxDouble(FloatRegister src, const Address& addr, Register scratch) {
BoxDouble(ARMRegister(scratch, 64), ARMFPRegister(src, 64));
Str(ARMRegister(scratch, 64), toMemOperand(addr));
}
template <typename T>
void boxDouble(FloatRegister src, const T& dest) {
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch64 = temps.AcquireX();
BoxDouble(scratch64, ARMFPRegister(src, 64));
storePtr(scratch64.asUnsized(), dest);
Fmov(ARMRegister(dest.valueReg(), 64), ARMFPRegister(src, 64));
}
void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
boxValue(type, src, dest.valueReg());
@ -1355,20 +1329,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
template <typename T>
void unboxDouble(const T& src, FloatRegister dest) {
vixl::UseScratchRegisterScope temps(this);
const ARMRegister scratch64 = temps.AcquireX();
loadPtr(src, scratch64.asUnsized());
Sub(scratch64, scratch64, Operand(int64_t(JS::detail::ValueDoubleAdjust)));
Fmov(ARMFPRegister(dest, 64), scratch64);
loadDouble(src, dest);
}
void unboxDouble(const ValueOperand& src, FloatRegister dest) {
unboxDouble(src, ARMFPRegister(dest, 64));
}
void unboxDouble(const ValueOperand& src, ARMFPRegister dest) {
ARMRegister srcReg = ARMRegister(src.valueReg(), 64);
Sub(srcReg, srcReg, Operand(int64_t(JS::detail::ValueDoubleAdjust)));
Fmov(dest, srcReg);
Add(srcReg, srcReg, Operand(int64_t(JS::detail::ValueDoubleAdjust)));
Fmov(ARMFPRegister(dest, 64), ARMRegister(src.valueReg(), 64));
}
void unboxArgObjMagic(const ValueOperand& src, Register dest) {
@ -1408,15 +1372,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
move32(src, dest);
return;
}
if (type == JSVAL_TYPE_OBJECT) {
MOZ_ASSERT(ImmShiftedTag(type).value == 0);
if (src != dest) {
movePtr(src, dest);
}
return;
}
Eor(ARMRegister(dest, 64), ARMRegister(src, 64),
Operand(ImmShiftedTag(type).value));
Operand(JSVAL_TYPE_TO_SHIFTED_TAG(type)));
}
void unboxPrivate(const ValueOperand& src, Register dest) {
@ -1446,7 +1403,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
And(ARMRegister(dest, 64), ARMRegister(dest, 64),
Operand(~JSVAL_SHIFTED_TAG_NULL));
Operand(~JS::detail::ValueObjectOrNullBit));
}
// See comment in MacroAssembler-x64.h.
@ -1500,7 +1457,35 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
}
void cmpTag(Register tag, ImmTag ref) {
cmp32(tag, Imm32(int32_t(ref.value)));
// As opposed to other architecture, splitTag is replaced by splitSignExtTag
// which extract the tag with a sign extension. The reason being that cmp32
// with a tag value would be too large to fit as a 12 bits immediate value,
// and would require the VIXL macro assembler to add an extra instruction
// and require extra scratch register to load the Tag value.
//
// Instead, we compare with the negative value of the sign extended tag with
// the CMN instruction. The sign extended tag is expected to be a negative
// value. Therefore the negative of the sign extended tag is expected to be
// near 0 and fit on 12 bits.
//
// Ignoring the sign extension, the logic is the following:
//
// CMP32(Reg, Tag) = Reg - Tag
// = Reg + (-Tag)
// = CMN32(Reg, -Tag)
//
// Note: testGCThing, testPrimitive and testNumber which are checking for
// inequalities should use unsigned comparisons (as done by default) in
// order to keep the same relation order after the sign extension, i.e.
// using Above or Below which are based on the carry flag.
uint32_t hiShift = JSVAL_TAG_SHIFT - 32;
int32_t seTag = int32_t(ref.value);
seTag = (seTag << hiShift) >> hiShift;
MOZ_ASSERT(seTag < 0);
int32_t negTag = -seTag;
// Check thest negTag is encoded on a 12 bits immediate value.
MOZ_ASSERT((negTag & ~0xFFF) == 0);
cmn32(tag, Imm32(negTag));
}
// Register-based tests.
@ -1546,18 +1531,21 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
}
Condition testDouble(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpTag(tag, ImmTag(JSVAL_TAG_MAX_NON_DOUBLE));
return (cond == Equal) ? Above : BelowOrEqual;
cmpTag(tag, ImmTag(JSVAL_TAG_MAX_DOUBLE));
// Requires unsigned comparison due to cmpTag internals.
return (cond == Equal) ? BelowOrEqual : Above;
}
Condition testNumber(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpTag(tag, ImmTag(JSVAL_TAG_INT32));
return cond == Equal ? AboveOrEqual : Below;
cmpTag(tag, ImmTag(JS::detail::ValueUpperInclNumberTag));
// Requires unsigned comparison due to cmpTag internals.
return (cond == Equal) ? BelowOrEqual : Above;
}
Condition testGCThing(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpTag(tag, ImmTag(JSVAL_TAG_UNDEFINED));
return cond == Equal ? Below : AboveOrEqual;
cmpTag(tag, ImmTag(JS::detail::ValueLowerInclGCThingTag));
// Requires unsigned comparison due to cmpTag internals.
return (cond == Equal) ? AboveOrEqual : Below;
}
Condition testMagic(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
@ -1566,8 +1554,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
}
Condition testPrimitive(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpTag(tag, ImmTag(JSVAL_TAG_OBJECT));
return cond == Equal ? NotEqual : Equal;
cmpTag(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag));
// Requires unsigned comparison due to cmpTag internals.
return (cond == Equal) ? Below : AboveOrEqual;
}
Condition testError(Condition cond, Register tag) {
return testMagic(cond, tag);
@ -1580,84 +1569,84 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(scratch != value.valueReg());
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testInt32(cond, scratch);
}
Condition testBoolean(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testBoolean(cond, scratch);
}
Condition testDouble(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testDouble(cond, scratch);
}
Condition testNull(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testNull(cond, scratch);
}
Condition testUndefined(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testUndefined(cond, scratch);
}
Condition testString(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testString(cond, scratch);
}
Condition testSymbol(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testBigInt(cond, scratch);
}
Condition testObject(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testObject(cond, scratch);
}
Condition testNumber(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testNumber(cond, scratch);
}
Condition testPrimitive(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testPrimitive(cond, scratch);
}
Condition testMagic(Condition cond, const ValueOperand& value) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(value.valueReg() != scratch);
splitTag(value, scratch);
splitSignExtTag(value, scratch);
return testMagic(cond, scratch);
}
Condition testError(Condition cond, const ValueOperand& value) {
@ -1669,84 +1658,84 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testGCThing(cond, scratch);
}
Condition testMagic(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testMagic(cond, scratch);
}
Condition testInt32(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testInt32(cond, scratch);
}
Condition testDouble(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testDouble(cond, scratch);
}
Condition testBoolean(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testBoolean(cond, scratch);
}
Condition testNull(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testNull(cond, scratch);
}
Condition testUndefined(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testUndefined(cond, scratch);
}
Condition testString(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testString(cond, scratch);
}
Condition testSymbol(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testBigInt(cond, scratch);
}
Condition testObject(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testObject(cond, scratch);
}
Condition testNumber(Condition cond, const Address& address) {
vixl::UseScratchRegisterScope temps(this);
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(address.base != scratch);
splitTag(address, scratch);
splitSignExtTag(address, scratch);
return testNumber(cond, scratch);
}
@ -1756,7 +1745,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testUndefined(cond, scratch);
}
Condition testNull(Condition cond, const BaseIndex& src) {
@ -1764,7 +1753,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testNull(cond, scratch);
}
Condition testBoolean(Condition cond, const BaseIndex& src) {
@ -1772,7 +1761,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testBoolean(cond, scratch);
}
Condition testString(Condition cond, const BaseIndex& src) {
@ -1780,7 +1769,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testString(cond, scratch);
}
Condition testSymbol(Condition cond, const BaseIndex& src) {
@ -1788,7 +1777,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const BaseIndex& src) {
@ -1796,7 +1785,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testBigInt(cond, scratch);
}
Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
@ -1817,7 +1806,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testInt32(cond, scratch);
}
Condition testObject(Condition cond, const BaseIndex& src) {
@ -1825,7 +1814,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testObject(cond, scratch);
}
Condition testDouble(Condition cond, const BaseIndex& src) {
@ -1833,7 +1822,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testDouble(cond, scratch);
}
Condition testMagic(Condition cond, const BaseIndex& src) {
@ -1841,7 +1830,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testMagic(cond, scratch);
}
Condition testGCThing(Condition cond, const BaseIndex& src) {
@ -1849,7 +1838,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(src.base != scratch);
MOZ_ASSERT(src.index != scratch);
splitTag(src, scratch);
splitSignExtTag(src, scratch);
return testGCThing(cond, scratch);
}
@ -1882,8 +1871,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
Label join;
testInt32(Equal, ValueOperand(src));
B(&isInt32, Equal);
// is double, unbox it.
unboxDouble(ValueOperand(src), dest);
// is double, move teh bits as is
Fmov(dest, ARMRegister(src, 64));
B(&join);
bind(&isInt32);
// is int32, do a conversion while moving
@ -2179,7 +2168,7 @@ class ScratchTagScopeRelease {
inline void MacroAssemblerCompat::splitTagForTest(const ValueOperand& value,
ScratchTagScope& tag) {
splitTag(value, tag);
splitSignExtTag(value, tag);
}
typedef MacroAssemblerCompat MacroAssemblerSpecific;

View File

@ -371,7 +371,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 {
template <typename T>
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
JS_STATIC_ASSERT(JSVAL_OBJECT_OR_NULL_BIT ==
JS_STATIC_ASSERT(JS::detail::ValueObjectOrNullBit ==
(uint64_t(0x8) << JSVAL_TAG_SHIFT));
ma_dins(dest, zero, Imm32(JSVAL_TAG_SHIFT + 3), Imm32(1));
}

View File

@ -119,11 +119,6 @@ void MacroAssemblerX64::boxValue(JSValueType type, Register src,
MOZ_ASSERT(src != dest);
JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
if (ImmShiftedTag(type).value == 0) {
MOZ_ASSERT(type == JSVAL_TYPE_OBJECT);
movq(src, dest);
return;
}
#ifdef DEBUG
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
Label upper32BitsZeroed;

View File

@ -201,15 +201,13 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
loadValue(src, dest);
}
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
ScratchRegisterScope scratch(asMasm());
MOZ_ASSERT(dest.valueReg() != scratch);
if (payload != dest.valueReg()) {
movq(payload, dest.valueReg());
}
if (ImmShiftedTag(type).value != 0) {
ScratchRegisterScope scratch(asMasm());
MOZ_ASSERT(dest.valueReg() != scratch);
mov(ImmShiftedTag(type), scratch);
orq(scratch, dest.valueReg());
}
mov(ImmShiftedTag(type), scratch);
orq(scratch, dest.valueReg());
}
void pushValue(ValueOperand val) { push(val.valueReg()); }
void popValue(ValueOperand val) { pop(val.valueReg()); }
@ -274,18 +272,18 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
}
Condition testDouble(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, Imm32(JSVAL_TAG_MAX_NON_DOUBLE));
return cond == Equal ? Above : BelowOrEqual;
cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
return cond == Equal ? BelowOrEqual : Above;
}
Condition testNumber(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, Imm32(JSVAL_TAG_INT32));
return cond == Equal ? AboveOrEqual : Below;
cmp32(tag, Imm32(JS::detail::ValueUpperInclNumberTag));
return cond == Equal ? BelowOrEqual : Above;
}
Condition testGCThing(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, Imm32(JSVAL_TAG_UNDEFINED));
return cond == Equal ? Below : AboveOrEqual;
cmp32(tag, Imm32(JS::detail::ValueLowerInclGCThingTag));
return cond == Equal ? AboveOrEqual : Below;
}
Condition testMagic(Condition cond, Register tag) {
@ -298,14 +296,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
}
Condition testPrimitive(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
return cond == Equal ? NotEqual : Equal;
cmp32(tag, ImmTag(JS::detail::ValueUpperExclPrimitiveTag));
return cond == Equal ? Below : AboveOrEqual;
}
Condition testUndefined(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedUndefined));
return cond;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testUndefined(cond, scratch);
}
Condition testInt32(Condition cond, const ValueOperand& src) {
ScratchRegisterScope scratch(asMasm());
@ -318,19 +316,19 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
return testBoolean(cond, scratch);
}
Condition testDouble(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedMinDouble));
return cond == Equal ? AboveOrEqual : Below;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testDouble(cond, scratch);
}
Condition testNumber(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedMinInt32));
return cond == Equal ? AboveOrEqual : Below;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testNumber(cond, scratch);
}
Condition testNull(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JSVAL_SHIFTED_TAG_NULL));
return cond;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testNull(cond, scratch);
}
Condition testString(Condition cond, const ValueOperand& src) {
ScratchRegisterScope scratch(asMasm());
@ -348,19 +346,19 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
return testBigInt(cond, scratch);
}
Condition testObject(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedMaxObjPtr));
return cond == Equal ? BelowOrEqual : Above;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testObject(cond, scratch);
}
Condition testGCThing(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedUndefined));
return cond == Equal ? Below : AboveOrEqual;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testGCThing(cond, scratch);
}
Condition testPrimitive(Condition cond, const ValueOperand& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src.valueReg(), ImmWord(JS::detail::ValueBoxedMaxObjPtr));
return cond == Equal ? Above : BelowOrEqual;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testPrimitive(cond, scratch);
}
Condition testUndefined(Condition cond, const Address& src) {
@ -377,14 +375,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
return cond;
}
Condition testDouble(Condition cond, const Address& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src, ImmWord(JS::detail::ValueBoxedMinDouble));
return cond == Equal ? AboveOrEqual : Below;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testDouble(cond, scratch);
}
Condition testNumber(Condition cond, const Address& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src, ImmWord(JS::detail::ValueBoxedMinInt32));
return cond == Equal ? AboveOrEqual : Below;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testNumber(cond, scratch);
}
Condition testNull(Condition cond, const Address& src) {
cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
@ -411,14 +409,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
return testObject(cond, scratch);
}
Condition testPrimitive(Condition cond, const Address& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src, ImmWord(JS::detail::ValueBoxedMaxObjPtr));
return cond == Equal ? Above : BelowOrEqual;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testPrimitive(cond, scratch);
}
Condition testGCThing(Condition cond, const Address& src) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmpPtr(src, ImmWord(JS::detail::ValueBoxedUndefined));
return cond == Equal ? Below : AboveOrEqual;
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testGCThing(cond, scratch);
}
Condition testMagic(Condition cond, const Address& src) {
ScratchRegisterScope scratch(asMasm());
@ -712,25 +710,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
emitSet(cond, dest);
}
void boxDouble(FloatRegister src, const Operand& dest, Register scratch) {
vmovq(src, scratch);
movq(scratch, Operand(dest));
movq(ImmWord(JS::detail::ValueDoubleAdjust), scratch);
addq(scratch, Operand(dest));
}
void boxDouble(FloatRegister src, const Address& dest, Register scratch) {
boxDouble(src, Operand(dest), scratch);
}
template <typename T>
void boxDouble(FloatRegister src, const T& dest) {
ScratchRegisterScope scratch(asMasm());
boxDouble(src, Operand(dest), scratch);
}
void boxDouble(FloatRegister src, const ValueOperand& dest, FloatRegister) {
ScratchRegisterScope scratch(asMasm());
vmovq(src, dest.valueReg());
movq(ImmWord(JS::detail::ValueDoubleAdjust), scratch);
addq(scratch, dest.valueReg());
}
void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
MOZ_ASSERT(src != dest.valueReg());
@ -748,12 +729,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
}
template <typename T>
void unboxDouble(const T& src, FloatRegister dest) {
// The value we want to produce is: to_float(src - ADJUST)
// we note that (src - ADJUST) == -ADJUST + src
ScratchRegisterScope scratch(asMasm());
movq(ImmWord(-JS::detail::ValueDoubleAdjust), scratch);
addq(Operand(src), scratch);
vmovq(scratch, dest);
loadDouble(Operand(src), dest);
}
void unboxArgObjMagic(const ValueOperand& src, Register dest) {
@ -779,12 +755,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
}
void unboxDouble(const ValueOperand& src, FloatRegister dest) {
// The value we want to produce is: to_float(src - ADJUST)
// we note that (src - ADJUST) == -ADJUST + src
ScratchRegisterScope scratch(asMasm());
movq(ImmWord(-JS::detail::ValueDoubleAdjust), scratch);
addq(src.valueReg(), scratch);
vmovq(scratch, dest);
vmovq(src.valueReg(), dest);
}
void unboxPrivate(const ValueOperand& src, const Register dest) {
movq(src.valueReg(), dest);
@ -800,13 +771,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
movl(src.valueReg(), dest);
return;
}
if (JSVAL_TYPE_TO_SHIFTED_TAG(type) == 0) {
MOZ_ASSERT(type == JSVAL_TYPE_OBJECT);
if (src.valueReg() != dest) {
movq(src.valueReg(), dest);
}
return;
}
if (src.valueReg() == dest) {
ScratchRegisterScope scratch(asMasm());
mov(ImmWord(JSVAL_TYPE_TO_SHIFTED_TAG(type)), scratch);
@ -822,15 +786,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
movl(src, dest);
return;
}
if (JSVAL_TYPE_TO_SHIFTED_TAG(type) == 0) {
MOZ_ASSERT(type == JSVAL_TYPE_OBJECT);
// Perform a simple move in all cases, except when the src
// is a simple register operand that's the same as `dest`.
if ((src.kind() != Operand::REG) || (src.reg() != dest.encoding())) {
movq(src, dest);
}
return;
}
// Explicitly permits |dest| to be used in |src|.
ScratchRegisterScope scratch(asMasm());
MOZ_ASSERT(dest != scratch);
@ -895,7 +850,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
void unboxObjectOrNull(const T& src, Register dest) {
unboxNonDouble(src, dest, JSVAL_TYPE_OBJECT);
ScratchRegisterScope scratch(asMasm());
mov(ImmWord(~JSVAL_SHIFTED_TAG_NULL), scratch);
mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
andq(scratch, dest);
}
@ -1032,7 +987,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
// 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_SHIFTED_TAG_NULL), scratch);
mov(ImmWord(~JS::detail::ValueObjectOrNullBit), scratch);
andq(scratch, Operand(address));
}
return;