mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 14:54:25 +00:00
Issue #1240 - Part 3c - Fast-forward to the V8 version of BigIntType. Disabling some sections temporarily since the dependencies are not there yet. Based on the following: https://bugzilla.mozilla.org/show_bug.cgi?id=1502797 https://bugzilla.mozilla.org/show_bug.cgi?id=1471134 https://bugzilla.mozilla.org/show_bug.cgi?id=1441098 Part 3 & 4 Add structured clone support for BigInt and Enable BigInt wrapping from DOM bindings. https://bugzilla.mozilla.org/show_bug.cgi?id=1522738
This commit is contained in:
@@ -1037,11 +1037,18 @@ MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
|
||||
return MaybeWrapStringValue(cx, rval);
|
||||
}
|
||||
|
||||
if (!rval.isObject()) {
|
||||
return true;
|
||||
if (rval.isObject()) {
|
||||
return MaybeWrapObjectValue(cx, rval);
|
||||
}
|
||||
|
||||
return MaybeWrapObjectValue(cx, rval);
|
||||
// This could be optimized by checking the zone first, similar to
|
||||
// the way strings are handled. At present, this is used primarily
|
||||
// for structured cloning, so avoiding the overhead of JS_WrapValue
|
||||
// calls is less important than for other types.
|
||||
if (rval.isBigInt()) {
|
||||
return JS_WrapValue(cx, rval);
|
||||
}
|
||||
MOZ_ASSERT(rval.isSymbol());
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace binding_detail {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@@ -19,7 +19,7 @@ FRAGMENT(jsval, simple) {
|
||||
RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!"));
|
||||
RootedValue friendly_string(cx, StringValue(hello));
|
||||
RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
|
||||
RootedValue bi(cx, BigIntValue(BigInt::create(cx)));
|
||||
RootedValue bi(cx, BigIntValue(BigInt::zero(cx)));
|
||||
|
||||
RootedValue global(cx);
|
||||
global.setObject(*CurrentGlobalOrNull(cx));
|
||||
|
||||
@@ -623,6 +623,7 @@ MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyn
|
||||
// BigInt
|
||||
MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
|
||||
MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
|
||||
MSG_DEF(JSMSG_BIGINT_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate")
|
||||
MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
|
||||
MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
|
||||
MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
|
||||
|
||||
+2
-1
@@ -487,7 +487,8 @@ ToAtomSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::HandleTyp
|
||||
return nullptr;
|
||||
}
|
||||
if (v.isBigInt()) {
|
||||
JSAtom* atom = BigIntToAtom(cx, v.toBigInt());
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
JSAtom* atom = BigIntToAtom(cx, i);
|
||||
if (!allowGC && !atom)
|
||||
cx->recoverFromOutOfMemory();
|
||||
return atom;
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ js::ToBooleanSlow(HandleValue v)
|
||||
if (v.isString())
|
||||
return v.toString()->length() != 0;
|
||||
if (v.isBigInt())
|
||||
return v.toBigInt()->toBoolean();
|
||||
return !v.toBigInt()->isZero();
|
||||
|
||||
MOZ_ASSERT(v.isObject());
|
||||
return !EmulatesUndefined(&v.toObject());
|
||||
|
||||
+2
-1
@@ -3737,7 +3737,8 @@ js::ToStringSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::Han
|
||||
} else if (v.isBigInt()) {
|
||||
if (!allowGC)
|
||||
return nullptr;
|
||||
str = BigInt::toString(cx, v.toBigInt(), 10);
|
||||
RootedBigInt i(cx, v.toBigInt());
|
||||
str = BigInt::toString(cx, i, 10);
|
||||
} else {
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
str = cx->names().undefined;
|
||||
|
||||
+3147
-94
File diff suppressed because it is too large
Load Diff
+354
-42
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@@ -6,62 +6,374 @@
|
||||
#ifndef vm_BigIntType_h
|
||||
#define vm_BigIntType_h
|
||||
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Heap.h"
|
||||
#include "js/GCHashTable.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TraceKind.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/String.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
// Handle future js::gc::Cell::ReservedBits, we have no reserved bits...
|
||||
#define js_gc_Cell_ReservedBits 0
|
||||
// Handle future js::gc::MinCellSize, 16 bytes, twice our js:gc:CellSize
|
||||
#define js_gc_MinCellSize (js::gc::CellSize*2)
|
||||
|
||||
namespace JS {
|
||||
|
||||
class BigInt final : public js::gc::TenuredCell
|
||||
{
|
||||
private:
|
||||
// The minimum allocation size is currently 16 bytes (see
|
||||
// SortedArenaList in gc/ArenaList.h).
|
||||
uint8_t unused_[16 + (16 % js::gc::CellSize)];
|
||||
#if 0 // Future XDR support
|
||||
class BigInt;
|
||||
|
||||
public:
|
||||
// Allocate and initialize a BigInt value
|
||||
static BigInt* create(js::ExclusiveContext* cx);
|
||||
|
||||
static BigInt* create(js::ExclusiveContext* cx, double d);
|
||||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
void finalize(js::FreeOp* fop);
|
||||
|
||||
js::HashNumber hash();
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
bool toBoolean();
|
||||
|
||||
static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
|
||||
static JSLinearString* toString(js::ExclusiveContext* cx, BigInt* x, uint8_t radix);
|
||||
|
||||
};
|
||||
|
||||
static_assert(sizeof(BigInt) >= js::gc::CellSize,
|
||||
"sizeof(BigInt) must be greater than the minimum allocation size");
|
||||
|
||||
} // namespace JS
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
extern JSAtom*
|
||||
BigIntToAtom(ExclusiveContext* cx, JS::BigInt* bi);
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi);
|
||||
|
||||
extern JS::BigInt*
|
||||
NumberToBigInt(ExclusiveContext* cx, double d);
|
||||
} // namespace js
|
||||
|
||||
extern JS::BigInt*
|
||||
ToBigInt(ExclusiveContext* cx, JS::Handle<JS::Value> v);
|
||||
} // namespace js
|
||||
namespace JS {
|
||||
#endif
|
||||
|
||||
class BigInt final : public 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;
|
||||
static constexpr size_t InlineDigitsLength =
|
||||
(js_gc_MinCellSize - sizeof(uintptr_t)) / sizeof(Digit);
|
||||
|
||||
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:
|
||||
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;
|
||||
|
||||
static BigInt* createUninitialized(js::ExclusiveContext* cx, size_t length,
|
||||
bool isNegative);
|
||||
static BigInt* createFromDouble(js::ExclusiveContext* cx, double d);
|
||||
static BigInt* createFromUint64(js::ExclusiveContext* cx, uint64_t n);
|
||||
static BigInt* createFromInt64(js::ExclusiveContext* cx, int64_t n);
|
||||
// FIXME: Cache these values.
|
||||
static BigInt* zero(js::ExclusiveContext* cx);
|
||||
static BigInt* one(js::ExclusiveContext* cx);
|
||||
|
||||
static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
static BigInt* add(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* sub(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* mul(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* div(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* mod(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* pow(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* neg(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
static BigInt* lsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* rsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* bitAnd(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* bitXor(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* bitOr(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
|
||||
static BigInt* bitNot(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
|
||||
static int64_t toInt64(BigInt* x);
|
||||
static uint64_t toUint64(BigInt* x);
|
||||
|
||||
static BigInt* asIntN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);
|
||||
static BigInt* asUintN(js::ExclusiveContext* cx, Handle<BigInt*> x, uint64_t bits);
|
||||
|
||||
// Type-checking versions of arithmetic operations. These methods
|
||||
// must be called with at least one BigInt operand. Binary
|
||||
// operations will throw a TypeError if one of the operands is not a
|
||||
// BigInt value.
|
||||
static bool add(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool sub(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool mul(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool div(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool mod(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool pow(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool neg(js::ExclusiveContext* cx, Handle<Value> operand,
|
||||
MutableHandle<Value> res);
|
||||
static bool lsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool rsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool bitAnd(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool bitXor(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool bitOr(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs,
|
||||
MutableHandle<Value> res);
|
||||
static bool bitNot(js::ExclusiveContext* cx, Handle<Value> operand,
|
||||
MutableHandle<Value> res);
|
||||
|
||||
static double numberValue(BigInt* x);
|
||||
|
||||
static JSLinearString* toString(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
uint8_t radix);
|
||||
template <typename CharT>
|
||||
static BigInt* parseLiteral(js::ExclusiveContext* cx,
|
||||
const mozilla::Range<const CharT> chars,
|
||||
bool* haveParseError);
|
||||
template <typename CharT>
|
||||
static BigInt* parseLiteralDigits(js::ExclusiveContext* 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 JS::Result<bool> looselyEqual(js::ExclusiveContext* 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);
|
||||
static mozilla::Maybe<bool> lessThan(double lhs, BigInt* rhs);
|
||||
static bool lessThan(js::ExclusiveContext* cx, Handle<BigInt*> lhs, HandleString rhs,
|
||||
mozilla::Maybe<bool>& res);
|
||||
static bool lessThan(js::ExclusiveContext* cx, HandleString lhs, Handle<BigInt*> rhs,
|
||||
mozilla::Maybe<bool>& res);
|
||||
static bool lessThan(js::ExclusiveContext* cx, HandleValue lhs, HandleValue rhs,
|
||||
mozilla::Maybe<bool>& res);
|
||||
|
||||
private:
|
||||
static constexpr size_t DigitBits = sizeof(Digit) * CHAR_BIT;
|
||||
static constexpr size_t HalfDigitBits = DigitBits / 2;
|
||||
static constexpr Digit HalfDigitMask = (1ull << HalfDigitBits) - 1;
|
||||
|
||||
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(js::ExclusiveContext* cx,
|
||||
uint8_t radix,
|
||||
size_t charCount,
|
||||
size_t* result);
|
||||
|
||||
static bool absoluteDivWithDigitDivisor(
|
||||
js::ExclusiveContext* 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(
|
||||
js::ExclusiveContext* 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(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
unsigned shift, LeftShiftMode);
|
||||
static bool productGreaterThan(Digit factor1, Digit factor2, Digit high,
|
||||
Digit low);
|
||||
static BigInt* lshByAbsolute(js::ExclusiveContext* cx, HandleBigInt x, HandleBigInt y);
|
||||
static BigInt* rshByAbsolute(js::ExclusiveContext* cx, HandleBigInt x, HandleBigInt y);
|
||||
static BigInt* rshByMaximum(js::ExclusiveContext* cx, bool isNegative);
|
||||
static BigInt* truncateAndSubFromPowerOfTwo(js::ExclusiveContext* 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(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y, BitwiseOp&& op);
|
||||
|
||||
// Return `|x| & |y|`.
|
||||
static BigInt* absoluteAnd(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| | |y|`.
|
||||
static BigInt* absoluteOr(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| & ~|y|`.
|
||||
static BigInt* absoluteAndNot(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `|x| ^ |y|`.
|
||||
static BigInt* absoluteXor(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y);
|
||||
|
||||
// Return `(|x| + 1) * (resultNegative ? -1 : +1)`.
|
||||
static BigInt* absoluteAddOne(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
bool resultNegative);
|
||||
|
||||
// Return `(|x| - 1) * (resultNegative ? -1 : +1)`, with the precondition that
|
||||
// |x| != 0.
|
||||
static BigInt* absoluteSubOne(js::ExclusiveContext* 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(js::ExclusiveContext* cx, Handle<BigInt*> x,
|
||||
Handle<BigInt*> y, bool resultNegative);
|
||||
|
||||
// Return `(|x| - |y|) * (resultNegative ? -1 : +1)`, with the precondition
|
||||
// that |x| >= |y|.
|
||||
static BigInt* absoluteSub(js::ExclusiveContext* 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(js::ExclusiveContext* cx, Handle<BigInt*>,
|
||||
unsigned radix);
|
||||
static JSLinearString* toStringGeneric(js::ExclusiveContext* cx, Handle<BigInt*>,
|
||||
unsigned radix);
|
||||
|
||||
static BigInt* trimHighZeroDigits(js::ExclusiveContext* cx, Handle<BigInt*> x);
|
||||
static BigInt* destructivelyTrimHighZeroDigits(js::ExclusiveContext* cx,
|
||||
Handle<BigInt*> x);
|
||||
|
||||
friend struct JSStructuredCloneReader;
|
||||
friend struct JSStructuredCloneWriter;
|
||||
#if 0 // Future XDR support
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::XDRBigInt(js::XDRState<mode>* xdr,
|
||||
MutableHandle<BigInt*> bi);
|
||||
#endif
|
||||
|
||||
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(js::ExclusiveContext* cx, JS::HandleBigInt bi);
|
||||
|
||||
extern JS::BigInt* NumberToBigInt(js::ExclusiveContext* cx, double d);
|
||||
|
||||
// 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(
|
||||
js::ExclusiveContext* cx, JS::Handle<JSString*> str);
|
||||
|
||||
// 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(
|
||||
js::ExclusiveContext* cx, const mozilla::Range<const char16_t>& chars);
|
||||
|
||||
extern JS::BigInt* ToBigInt(js::ExclusiveContext* cx, JS::Handle<JS::Value> v);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#undef js_gc_MinCellSize
|
||||
#undef js_gc_Cell_ReservedBits
|
||||
|
||||
#endif
|
||||
|
||||
@@ -171,7 +171,8 @@ js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
return sb.append(str);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -39,6 +40,8 @@
|
||||
#include "jsdate.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "vm/BigIntType.h"
|
||||
|
||||
#include "builtin/MapObject.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/GCHashTable.h"
|
||||
@@ -57,6 +60,7 @@ using mozilla::IsNaN;
|
||||
using mozilla::LittleEndian;
|
||||
using mozilla::NativeEndian;
|
||||
using mozilla::NumbersAreIdentical;
|
||||
using mozilla::RangedPtr;
|
||||
using JS::CanonicalizeNaN;
|
||||
|
||||
// When you make updates here, make sure you consider whether you need to bump the
|
||||
@@ -104,6 +108,9 @@ enum StructuredDataType : uint32_t {
|
||||
|
||||
SCTAG_SHARED_ARRAY_BUFFER_OBJECT,
|
||||
|
||||
SCTAG_BIGINT,
|
||||
SCTAG_BIGINT_OBJECT,
|
||||
|
||||
SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100,
|
||||
SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Int8,
|
||||
SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + Scalar::Uint8,
|
||||
@@ -349,6 +356,8 @@ struct JSStructuredCloneReader {
|
||||
JSString* readStringImpl(uint32_t nchars);
|
||||
JSString* readString(uint32_t data);
|
||||
|
||||
BigInt* readBigInt(uint32_t data);
|
||||
|
||||
bool checkDouble(double d);
|
||||
bool readTypedArray(uint32_t arrayType, uint32_t nelems, MutableHandleValue vp,
|
||||
bool v1Read = false);
|
||||
@@ -439,6 +448,8 @@ struct JSStructuredCloneWriter {
|
||||
bool traverseSet(HandleObject obj);
|
||||
bool traverseSavedFrame(HandleObject obj);
|
||||
|
||||
bool writeBigInt(uint32_t tag, BigInt* bi);
|
||||
|
||||
bool reportDataCloneError(uint32_t errorId);
|
||||
|
||||
bool parseTransferable();
|
||||
@@ -1055,6 +1066,23 @@ JSStructuredCloneWriter::writeString(uint32_t tag, JSString* str)
|
||||
: out.writeChars(linear->twoByteChars(nogc), length);
|
||||
}
|
||||
|
||||
bool
|
||||
JSStructuredCloneWriter::writeBigInt(uint32_t tag, BigInt* 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);
|
||||
|
||||
if (!out.writePair(tag, lengthAndSign)) {
|
||||
return false;
|
||||
}
|
||||
return out.writeArray(bi->digits().data(), length);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSStructuredCloneWriter::checkStack()
|
||||
{
|
||||
@@ -1388,6 +1416,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
|
||||
return out.writePair(SCTAG_NULL, 0);
|
||||
} else if (v.isUndefined()) {
|
||||
return out.writePair(SCTAG_UNDEFINED, 0);
|
||||
} else if (v.isBigInt()) {
|
||||
return writeBigInt(SCTAG_BIGINT, v.toBigInt());
|
||||
} else if (v.isObject()) {
|
||||
RootedObject obj(context(), &v.toObject());
|
||||
|
||||
@@ -1441,6 +1471,12 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
|
||||
return writeString(SCTAG_STRING_OBJECT, unboxed.toString());
|
||||
} else if (cls == ESClass::Map) {
|
||||
return traverseMap(obj);
|
||||
} else if (cls == ESClass::BigInt) {
|
||||
RootedValue unboxed(context());
|
||||
if (!Unbox(context(), obj, &unboxed)) {
|
||||
return false;
|
||||
}
|
||||
return writeBigInt(SCTAG_BIGINT_OBJECT, unboxed.toBigInt());
|
||||
} else if (cls == ESClass::Set) {
|
||||
return traverseSet(obj);
|
||||
} else if (SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
|
||||
@@ -1745,6 +1781,22 @@ JSStructuredCloneReader::readString(uint32_t data)
|
||||
return latin1 ? readStringImpl<Latin1Char>(nchars) : readStringImpl<char16_t>(nchars);
|
||||
}
|
||||
|
||||
BigInt* JSStructuredCloneReader::readBigInt(uint32_t data) {
|
||||
size_t length = data & JS_BITMASK(31);
|
||||
bool isNegative = data & (1 << 31);
|
||||
if (length == 0) {
|
||||
return BigInt::zero(context());
|
||||
}
|
||||
BigInt* result = BigInt::createUninitialized(context(), length, isNegative);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!in.readArray(result->digits().data(), length)) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
TagToV1ArrayType(uint32_t tag)
|
||||
{
|
||||
@@ -2021,6 +2073,19 @@ JSStructuredCloneReader::startRead(MutableHandleValue vp)
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_BIGINT:
|
||||
case SCTAG_BIGINT_OBJECT: {
|
||||
RootedBigInt bi(context(), readBigInt(data));
|
||||
if (!bi) {
|
||||
return false;
|
||||
}
|
||||
vp.setBigInt(bi);
|
||||
if (tag == SCTAG_BIGINT_OBJECT && !PrimitiveToObject(context(), vp)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTAG_DATE_OBJECT: {
|
||||
double d;
|
||||
if (!in.readDouble(&d) || !checkDouble(d))
|
||||
|
||||
Reference in New Issue
Block a user