mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1502797 - Reimplement BigInt using V8/JSC code instead of GMP r=jwalden
Differential Revision: https://phabricator.services.mozilla.com/D10046 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
9e9978c28d
commit
887bf9200b
@ -45,25 +45,6 @@ extern JS_PUBLIC_API bool JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn,
|
||||
JS_ICUReallocFn reallocFn,
|
||||
JS_ICUFreeFn freeFn);
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
namespace JS {
|
||||
|
||||
// These types are documented as allocate_function, reallocate_function,
|
||||
// and free_function in the Info node `(gmp)Custom Allocation`.
|
||||
using GMPAllocFn = void* (*)(size_t allocSize);
|
||||
using GMPReallocFn = void* (*)(void* p, size_t oldSize, size_t newSize);
|
||||
using GMPFreeFn = void (*)(void* p, size_t size);
|
||||
|
||||
// This function can be used to track memory used by GMP. If it is
|
||||
// called, it *must* be called before JS_Init so that same functions are
|
||||
// used for all allocations.
|
||||
extern JS_PUBLIC_API void SetGMPMemoryFunctions(GMPAllocFn allocFn,
|
||||
GMPReallocFn reallocFn,
|
||||
GMPFreeFn freeFn);
|
||||
|
||||
}; // namespace JS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize SpiderMonkey, returning true only if initialization succeeded.
|
||||
* Once this method has succeeded, it is safe to call JS_NewContext and other
|
||||
|
@ -164,7 +164,7 @@ JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) {
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (v.isBigInt()) {
|
||||
return v.toBigInt()->toBoolean();
|
||||
return !v.toBigInt()->isZero();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -487,8 +487,8 @@ static Truthiness Boolish(ParseNode* pn) {
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigIntExpr:
|
||||
return (pn->as<BigIntLiteral>().box()->value()->toBoolean()) ? Truthy
|
||||
: Falsy;
|
||||
return (pn->as<BigIntLiteral>().box()->value()->isZero()) ? Falsy
|
||||
: Truthy;
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::StringExpr:
|
||||
|
@ -9022,7 +9022,7 @@ BigIntLiteral* Parser<FullParseHandler, Unit>::newBigInt() {
|
||||
const auto& chars = tokenStream.getCharBuffer();
|
||||
mozilla::Range<const char16_t> source(chars.begin(), chars.length());
|
||||
|
||||
BigInt* b = js::StringToBigInt(context, source);
|
||||
BigInt* b = js::ParseBigIntLiteral(context, source);
|
||||
if (!b) {
|
||||
return null();
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ FRAGMENT(jsval, simple) {
|
||||
RootedValue friendly_string(cx, StringValue(hello));
|
||||
RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
|
||||
#ifdef ENABLE_BIGINT
|
||||
RootedValue bi(cx, BigIntValue(BigInt::create(cx)));
|
||||
RootedValue bi(cx, BigIntValue(BigInt::zero(cx)));
|
||||
#endif
|
||||
|
||||
RootedValue global(cx);
|
||||
|
@ -169,7 +169,8 @@ bool js::ValueToStringBufferSlow(JSContext* cx, const Value& arg,
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (v.isBigInt()) {
|
||||
JSLinearString* str = BigInt::toString(cx, v.toBigInt(), 10);
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
JSLinearString* str = BigInt::toString(cx, i, 10);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,7 @@
|
||||
#define vm_BigIntType_h
|
||||
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
|
||||
#include <gmp.h>
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/GC.h"
|
||||
@ -32,10 +30,6 @@ class BigInt;
|
||||
|
||||
namespace js {
|
||||
|
||||
template <typename CharT>
|
||||
static bool StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
|
||||
uint8_t radix, Handle<JS::BigInt*> res);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi);
|
||||
|
||||
@ -44,54 +38,61 @@ XDRResult XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi);
|
||||
namespace JS {
|
||||
|
||||
class BigInt final : public js::gc::TenuredCell {
|
||||
// StringToBigIntImpl modifies the num_ field of the res argument.
|
||||
template <typename CharT>
|
||||
friend bool js::StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
|
||||
uint8_t radix, Handle<BigInt*> res);
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::XDRBigInt(js::XDRState<mode>* xdr,
|
||||
MutableHandle<BigInt*> bi);
|
||||
|
||||
protected:
|
||||
// Reserved word for Cell GC invariants. This also ensures minimum
|
||||
// structure size.
|
||||
uintptr_t reserved_;
|
||||
public:
|
||||
using Digit = uintptr_t;
|
||||
|
||||
private:
|
||||
mpz_t num_;
|
||||
// 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;
|
||||
static constexpr size_t InlineDigitsLength =
|
||||
(js::gc::MinCellSize - sizeof(uintptr_t)) / sizeof(Digit);
|
||||
|
||||
protected:
|
||||
BigInt() : reserved_(0) {}
|
||||
uintptr_t lengthSignAndReservedBits_;
|
||||
|
||||
// The digit storage starts with the least significant digit (little-endian
|
||||
// digit order). Byte order within a digit is of course native endian.
|
||||
union {
|
||||
Digit* heapDigits_;
|
||||
Digit inlineDigits_[InlineDigitsLength];
|
||||
};
|
||||
|
||||
public:
|
||||
// Allocate and initialize a BigInt value
|
||||
static BigInt* create(JSContext* cx);
|
||||
|
||||
static BigInt* createFromDouble(JSContext* cx, double d);
|
||||
|
||||
static BigInt* createFromBoolean(JSContext* cx, bool b);
|
||||
|
||||
// Read a BigInt value from a little-endian byte array.
|
||||
static BigInt* createFromBytes(JSContext* cx, int sign, void* bytes,
|
||||
size_t nbytes);
|
||||
|
||||
static BigInt* createFromInt64(JSContext* cx, int64_t n);
|
||||
static BigInt* createFromUint64(JSContext* cx, uint64_t n);
|
||||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
|
||||
|
||||
size_t digitLength() const {
|
||||
return lengthSignAndReservedBits_ >> LengthShift;
|
||||
}
|
||||
|
||||
bool hasInlineDigits() const { return digitLength() <= InlineDigitsLength; }
|
||||
bool hasHeapDigits() const { return !hasInlineDigits(); }
|
||||
|
||||
using Digits = mozilla::Span<Digit>;
|
||||
Digits digits() {
|
||||
return Digits(hasInlineDigits() ? inlineDigits_ : heapDigits_,
|
||||
digitLength());
|
||||
}
|
||||
Digit digit(size_t idx) { return digits()[idx]; }
|
||||
void setDigit(size_t idx, Digit digit) { digits()[idx] = digit; }
|
||||
|
||||
bool isZero() const { return digitLength() == 0; }
|
||||
bool isNegative() const { return lengthSignAndReservedBits_ & SignBit; }
|
||||
|
||||
void initializeDigitsToZero();
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
void finalize(js::FreeOp* fop);
|
||||
|
||||
js::HashNumber hash();
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
bool toBoolean();
|
||||
int8_t sign();
|
||||
|
||||
static void init();
|
||||
static BigInt* createUninitialized(JSContext* cx, size_t length,
|
||||
bool isNegative);
|
||||
static BigInt* createFromDouble(JSContext* cx, double d);
|
||||
static BigInt* createFromUint64(JSContext* cx, uint64_t n);
|
||||
static BigInt* createFromInt64(JSContext* cx, int64_t n);
|
||||
// FIXME: Cache these values.
|
||||
static BigInt* zero(JSContext* cx);
|
||||
static BigInt* one(JSContext* cx);
|
||||
|
||||
static BigInt* copy(JSContext* cx, Handle<BigInt*> x);
|
||||
static BigInt* add(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
@ -116,7 +117,7 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
|
||||
// Type-checking versions of arithmetic operations. These methods
|
||||
// must be called with at least one BigInt operand. Binary
|
||||
// operations with throw a TypeError if one of the operands is not a
|
||||
// operations will throw a TypeError if one of the operands is not a
|
||||
// BigInt value.
|
||||
static bool add(JSContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
@ -146,15 +147,25 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
MutableHandle<Value> res);
|
||||
|
||||
static double numberValue(BigInt* x);
|
||||
static JSLinearString* toString(JSContext* cx, BigInt* x, uint8_t radix);
|
||||
|
||||
static JSLinearString* toString(JSContext* cx, Handle<BigInt*> x,
|
||||
uint8_t radix);
|
||||
template <typename CharT>
|
||||
static BigInt* parseLiteral(JSContext* cx,
|
||||
const mozilla::Range<const CharT> chars,
|
||||
bool* haveParseError);
|
||||
template <typename CharT>
|
||||
static BigInt* parseLiteralDigits(JSContext* cx,
|
||||
const mozilla::Range<const CharT> chars,
|
||||
unsigned radix, bool isNegative,
|
||||
bool* haveParseError);
|
||||
|
||||
static int8_t compare(BigInt* lhs, BigInt* rhs);
|
||||
static bool equal(BigInt* lhs, BigInt* rhs);
|
||||
static bool equal(BigInt* lhs, double rhs);
|
||||
static JS::Result<bool> looselyEqual(JSContext* cx, Handle<BigInt*> lhs,
|
||||
HandleValue rhs);
|
||||
|
||||
static bool lessThan(BigInt* x, BigInt* y);
|
||||
|
||||
// These methods return Nothing when the non-BigInt operand is NaN
|
||||
// or a string that can't be interpreted as a BigInt.
|
||||
static mozilla::Maybe<bool> lessThan(BigInt* lhs, double rhs);
|
||||
@ -166,34 +177,191 @@ class BigInt final : public js::gc::TenuredCell {
|
||||
static bool lessThan(JSContext* cx, HandleValue lhs, HandleValue rhs,
|
||||
mozilla::Maybe<bool>& res);
|
||||
|
||||
// Return the length in bytes of the representation used by
|
||||
// writeBytes.
|
||||
static size_t byteLength(BigInt* x);
|
||||
private:
|
||||
static constexpr size_t DigitBits = sizeof(Digit) * CHAR_BIT;
|
||||
static constexpr size_t HalfDigitBits = DigitBits / 2;
|
||||
static constexpr Digit HalfDigitMask = (1ull << HalfDigitBits) - 1;
|
||||
|
||||
// Write a little-endian representation of a BigInt's absolute value
|
||||
// to a byte array.
|
||||
static void writeBytes(BigInt* x, mozilla::RangedPtr<uint8_t> buffer);
|
||||
static_assert(DigitBits == 32 || DigitBits == 64,
|
||||
"Unexpected BigInt Digit size");
|
||||
|
||||
// The maximum number of digits that the current implementation supports
|
||||
// would be 0x7fffffff / DigitBits. However, we use a lower limit for now,
|
||||
// because raising it later is easier than lowering it. Support up to 1
|
||||
// million bits.
|
||||
static constexpr size_t MaxBitLength = 1024 * 1024;
|
||||
static constexpr size_t MaxDigitLength = MaxBitLength / DigitBits;
|
||||
|
||||
// BigInts can be serialized to strings of radix between 2 and 36. For a
|
||||
// given bigint, radix 2 will take the most characters (one per bit).
|
||||
// Ensure that the max bigint size is small enough so that we can fit the
|
||||
// corresponding character count into a size_t, with space for a possible
|
||||
// sign prefix.
|
||||
static_assert(MaxBitLength <= std::numeric_limits<size_t>::max() - 1,
|
||||
"BigInt max length must be small enough to be serialized as a "
|
||||
"binary string");
|
||||
|
||||
static size_t calculateMaximumCharactersRequired(HandleBigInt x,
|
||||
unsigned radix);
|
||||
static MOZ_MUST_USE bool calculateMaximumDigitsRequired(JSContext* cx,
|
||||
uint8_t radix,
|
||||
size_t charCount,
|
||||
size_t* result);
|
||||
|
||||
static bool absoluteDivWithDigitDivisor(
|
||||
JSContext* cx, Handle<BigInt*> x, Digit divisor,
|
||||
const mozilla::Maybe<MutableHandle<BigInt*>>& quotient, Digit* remainder,
|
||||
bool quotientNegative);
|
||||
static void internalMultiplyAdd(BigInt* source, Digit factor, Digit summand,
|
||||
unsigned, BigInt* result);
|
||||
static void multiplyAccumulate(BigInt* multiplicand, Digit multiplier,
|
||||
BigInt* accumulator,
|
||||
unsigned accumulatorIndex);
|
||||
static bool absoluteDivWithBigIntDivisor(
|
||||
JSContext* cx, Handle<BigInt*> dividend, Handle<BigInt*> divisor,
|
||||
const mozilla::Maybe<MutableHandle<BigInt*>>& quotient,
|
||||
const mozilla::Maybe<MutableHandle<BigInt*>>& remainder,
|
||||
bool quotientNegative);
|
||||
|
||||
enum class LeftShiftMode { SameSizeResult, AlwaysAddOneDigit };
|
||||
|
||||
static BigInt* absoluteLeftShiftAlwaysCopy(JSContext* cx, Handle<BigInt*> x,
|
||||
unsigned shift, LeftShiftMode);
|
||||
static bool productGreaterThan(Digit factor1, Digit factor2, Digit high,
|
||||
Digit low);
|
||||
static BigInt* lshByAbsolute(JSContext* cx, HandleBigInt x, HandleBigInt y);
|
||||
static BigInt* rshByAbsolute(JSContext* cx, HandleBigInt x, HandleBigInt y);
|
||||
static BigInt* rshByMaximum(JSContext* cx, bool isNegative);
|
||||
static BigInt* truncateAndSubFromPowerOfTwo(JSContext* cx, HandleBigInt x,
|
||||
uint64_t bits,
|
||||
bool resultNegative);
|
||||
|
||||
Digit absoluteInplaceAdd(BigInt* summand, unsigned startIndex);
|
||||
Digit absoluteInplaceSub(BigInt* subtrahend, unsigned startIndex);
|
||||
void inplaceRightShiftLowZeroBits(unsigned shift);
|
||||
void inplaceMultiplyAdd(Digit multiplier, Digit part);
|
||||
|
||||
// The result of an SymmetricTrim bitwise op has as many digits as the
|
||||
// smaller operand. A SymmetricFill bitwise op result has as many digits as
|
||||
// the larger operand, with high digits (if any) copied from the larger
|
||||
// operand. AsymmetricFill is like SymmetricFill, except the result has as
|
||||
// many digits as the first operand; this kind is used for the and-not
|
||||
// operation.
|
||||
enum class BitwiseOpKind { SymmetricTrim, SymmetricFill, AsymmetricFill };
|
||||
|
||||
template <BitwiseOpKind kind, typename BitwiseOp>
|
||||
static BigInt* absoluteBitwiseOp(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y, BitwiseOp&& op);
|
||||
|
||||
// Return `|x| & |y|`.
|
||||
static BigInt* absoluteAnd(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| | |y|`.
|
||||
static BigInt* absoluteOr(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| & ~|y|`.
|
||||
static BigInt* absoluteAndNot(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| ^ |y|`.
|
||||
static BigInt* absoluteXor(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `(|x| + 1) * (resultNegative ? -1 : +1)`.
|
||||
static BigInt* absoluteAddOne(JSContext* cx, Handle<BigInt*> x,
|
||||
bool resultNegative);
|
||||
|
||||
// Return `(|x| - 1) * (resultNegative ? -1 : +1)`, with the precondition that
|
||||
// |x| != 0.
|
||||
static BigInt* absoluteSubOne(JSContext* cx, Handle<BigInt*> x,
|
||||
unsigned resultLength);
|
||||
|
||||
// Return `a + b`, incrementing `*carry` if the addition overflows.
|
||||
static inline Digit digitAdd(Digit a, Digit b, Digit* carry) {
|
||||
Digit result = a + b;
|
||||
*carry += static_cast<Digit>(result < a);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return `left - right`, incrementing `*borrow` if the addition overflows.
|
||||
static inline Digit digitSub(Digit left, Digit right, Digit* borrow) {
|
||||
Digit result = left - right;
|
||||
*borrow += static_cast<Digit>(result > left);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compute `a * b`, returning the low half of the result and putting the
|
||||
// high half in `*high`.
|
||||
static Digit digitMul(Digit a, Digit b, Digit* high);
|
||||
|
||||
// Divide `(high << DigitBits) + low` by `divisor`, returning the quotient
|
||||
// and storing the remainder in `*remainder`, with the precondition that
|
||||
// `high < divisor` so that the result fits in a Digit.
|
||||
static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit* remainder);
|
||||
|
||||
// Return `(|x| + |y|) * (resultNegative ? -1 : +1)`.
|
||||
static BigInt* absoluteAdd(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y, bool resultNegative);
|
||||
|
||||
// Return `(|x| - |y|) * (resultNegative ? -1 : +1)`, with the precondition
|
||||
// that |x| >= |y|.
|
||||
static BigInt* absoluteSub(JSContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y, bool resultNegative);
|
||||
|
||||
// If `|x| < |y|` return -1; if `|x| == |y|` return 0; otherwise return 1.
|
||||
static int8_t absoluteCompare(BigInt* lhs, BigInt* rhs);
|
||||
|
||||
static int8_t compare(BigInt* lhs, double rhs);
|
||||
|
||||
static bool equal(BigInt* lhs, double rhs);
|
||||
|
||||
static JSLinearString* toStringBasePowerOfTwo(JSContext* cx, Handle<BigInt*>,
|
||||
unsigned radix);
|
||||
static JSLinearString* toStringGeneric(JSContext* cx, Handle<BigInt*>,
|
||||
unsigned radix);
|
||||
|
||||
static BigInt* trimHighZeroDigits(JSContext* cx, Handle<BigInt*> x);
|
||||
static BigInt* destructivelyTrimHighZeroDigits(JSContext* cx,
|
||||
Handle<BigInt*> x);
|
||||
|
||||
friend struct JSStructuredCloneReader;
|
||||
friend struct JSStructuredCloneWriter;
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::XDRBigInt(js::XDRState<mode>* xdr,
|
||||
MutableHandle<BigInt*> bi);
|
||||
|
||||
BigInt() = delete;
|
||||
BigInt(const BigInt& other) = delete;
|
||||
void operator=(const BigInt& other) = delete;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
sizeof(BigInt) >= js::gc::MinCellSize,
|
||||
"sizeof(BigInt) must be greater than the minimum allocation size");
|
||||
|
||||
static_assert(
|
||||
sizeof(BigInt) == js::gc::MinCellSize,
|
||||
"sizeof(BigInt) intended to be the same as the minimum allocation size");
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
extern JSAtom* BigIntToAtom(JSContext* cx, JS::BigInt* bi);
|
||||
extern JSAtom* BigIntToAtom(JSContext* cx, JS::HandleBigInt bi);
|
||||
|
||||
extern JS::BigInt* NumberToBigInt(JSContext* cx, double d);
|
||||
|
||||
// Convert a string to a BigInt, returning nullptr if parsing fails.
|
||||
// Parse a BigInt from a string, using the method specified for StringToBigInt.
|
||||
// Used by the BigInt constructor among other places.
|
||||
extern JS::Result<JS::BigInt*, JS::OOM&> StringToBigInt(
|
||||
JSContext* cx, JS::Handle<JSString*> str, uint8_t radix);
|
||||
JSContext* cx, JS::Handle<JSString*> str);
|
||||
|
||||
// Same.
|
||||
extern JS::BigInt* StringToBigInt(JSContext* cx,
|
||||
const mozilla::Range<const char16_t>& chars);
|
||||
// Parse a BigInt from an already-validated numeric literal. Used by the
|
||||
// parser. Can only fail in out-of-memory situations.
|
||||
extern JS::BigInt* ParseBigIntLiteral(
|
||||
JSContext* cx, const mozilla::Range<const char16_t>& chars);
|
||||
|
||||
extern JS::BigInt* ToBigInt(JSContext* cx, JS::Handle<JS::Value> v);
|
||||
|
||||
|
@ -80,7 +80,7 @@ JS_PUBLIC_API const char* JS::detail::InitWithFailureDiagnostic(
|
||||
|
||||
MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
|
||||
"must call JS_Init once before any JSAPI operation except "
|
||||
"JS_SetICUMemoryFunctions or JS::SetGMPMemoryFunctions");
|
||||
"JS_SetICUMemoryFunctions");
|
||||
MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
|
||||
"how do we have live runtimes before JS_Init?");
|
||||
|
||||
@ -146,10 +146,6 @@ JS_PUBLIC_API const char* JS::detail::InitWithFailureDiagnostic(
|
||||
RETURN_IF_FAIL(js::jit::SimulatorProcess::initialize());
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
JS::BigInt::init();
|
||||
#endif
|
||||
|
||||
libraryInitState = InitState::Running;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1081,7 +1081,8 @@ static JSAtom* ToAtomSlow(
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (v.isBigInt()) {
|
||||
JSAtom* atom = BigIntToAtom(cx, v.toBigInt());
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
JSAtom* atom = BigIntToAtom(cx, i);
|
||||
if (!allowGC && !atom) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
|
@ -2169,7 +2169,8 @@ JSString* js::ToStringSlow(
|
||||
if (!allowGC) {
|
||||
return nullptr;
|
||||
}
|
||||
str = BigInt::toString(cx, v.toBigInt(), 10);
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
str = BigInt::toString(cx, i, 10);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
|
@ -310,7 +310,7 @@ struct SCOutput {
|
||||
MOZ_MUST_USE bool writeChars(const char16_t* p, size_t nchars);
|
||||
|
||||
template <class T>
|
||||
MOZ_MUST_USE bool writeArray(const T* p, size_t nbytes);
|
||||
MOZ_MUST_USE bool writeArray(const T* p, size_t nelems);
|
||||
|
||||
void setCallbacks(const JSStructuredCloneCallbacks* callbacks, void* closure,
|
||||
OwnTransferablePolicy policy) {
|
||||
@ -1143,24 +1143,18 @@ bool JSStructuredCloneWriter::writeString(uint32_t tag, JSString* str) {
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool JSStructuredCloneWriter::writeBigInt(uint32_t tag, BigInt* bi) {
|
||||
bool signBit = bi->sign() < 1;
|
||||
size_t length = BigInt::byteLength(bi);
|
||||
bool signBit = bi->isNegative();
|
||||
size_t length = bi->digitLength();
|
||||
// The length must fit in 31 bits to leave room for a sign bit.
|
||||
if (length > size_t(INT32_MAX)) {
|
||||
return false;
|
||||
}
|
||||
uint32_t lengthAndSign = length | (static_cast<uint32_t>(signBit) << 31);
|
||||
|
||||
js::UniquePtr<uint8_t> buf(js_pod_malloc<uint8_t>(length));
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BigInt::writeBytes(bi, RangedPtr<uint8_t>(buf.get(), length));
|
||||
if (!out.writePair(tag, lengthAndSign)) {
|
||||
return false;
|
||||
}
|
||||
return out.writeBytes(buf.get(), length);
|
||||
return out.writeArray(bi->digits().data(), length);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2070,22 +2064,19 @@ JSString* JSStructuredCloneReader::readString(uint32_t data) {
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigInt* JSStructuredCloneReader::readBigInt(uint32_t data) {
|
||||
size_t nbytes = data & JS_BITMASK(31);
|
||||
size_t length = data & JS_BITMASK(31);
|
||||
bool isNegative = data & (1 << 31);
|
||||
|
||||
if (nbytes == 0) {
|
||||
return BigInt::create(context());
|
||||
if (length == 0) {
|
||||
return BigInt::zero(context());
|
||||
}
|
||||
|
||||
UniquePtr<uint8_t> buf(js_pod_malloc<uint8_t>(nbytes));
|
||||
if (!buf) {
|
||||
BigInt* result = BigInt::createUninitialized(context(), length, isNegative);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!in.readBytes(buf.get(), nbytes)) {
|
||||
if (!in.readArray(result->digits().data(), length)) {
|
||||
return nullptr;
|
||||
}
|
||||
return BigInt::createFromBytes(context(), isNegative ? -1 : 1, buf.get(),
|
||||
nbytes);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -385,40 +385,6 @@ NS_IMPL_ISUPPORTS(OggReporter, nsIMemoryReporter)
|
||||
CountingAllocatorBase<OggReporter>::AmountType
|
||||
CountingAllocatorBase<OggReporter>::sAmount(0);
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
class GMPReporter final : public nsIMemoryReporter,
|
||||
public CountingAllocatorBase<GMPReporter> {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
static void* Alloc(size_t size) { return CountingMalloc(size); }
|
||||
|
||||
static void* Realloc(void* ptr, size_t oldSize, size_t newSize) {
|
||||
return CountingRealloc(ptr, newSize);
|
||||
}
|
||||
|
||||
static void Free(void* ptr, size_t size) { return CountingFree(ptr); }
|
||||
|
||||
private:
|
||||
NS_IMETHOD
|
||||
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
|
||||
bool aAnonymize) override {
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/gmp", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
|
||||
"Memory allocated through libgmp for BigInt arithmetic.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
~GMPReporter() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GMPReporter, nsIMemoryReporter)
|
||||
|
||||
/* static */ template <>
|
||||
Atomic<size_t> CountingAllocatorBase<GMPReporter>::sAmount(0);
|
||||
#endif // ENABLE_BIGINT
|
||||
|
||||
static bool sInitializedJS = false;
|
||||
|
||||
// Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser
|
||||
@ -611,11 +577,6 @@ NS_InitXPCOM2(nsIServiceManager** aResult, nsIFile* aBinDirectory,
|
||||
OggReporter::CountingMalloc, OggReporter::CountingCalloc,
|
||||
OggReporter::CountingRealloc, OggReporter::CountingFree);
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
// And for libgmp.
|
||||
mozilla::SetGMPMemoryFunctions();
|
||||
#endif
|
||||
|
||||
// Initialize the JS engine.
|
||||
const char* jsInitFailureReason = JS_InitWithFailureDiagnostic();
|
||||
if (jsInitFailureReason) {
|
||||
@ -758,17 +719,6 @@ void SetICUMemoryFunctions() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
void SetGMPMemoryFunctions() {
|
||||
static bool sGMPReporterInitialized = false;
|
||||
if (!sGMPReporterInitialized) {
|
||||
JS::SetGMPMemoryFunctions(GMPReporter::Alloc, GMPReporter::Realloc,
|
||||
GMPReporter::Free);
|
||||
sGMPReporterInitialized = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) {
|
||||
// Make sure the hang monitor is enabled for shutdown.
|
||||
BackgroundHangMonitor().NotifyActivity();
|
||||
|
@ -40,10 +40,6 @@ nsresult ShutdownXPCOM(nsIServiceManager* aServMgr);
|
||||
|
||||
void SetICUMemoryFunctions();
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
void SetGMPMemoryFunctions();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++ namespaced version of NS_LogTerm.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user