mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 09:19:28 +00:00
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:
parent
7e04db4516
commit
5cd03cc9d2
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user