Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
510d86ddfb | ||
|
|
3527ad788c |
No files matched your search
@@ -1377,6 +1377,100 @@ TenuredCell::isAligned() const
|
||||
static const int32_t ChunkLocationOffsetFromLastByte =
|
||||
int32_t(gc::ChunkLocationOffset) - int32_t(gc::ChunkMask);
|
||||
|
||||
// Base class for GC things that have 32-bit length and 32-bit flags fields
|
||||
// stored at the beginning (currently BigInt).
|
||||
//
|
||||
// First word of a Cell has additional requirements from GC and normally
|
||||
// would store a pointer. If a single word isn't large enough, the length
|
||||
// is stored separately.
|
||||
//
|
||||
// 32 0
|
||||
// ------------------
|
||||
// | Length | Flags |
|
||||
// ------------------
|
||||
//
|
||||
// The low bits of the flags word (see NumFlagBitsReservedForGC) are reserved
|
||||
// for GC. Derived classes must ensure they don't use these flags for non-GC
|
||||
// purposes.
|
||||
template <class BaseCell>
|
||||
class CellWithLengthAndFlags : public BaseCell {
|
||||
static_assert(std::is_same<BaseCell, Cell>::value ||
|
||||
std::is_same<BaseCell, TenuredCell>::value,
|
||||
"BaseCell must be either Cell or TenuredCell");
|
||||
|
||||
// NOTE: This word can also be used for temporary storage, see
|
||||
// setTemporaryGCUnsafeData.
|
||||
uintptr_t flags_;
|
||||
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
// Additional storage for length if |flags_| is too small to fit both.
|
||||
uint32_t length_;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static constexpr size_t NumFlagBitsReservedForGC = 2; //Cell::ReservedBits;
|
||||
|
||||
uint32_t lengthField() const {
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
return length_;
|
||||
#else
|
||||
return uint32_t(flags_ >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t flagsField() const { return uint32_t(flags_); }
|
||||
|
||||
void setFlagBit(uint32_t flag) { flags_ |= uintptr_t(flag); }
|
||||
void clearFlagBit(uint32_t flag) { flags_ &= ~uintptr_t(flag); }
|
||||
void toggleFlagBit(uint32_t flag) { flags_ ^= uintptr_t(flag); }
|
||||
|
||||
void setLengthAndFlags(uint32_t len, uint32_t flags) {
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
flags_ = flags;
|
||||
length_ = len;
|
||||
#else
|
||||
flags_ = (uint64_t(len) << 32) | uint64_t(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Sub classes can store temporary data in the flags word. This is not GC safe
|
||||
// and users must ensure flags/length are never checked (including by asserts)
|
||||
// while this data is stored. Use of this method is strongly discouraged!
|
||||
void setTemporaryGCUnsafeData(uintptr_t data) { flags_ = data; }
|
||||
|
||||
// To get back the data, values to safely re-initialize clobbered flags
|
||||
// must be provided.
|
||||
uintptr_t unsetTemporaryGCUnsafeData(uint32_t len, uint32_t flags) {
|
||||
uintptr_t data = flags_;
|
||||
setLengthAndFlags(len, flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Offsets for direct field from jit code. A number of places directly
|
||||
// access 32-bit length and flags fields so do endian trickery here.
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
static constexpr size_t offsetOfFlags() {
|
||||
return offsetof(CellWithLengthAndFlags, flags_);
|
||||
}
|
||||
static constexpr size_t offsetOfLength() {
|
||||
return offsetof(CellWithLengthAndFlags, length_);
|
||||
}
|
||||
#elif MOZ_LITTLE_ENDIAN
|
||||
static constexpr size_t offsetOfFlags() {
|
||||
return offsetof(CellWithLengthAndFlags, flags_);
|
||||
}
|
||||
static constexpr size_t offsetOfLength() {
|
||||
return offsetof(CellWithLengthAndFlags, flags_) + sizeof(uint32_t);
|
||||
}
|
||||
#else
|
||||
static constexpr size_t offsetOfFlags() {
|
||||
return offsetof(CellWithLengthAndFlags, flags_) + sizeof(uint32_t);
|
||||
}
|
||||
static constexpr size_t offsetOfLength() {
|
||||
return offsetof(CellWithLengthAndFlags, flags_);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
|
||||
@@ -336,6 +336,13 @@ GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj
|
||||
if (!fieldDescr->is<SimpleTypeDescr>())
|
||||
return true;
|
||||
|
||||
if (fieldDescr->is<ScalarTypeDescr>()) {
|
||||
Scalar::Type type = fieldDescr->as<ScalarTypeDescr>().type();
|
||||
if (Scalar::isBigIntType(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Shape* shape = typedObj->maybeShape();
|
||||
TypedThingLayout layout = GetTypedThingLayout(shape->getObjectClass());
|
||||
|
||||
|
||||
@@ -9417,6 +9417,11 @@ IonBuilder::checkTypedObjectIndexInBounds(uint32_t elemSize,
|
||||
return indexAsByteOffset->add(index, AssertedCast<int32_t>(elemSize));
|
||||
}
|
||||
|
||||
static bool CheckTypedObjectSupportedType(Scalar::Type type) {
|
||||
// FIXME: Enable TypedArray JIT optimizations for Big(U)Int64Array
|
||||
return !Scalar::isBigIntType(type);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::getElemTryScalarElemOfTypedObject(bool* emitted,
|
||||
MDefinition* obj,
|
||||
@@ -9431,6 +9436,10 @@ IonBuilder::getElemTryScalarElemOfTypedObject(bool* emitted,
|
||||
ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
|
||||
MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||
|
||||
if (!CheckTypedObjectSupportedType(elemType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
return true;
|
||||
@@ -10523,6 +10532,10 @@ IonBuilder::setElemTryScalarElemOfTypedObject(bool* emitted,
|
||||
ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
|
||||
MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||
|
||||
if (!CheckTypedObjectSupportedType(elemType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LinearSum indexAsByteOffset(alloc());
|
||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
|
||||
return true;
|
||||
@@ -12110,6 +12123,10 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedO
|
||||
// Must always be loading the same scalar type
|
||||
Scalar::Type fieldType = fieldPrediction.scalarType();
|
||||
|
||||
if (!CheckTypedObjectSupportedType(fieldType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't optimize if the typed object's underlying buffer may be detached.
|
||||
TypeSet::ObjectKey* globalKey = TypeSet::ObjectKey::get(&script()->global());
|
||||
if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER))
|
||||
@@ -13196,6 +13213,10 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool* emitted,
|
||||
// Must always be loading the same scalar type
|
||||
Scalar::Type fieldType = fieldPrediction.scalarType();
|
||||
|
||||
if (!CheckTypedObjectSupportedType(fieldType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't optimize if the typed object's underlying buffer may be detached.
|
||||
TypeSet::ObjectKey* globalKey = TypeSet::ObjectKey::get(&script()->global());
|
||||
if (globalKey->hasFlags(constraints(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER))
|
||||
|
||||
@@ -1328,6 +1328,74 @@ MacroAssembler::loadStringChar(Register str, Register index, Register output)
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
void MacroAssembler::loadBigInt64(Register bigInt, Register64 dest) {
|
||||
// This code follows the implementation of |BigInt::toUint64()|. We're also
|
||||
// using it for inline callers of |BigInt::toInt64()|, which works, because
|
||||
// all supported Jit architectures use a two's complement representation for
|
||||
// int64 values, which means the WrapToSigned call in toInt64() is a no-op.
|
||||
|
||||
Label done, nonZero;
|
||||
|
||||
branch32(Assembler::NotEqual, Address(bigInt, BigInt::offsetOfLength()),
|
||||
Imm32(0), &nonZero);
|
||||
{
|
||||
move64(Imm64(0), dest);
|
||||
jump(&done);
|
||||
}
|
||||
bind(&nonZero);
|
||||
|
||||
#ifdef JS_PUNBOX64
|
||||
Register digits = dest.reg;
|
||||
#else
|
||||
Register digits = dest.high;
|
||||
#endif
|
||||
MOZ_ASSERT(digits != bigInt);
|
||||
|
||||
Label isInline, inlineDone;
|
||||
|
||||
branch32(Assembler::NonZero, Address(bigInt, BigInt::offsetOfLength()),
|
||||
Imm32(int32_t(BigInt::nonInlineDigitsLengthMask())),
|
||||
&isInline);
|
||||
|
||||
load64(Address(bigInt, BigInt::nonInlineDigitsLengthMask()), dest);
|
||||
jump(&inlineDone);
|
||||
|
||||
bind(&isInline);
|
||||
// Load the inline digits.
|
||||
computeEffectiveAddress(Address(bigInt, BigInt::offsetOfInlineDigits()),
|
||||
digits);
|
||||
|
||||
bind(&inlineDone);
|
||||
|
||||
#if JS_PUNBOX64
|
||||
// Load the first digit into the destination register.
|
||||
load64(Address(digits, 0), dest);
|
||||
#else
|
||||
// Load the first digit into the destination register's low value.
|
||||
load32(Address(digits, 0), dest.low);
|
||||
|
||||
// And conditionally load the second digit into the high value register.
|
||||
Label twoDigits, digitsDone;
|
||||
branch32(Assembler::GreaterThan, Address(bigInt, BigInt::offsetOfLength()),
|
||||
Imm32(1), &twoDigits);
|
||||
{
|
||||
move32(Imm32(0), dest.high);
|
||||
jump(&digitsDone);
|
||||
}
|
||||
{
|
||||
bind(&twoDigits);
|
||||
load32(Address(digits, sizeof(BigInt::Digit)), dest.high);
|
||||
}
|
||||
bind(&digitsDone);
|
||||
#endif
|
||||
|
||||
branchTest32(Assembler::Zero, Address(bigInt, BigInt::offsetOfFlags()),
|
||||
Imm32(BigInt::signBitMask()), &done);
|
||||
neg64(dest);
|
||||
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
static void
|
||||
BailoutReportOverRecursed(JSContext* cx)
|
||||
{
|
||||
|
||||
@@ -835,7 +835,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
inline void dec32(RegisterOrInt32Constant* key);
|
||||
|
||||
inline void neg32(Register reg) PER_SHARED_ARCH;
|
||||
inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64);
|
||||
inline void neg64(Register64 reg) PER_SHARED_ARCH;
|
||||
|
||||
inline void negateFloat(FloatRegister reg) PER_SHARED_ARCH;
|
||||
|
||||
@@ -1441,6 +1441,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
void loadStringChars(Register str, Register dest);
|
||||
void loadStringChar(Register str, Register index, Register output);
|
||||
|
||||
/**
|
||||
* Load the first [u]int64 value from |bigInt| into |dest|.
|
||||
*/
|
||||
void loadBigInt64(Register bigInt, Register64 dest);
|
||||
|
||||
void loadJSContext(Register dest) {
|
||||
movePtr(ImmPtr(GetJitContext()->runtime->getJSContext()), dest);
|
||||
}
|
||||
|
||||
@@ -3773,8 +3773,7 @@ MacroAssemblerARMCompat::testBigIntTruthy(bool truthy, const ValueOperand& value
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
|
||||
ma_dtr(IsLoad, bi, Imm32(BigInt::offsetOfLengthSignAndReservedBits()),
|
||||
scratch, scratch2);
|
||||
ma_dtr(IsLoad, bi, Imm32(BigInt::offsetOfDigitLength()), scratch, scratch2);
|
||||
as_cmp(scratch, Imm8(0));
|
||||
return truthy ? Assembler::NotEqual : Assembler::Equal;
|
||||
}
|
||||
|
||||
@@ -1077,11 +1077,21 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
store32(src.high, Address(address.base, address.offset + INT64HIGH_OFFSET));
|
||||
}
|
||||
|
||||
void store64(Register64 src, const BaseIndex& address) {
|
||||
store32(src.low, Address(address.base, address.offset + INT64LOW_OFFSET));
|
||||
store32(src.high, Address(address.base, address.offset + INT64HIGH_OFFSET));
|
||||
}
|
||||
|
||||
void store64(Imm64 imm, Address address) {
|
||||
store32(imm.low(), Address(address.base, address.offset + INT64LOW_OFFSET));
|
||||
store32(imm.hi(), Address(address.base, address.offset + INT64HIGH_OFFSET));
|
||||
}
|
||||
|
||||
void store64(Imm64 imm, const BaseIndex& address) {
|
||||
store32(imm.low(), Address(address.base, address.offset + INT64LOW_OFFSET));
|
||||
store32(imm.hi(), Address(address.base, address.offset + INT64HIGH_OFFSET));
|
||||
}
|
||||
|
||||
void storePtr(ImmWord imm, const Address& address);
|
||||
void storePtr(ImmWord imm, const BaseIndex& address);
|
||||
void storePtr(ImmPtr imm, const Address& address);
|
||||
|
||||
@@ -504,6 +504,12 @@ MacroAssembler::neg32(Register reg)
|
||||
Negs(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32)));
|
||||
}
|
||||
|
||||
void MacroAssembler::neg64(Register64 reg) { negPtr(reg.reg); }
|
||||
|
||||
void MacroAssembler::negPtr(Register reg) {
|
||||
Negs(ARMRegister(reg, 64), Operand(ARMRegister(reg, 64)));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::negateFloat(FloatRegister reg)
|
||||
{
|
||||
|
||||
@@ -907,6 +907,14 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
storePtr(src.reg, address);
|
||||
}
|
||||
|
||||
void store64(Register64 src, const BaseIndex& address) {
|
||||
storePtr(src.reg, address);
|
||||
}
|
||||
|
||||
void store64(Imm64 imm, const BaseIndex& address) {
|
||||
storePtr(ImmWord(imm.value), address);
|
||||
}
|
||||
|
||||
// StackPointer manipulation.
|
||||
template <typename T> void addToStackPtr(T t);
|
||||
template <typename T> void addStackPtrTo(T t);
|
||||
@@ -2302,3 +2310,4 @@ typedef MacroAssemblerCompat MacroAssemblerSpecific;
|
||||
} // namespace js
|
||||
|
||||
#endif // jit_arm64_MacroAssembler_arm64_h
|
||||
void store64(Register64 src, const BaseIndex& address) {
|
||||
@@ -972,7 +972,7 @@ void MacroAssembler::branchTestBigIntTruthy(bool b, const ValueOperand& value, L
|
||||
{
|
||||
Register bi = value.payloadReg();
|
||||
SecondScratchRegisterScope scratch2(*this);
|
||||
ma_lw(scratch2, Address(bi, BigInt::offsetOfLengthSignAndReservedBits()));
|
||||
ma_lw(scratch2, Address(bi, BigInt::offsetOfDigitLength()));
|
||||
ma_b(scratch2, Imm32(0), label, b ? NotEqual : Equal);
|
||||
}
|
||||
|
||||
|
||||
@@ -633,8 +633,8 @@ void MacroAssembler::branchTestBigIntTruthy(bool b, const ValueOperand& value, L
|
||||
{
|
||||
SecondScratchRegisterScope scratch2(*this);
|
||||
unboxBigInt(value, scratch2);
|
||||
loadPtr(Address(scratch2, BigInt::offsetOfLengthSignAndReservedBits()), scratch2);
|
||||
ma_b(scratch2, ImmWord(0), label, b ? NotEqual : Equal);
|
||||
load32(Address(scratch2, BigInt::offsetOfDigitLength()), scratch2);
|
||||
ma_b(scratch2, Imm32(0), label, b ? NotEqual : Equal);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -663,9 +663,15 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
void store64(Register64 src, Address address) {
|
||||
storePtr(src.reg, address);
|
||||
}
|
||||
void store64(Register64 src, const BaseIndex& address) {
|
||||
storePtr(src.reg, address);
|
||||
}
|
||||
void store64(Imm64 imm, Address address) {
|
||||
storePtr(ImmWord(imm.value), address);
|
||||
}
|
||||
void store64(Imm64 imm, const BaseIndex& address) {
|
||||
storePtr(ImmWord(imm.value), address);
|
||||
}
|
||||
|
||||
void splitTag(Register src, Register dest) {
|
||||
if (src != dest)
|
||||
@@ -920,8 +926,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
unboxBigInt(value, scratch);
|
||||
cmpPtr(Operand(scratch, BigInt::offsetOfLengthSignAndReservedBits()),
|
||||
ImmWord(0));
|
||||
cmp32(Operand(scratch, BigInt::offsetOfDigitLength()), Imm32(0));
|
||||
return truthy ? Assembler::NotEqual : Assembler::Equal;
|
||||
}
|
||||
|
||||
|
||||
@@ -810,8 +810,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
}
|
||||
Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
|
||||
Register bi = value.payloadReg();
|
||||
cmpPtr(Operand(bi, BigInt::offsetOfLengthSignAndReservedBits()),
|
||||
ImmWord(0));
|
||||
cmp32(Operand(bi, BigInt::offsetOfDigitLength()), Imm32(0));
|
||||
return truthy ? Assembler::NotEqual : Assembler::Equal;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,9 +123,9 @@ static inline unsigned DigitLeadingZeroes(BigInt::Digit x) {
|
||||
: mozilla::CountLeadingZeroes64(x);
|
||||
}
|
||||
|
||||
BigInt* BigInt::createUninitialized(ExclusiveContext* cx, size_t length,
|
||||
BigInt* BigInt::createUninitialized(ExclusiveContext* cx, size_t digitLength,
|
||||
bool isNegative) {
|
||||
if (length > MaxDigitLength) {
|
||||
if (digitLength > MaxDigitLength) {
|
||||
if (cx->isJSContext()) {
|
||||
JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr,
|
||||
JSMSG_BIGINT_TOO_LARGE);
|
||||
@@ -134,8 +134,8 @@ BigInt* BigInt::createUninitialized(ExclusiveContext* cx, size_t length,
|
||||
}
|
||||
|
||||
UniquePtr<Digit[], JS::FreePolicy> heapDigits;
|
||||
if (length > InlineDigitsLength) {
|
||||
heapDigits = cx->make_pod_array<Digit>(length);
|
||||
if (digitLength > InlineDigitsLength) {
|
||||
heapDigits = cx->make_pod_array<Digit>(digitLength);
|
||||
if (!heapDigits) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -148,9 +148,9 @@ BigInt* BigInt::createUninitialized(ExclusiveContext* cx, size_t length,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
x->lengthSignAndReservedBits_ =
|
||||
(length << LengthShift) | (isNegative ? SignBit : 0);
|
||||
MOZ_ASSERT(x->digitLength() == length);
|
||||
x->setLengthAndFlags(digitLength, isNegative ? SignBit : 0);
|
||||
|
||||
MOZ_ASSERT(x->digitLength() == digitLength);
|
||||
MOZ_ASSERT(x->isNegative() == isNegative);
|
||||
|
||||
if (heapDigits) {
|
||||
@@ -211,7 +211,7 @@ BigInt* BigInt::neg(ExclusiveContext* cx, HandleBigInt x) {
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
result->lengthSignAndReservedBits_ ^= SignBit;
|
||||
result->toggleFlagBit(SignBit);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1612,7 +1612,7 @@ BigInt* BigInt::createFromInt64(ExclusiveContext* cx, int64_t n) {
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
res->lengthSignAndReservedBits_ |= SignBit;
|
||||
res->setFlagBit(SignBit);
|
||||
}
|
||||
MOZ_ASSERT(res->isNegative() == (n < 0));
|
||||
|
||||
|
||||
+39
-16
@@ -39,18 +39,21 @@ bool XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi);
|
||||
|
||||
namespace JS {
|
||||
|
||||
class BigInt final : public js::gc::TenuredCell {
|
||||
class BigInt final
|
||||
: public js::gc::CellWithLengthAndFlags<js::gc::TenuredCell> {
|
||||
using Base = js::gc::CellWithLengthAndFlags<js::gc::TenuredCell>;
|
||||
|
||||
public:
|
||||
using Digit = uintptr_t;
|
||||
|
||||
private:
|
||||
// The low js::gc::Cell::ReservedBits are reserved.
|
||||
static constexpr uintptr_t SignBit = JS_BIT(js_gc_Cell_ReservedBits);
|
||||
static constexpr uintptr_t LengthShift = js_gc_Cell_ReservedBits + 1;
|
||||
// The low NumFlagBitsReservedForGC flag bits are reserved.
|
||||
static constexpr uintptr_t SignBit = JS_BIT(Base::NumFlagBitsReservedForGC);
|
||||
static constexpr size_t InlineDigitsLength =
|
||||
(js_gc_MinCellSize - sizeof(uintptr_t)) / sizeof(Digit);
|
||||
(js_gc_MinCellSize - sizeof(Base)) / sizeof(Digit);
|
||||
|
||||
uintptr_t lengthSignAndReservedBits_;
|
||||
// Note: 32-bit length and flags fields are inherited from
|
||||
// CellWithLengthAndFlags.
|
||||
|
||||
// The digit storage starts with the least significant digit (little-endian
|
||||
// digit order). Byte order within a digit is of course native endian.
|
||||
@@ -62,8 +65,11 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
public:
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
|
||||
|
||||
size_t digitLength() const {
|
||||
return lengthSignAndReservedBits_ >> LengthShift;
|
||||
size_t digitLength() const { return lengthField(); }
|
||||
|
||||
// Offset for direct access from JIT code.
|
||||
static constexpr size_t offsetOfDigitLength() {
|
||||
return Base::offsetOfLength();
|
||||
}
|
||||
|
||||
bool hasInlineDigits() const { return digitLength() <= InlineDigitsLength; }
|
||||
@@ -78,12 +84,7 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
void setDigit(size_t idx, Digit digit) { digits()[idx] = digit; }
|
||||
|
||||
bool isZero() const { return digitLength() == 0; }
|
||||
bool isNegative() const { return lengthSignAndReservedBits_ & SignBit; }
|
||||
|
||||
// Offset for direct access from JIT code.
|
||||
static constexpr size_t offsetOfLengthSignAndReservedBits() {
|
||||
return offsetof(BigInt, lengthSignAndReservedBits_);
|
||||
}
|
||||
bool isNegative() const { return flagsField() & SignBit; }
|
||||
|
||||
void initializeDigitsToZero();
|
||||
|
||||
@@ -92,7 +93,7 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
js::HashNumber hash();
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
static BigInt* createUninitialized(js::ExclusiveContext* cx, size_t length,
|
||||
static BigInt* createUninitialized(js::ExclusiveContext* cx, size_t digitLength,
|
||||
bool isNegative);
|
||||
static BigInt* createFromDouble(js::ExclusiveContext* cx, double d);
|
||||
static BigInt* createFromUint64(js::ExclusiveContext* cx, uint64_t n);
|
||||
@@ -354,7 +355,29 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
BigInt() = delete;
|
||||
BigInt(const BigInt& other) = delete;
|
||||
void operator=(const BigInt& other) = delete;
|
||||
};
|
||||
|
||||
private:
|
||||
// To help avoid writing Spectre-unsafe code, we only allow MacroAssembler to
|
||||
// call the methods below.
|
||||
friend class js::jit::MacroAssembler;
|
||||
|
||||
// Make offset accessors accessible to the MacroAssembler.
|
||||
using Base::offsetOfFlags;
|
||||
using Base::offsetOfLength;
|
||||
|
||||
static size_t offsetOfInlineDigits() {
|
||||
return offsetof(BigInt, inlineDigits_);
|
||||
}
|
||||
|
||||
static size_t offsetOfHeapDigits() { return offsetof(BigInt, heapDigits_); }
|
||||
|
||||
static constexpr size_t nonInlineDigitsLengthMask() {
|
||||
static_assert(mozilla::IsPowerOfTwo(InlineDigitsLength),
|
||||
"inline digits length is a power of two");
|
||||
return ~(InlineDigitsLength - 1) & ~InlineDigitsLength;
|
||||
}
|
||||
|
||||
static constexpr size_t signBitMask() { return SignBit; }};
|
||||
|
||||
static_assert(
|
||||
sizeof(BigInt) >= js_gc_MinCellSize,
|
||||
|
||||
Reference in new issue
Block a user