/* * Copyright (C) 2017 Caio Lima * Copyright (C) 2019-2020 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "CPU.h" #include "Error.h" #include "ExceptionHelpers.h" #include "JSGlobalObject.h" #include "JSObject.h" #include "MathCommon.h" #include #include #include #include namespace JSC { class Int32BigIntImpl; class HeapBigIntImpl; class JSBigInt final : public JSCell { public: using Base = JSCell; using Digit = UCPURegister; static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal | OverridesToThis; friend class CachedBigInt; static void visitChildren(JSCell*, SlotVisitor&); template static IsoSubspace* subspaceFor(VM& vm) { return &vm.bigIntSpace; } enum class InitializationType { None, WithZero }; void initialize(InitializationType); static size_t estimatedSize(JSCell*, VM&); static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); JS_EXPORT_PRIVATE static JSBigInt* createZero(JSGlobalObject*); JS_EXPORT_PRIVATE static JSBigInt* tryCreateZero(VM&); JS_EXPORT_PRIVATE static JSBigInt* tryCreateWithLength(VM&, unsigned length); JS_EXPORT_PRIVATE static JSBigInt* createWithLength(JSGlobalObject*, unsigned length); JS_EXPORT_PRIVATE static JSBigInt* createFrom(JSGlobalObject*, int32_t value); static JSBigInt* tryCreateFrom(VM&, int32_t value); static JSBigInt* createFrom(JSGlobalObject*, uint32_t value); static JSBigInt* createFrom(JSGlobalObject*, int64_t value); JS_EXPORT_PRIVATE static JSBigInt* createFrom(JSGlobalObject*, uint64_t value); static JSBigInt* createFrom(JSGlobalObject*, bool value); static JSBigInt* createFrom(JSGlobalObject*, double value); static JSBigInt* createFrom(JSGlobalObject*, VM&, int32_t value); static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSBigInt, m_length); } DECLARE_EXPORT_INFO; JSValue toPrimitive(JSGlobalObject*, PreferredPrimitiveType) const; void setSign(bool sign) { m_sign = sign; } bool sign() const { return m_sign; } unsigned length() const { return m_length; } static JSValue makeHeapBigIntOrBigInt32(JSGlobalObject* globalObject, int64_t value) { #if USE(BIGINT32) if (value <= INT_MAX && value >= INT_MIN) return jsBigInt32(static_cast(value)); #endif return JSBigInt::createFrom(globalObject, value); } static JSValue makeHeapBigIntOrBigInt32(JSGlobalObject* globalObject, double value) { ASSERT(isInteger(value)); if (std::abs(value) <= maxSafeInteger()) return makeHeapBigIntOrBigInt32(globalObject, static_cast(value)); return JSBigInt::createFrom(globalObject, value); } enum class ErrorParseMode { ThrowExceptions, IgnoreExceptions }; enum class ParseIntMode { DisallowEmptyString, AllowEmptyString }; enum class ParseIntSign { Unsigned, Signed }; static JSValue parseInt(JSGlobalObject*, VM&, StringView, uint8_t radix, ErrorParseMode = ErrorParseMode::ThrowExceptions, ParseIntSign = ParseIntSign::Unsigned); static JSValue parseInt(JSGlobalObject*, StringView, ErrorParseMode = ErrorParseMode::ThrowExceptions); static JSValue stringToBigInt(JSGlobalObject*, StringView); static String tryGetString(VM&, JSBigInt*, unsigned radix); String toString(JSGlobalObject*, unsigned radix); enum class ComparisonMode { LessThan, LessThanOrEqual }; enum class ComparisonResult { Equal, Undefined, GreaterThan, LessThan }; JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*); bool equalsToNumber(JSValue); JS_EXPORT_PRIVATE bool equalsToInt32(int32_t); static ComparisonResult compare(JSBigInt* x, JSBigInt* y); static ComparisonResult compare(int32_t x, JSBigInt* y); static ComparisonResult compare(JSBigInt* x, int32_t y); static ComparisonResult compare(int32_t x, int32_t y) { if (x == y) return JSBigInt::ComparisonResult::Equal; if (x < y) return JSBigInt::ComparisonResult::LessThan; return JSBigInt::ComparisonResult::GreaterThan; } double toNumber(JSGlobalObject*) const; JSObject* toObject(JSGlobalObject*) const; inline bool toBoolean() const { return !isZero(); } ComparisonResult static compareToDouble(JSBigInt* x, double y); ALWAYS_INLINE static JSValue asInt32OrHeapCell(JSGlobalObject* globalObject, int64_t value) { #if USE(BIGINT32) if (static_cast(static_cast(value)) == value) return jsBigInt32(static_cast(value)); #endif return createFrom(globalObject, value); } private: friend class HeapBigIntImpl; public: struct ImplResult { ImplResult(HeapBigIntImpl&); ImplResult(JSBigInt*); #if USE(BIGINT32) ImplResult(Int32BigIntImpl&); #endif ImplResult(JSValue); JSValue payload; }; private: static JSBigInt* createWithLength(JSGlobalObject*, VM&, unsigned length); static JSBigInt* createZero(JSGlobalObject*, VM&); template static ImplResult exponentiateImpl(JSGlobalObject*, BigIntImpl1 base, BigIntImpl2 exponent); template static ImplResult multiplyImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult incImpl(JSGlobalObject*, BigIntImpl x); template static ImplResult decImpl(JSGlobalObject*, BigIntImpl x); template static ImplResult addImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult subImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult divideImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult remainderImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult unaryMinusImpl(JSGlobalObject*, BigIntImpl x); template static ImplResult bitwiseAndImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult bitwiseOrImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult bitwiseXorImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult bitwiseNotImpl(JSGlobalObject*, BigIntImpl x); template static ImplResult leftShiftImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult signedRightShiftImpl(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ComparisonResult compareImpl(BigIntImpl1 x, BigIntImpl2 y); public: static JSValue exponentiate(JSGlobalObject*, JSBigInt* base, JSBigInt* exponent); #if USE(BIGINT32) static JSValue exponentiate(JSGlobalObject*, JSBigInt* base, int32_t exponent); static JSValue exponentiate(JSGlobalObject*, int32_t base, JSBigInt* exponent); static JSValue exponentiate(JSGlobalObject*, int32_t base, int32_t exponent); #endif static JSValue multiply(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue multiply(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue multiply(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue multiply(JSGlobalObject* globalObject, int32_t x, int32_t y) { int64_t result = static_cast(x) * static_cast(y); return asInt32OrHeapCell(globalObject, result); } #endif static JSValue inc(JSGlobalObject*, JSBigInt* x); #if USE(BIGINT32) static JSValue inc(JSGlobalObject* globalObject, int32_t x) { return asInt32OrHeapCell(globalObject, static_cast(x) + 1); } #endif static JSValue dec(JSGlobalObject*, JSBigInt* x); #if USE(BIGINT32) static JSValue dec(JSGlobalObject* globalObject, int32_t x) { return asInt32OrHeapCell(globalObject, static_cast(x) - 1); } #endif static JSValue add(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue add(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue add(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue add(JSGlobalObject* globalObject, int32_t x, int32_t y) { return asInt32OrHeapCell(globalObject, static_cast(x) + static_cast(y)); } #endif static JSValue sub(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue sub(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue sub(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue sub(JSGlobalObject* globalObject, int32_t x, int32_t y) { return asInt32OrHeapCell(globalObject, static_cast(x) - static_cast(y)); } #endif static JSValue divide(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue divide(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue divide(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue divide(JSGlobalObject* globalObject, int32_t x, int32_t y) { if (!y) { auto scope = DECLARE_THROW_SCOPE(getVM(globalObject)); throwRangeError(globalObject, scope, "0 is an invalid divisor value."_s); return JSValue(); } return asInt32OrHeapCell(globalObject, static_cast(x) / static_cast(y)); } #endif static JSValue remainder(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue remainder(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue remainder(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue remainder(JSGlobalObject* globalObject, int32_t x, int32_t y) { if (!y) { auto scope = DECLARE_THROW_SCOPE(getVM(globalObject)); throwRangeError(globalObject, scope, "0 is an invalid divisor value."_s); return JSValue(); } return asInt32OrHeapCell(globalObject, static_cast(x) % static_cast(y)); } #endif static JSValue unaryMinus(JSGlobalObject*, JSBigInt* x); #if USE(BIGINT32) static JSValue unaryMinus(JSGlobalObject* globalObject, int32_t x) { return asInt32OrHeapCell(globalObject, -static_cast(x)); } #endif static JSValue bitwiseAnd(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue bitwiseAnd(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue bitwiseAnd(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue bitwiseAnd(JSGlobalObject* globalObject, int32_t x, int32_t y) { return asInt32OrHeapCell(globalObject, x & y); } #endif static JSValue bitwiseOr(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue bitwiseOr(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue bitwiseOr(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue bitwiseOr(JSGlobalObject* globalObject, int32_t x, int32_t y) { return asInt32OrHeapCell(globalObject, x | y); } #endif static JSValue bitwiseXor(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue bitwiseXor(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue bitwiseXor(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue bitwiseXor(JSGlobalObject* globalObject, int32_t x, int32_t y) { return asInt32OrHeapCell(globalObject, x ^ y); } #endif static JSValue bitwiseNot(JSGlobalObject*, JSBigInt* x); #if USE(BIGINT32) static JSValue bitwiseNot(JSGlobalObject* globalObject, int32_t x) { return asInt32OrHeapCell(globalObject, ~x); } #endif static JSValue leftShift(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue leftShift(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue leftShift(JSGlobalObject*, int32_t x, JSBigInt* y); private: static JSValue leftShiftSlow(JSGlobalObject*, int32_t x, int32_t y); public: static JSValue leftShift(JSGlobalObject* globalObject, int32_t x, int32_t y) { if (y < 0) { // Shifts one less than requested, but doesn't matter since lhs is int32 return signedRightShift(globalObject, x, y == INT32_MIN ? INT32_MAX : -y); } // Do some checks to detect overflow of left-shift. But this is much cheaper compared to allocating two JSBigInt and perform shift operations in JSBigInt. if (!x) return jsBigInt32(0); if (y < 32) return asInt32OrHeapCell(globalObject, static_cast(x) << y); return leftShiftSlow(globalObject, x, y); } #endif static JSValue signedRightShift(JSGlobalObject*, JSBigInt* x, JSBigInt* y); #if USE(BIGINT32) static JSValue signedRightShift(JSGlobalObject*, JSBigInt* x, int32_t y); static JSValue signedRightShift(JSGlobalObject*, int32_t x, JSBigInt* y); static JSValue signedRightShift(JSGlobalObject* globalObject, int32_t x, int32_t y) { if (y < 0) { // Shifts one less than requested, but doesn't matter since lhs is int32 return leftShift(globalObject, x, y == INT32_MIN ? INT32_MAX : -y); } return jsBigInt32(x >> std::min(y, 31)); } #endif static JSValue toNumberHeap(JSBigInt*); static JSValue toNumber(JSValue bigInt) { ASSERT(bigInt.isBigInt()); #if USE(BIGINT32) if (bigInt.isBigInt32()) return jsNumber(bigInt.bigInt32AsInt32()); #endif return toNumberHeap(jsCast(bigInt)); } static JSValue asIntN(JSGlobalObject*, uint64_t numberOfBits, JSBigInt*); static JSValue asUintN(JSGlobalObject*, uint64_t numberOfBits, JSBigInt*); #if USE(BIGINT32) static JSValue asIntN(JSGlobalObject*, uint64_t numberOfBits, int32_t bigIntAsInt32); static JSValue asUintN(JSGlobalObject*, uint64_t numberOfBits, int32_t bigIntAsInt32); #endif static uint64_t toBigUInt64(JSValue bigInt) { ASSERT(bigInt.isBigInt()); #if USE(BIGINT32) if (bigInt.isBigInt32()) return static_cast(static_cast(bigInt.bigInt32AsInt32())); #endif return toBigUInt64Heap(bigInt.asHeapBigInt()); } static uint64_t toBigInt64(JSValue bigInt) { ASSERT(bigInt.isBigInt()); #if USE(BIGINT32) if (bigInt.isBigInt32()) return static_cast(bigInt.bigInt32AsInt32()); #endif return static_cast(toBigUInt64Heap(bigInt.asHeapBigInt())); } Digit digit(unsigned); void setDigit(unsigned, Digit); // Use only when initializing. JS_EXPORT_PRIVATE JSBigInt* rightTrim(JSGlobalObject*); JS_EXPORT_PRIVATE JSBigInt* tryRightTrim(VM&); JS_EXPORT_PRIVATE Optional concurrentHash(); unsigned hash() { if (m_hash) return m_hash; return hashSlow(); } private: JSBigInt(VM&, Structure*, Digit*, unsigned length); JSBigInt* rightTrim(JSGlobalObject*, VM&); JS_EXPORT_PRIVATE unsigned hashSlow(); static JSBigInt* createFromImpl(JSGlobalObject*, uint64_t value, bool sign); static constexpr unsigned bitsPerByte = 8; static constexpr unsigned digitBits = sizeof(Digit) * bitsPerByte; static constexpr unsigned halfDigitBits = digitBits / 2; static constexpr Digit halfDigitMask = (1ull << halfDigitBits) - 1; static constexpr int maxInt = 0x7FFFFFFF; static constexpr unsigned doubleMantissaSize = 53; static constexpr unsigned doublePhysicalMantissaSize = 52; // Excluding hidden-bit. static constexpr uint64_t doublePhysicalMantissaMask = (1ULL << doublePhysicalMantissaSize) - 1; static constexpr uint64_t doubleMantissaHiddenBit = 1ULL << doublePhysicalMantissaSize; // The maximum length that the current implementation supports would be // maxInt / 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 unsigned maxLengthBits = 1024 * 1024; static constexpr unsigned maxLength = maxLengthBits / digitBits; static_assert(maxLengthBits % digitBits == 0); static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); template static ComparisonResult absoluteCompare(BigIntImpl1 x, BigIntImpl2 y); template static bool absoluteDivWithDigitDivisor(JSGlobalObject*, VM&, BigIntImpl x, Digit divisor, JSBigInt** quotient, Digit& remainder); template static void internalMultiplyAdd(BigIntImpl source, Digit factor, Digit summand, unsigned, JSBigInt* result); template static void multiplyAccumulate(BigIntImpl multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex); template static void absoluteDivWithBigIntDivisor(JSGlobalObject*, BigIntImpl1 dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder); enum class LeftShiftMode { SameSizeResult, AlwaysAddOneDigit }; template static JSBigInt* absoluteLeftShiftAlwaysCopy(JSGlobalObject*, BigIntImpl x, unsigned shift, LeftShiftMode); static bool productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low); Digit absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex); Digit absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex); void inplaceRightShift(unsigned shift); enum class RoundingResult { RoundDown, Tie, RoundUp }; static RoundingResult decideRounding(JSBigInt*, int32_t mantissaBitsUnset, int32_t digitIndex, uint64_t currentDigit); enum class ExtraDigitsHandling { Copy, Skip }; template static JSBigInt* absoluteBitwiseOp(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y, ExtraDigitsHandling, BitwiseOp&&); template static JSBigInt* absoluteAnd(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static JSBigInt* absoluteOr(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static JSBigInt* absoluteAndNot(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static JSBigInt* absoluteXor(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); enum class SignOption { Signed, Unsigned }; template static JSBigInt* absoluteAddOne(JSGlobalObject*, BigIntImpl x, SignOption); template static JSBigInt* absoluteSubOne(JSGlobalObject*, BigIntImpl x, unsigned resultLength); // Digit arithmetic helpers. static Digit digitAdd(Digit a, Digit b, Digit& carry); static Digit digitSub(Digit a, Digit b, Digit& borrow); static Digit digitMul(Digit a, Digit b, Digit& high); static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder); static Digit digitPow(Digit base, Digit exponent); static String toStringBasePowerOfTwo(VM&, JSGlobalObject*, JSBigInt*, unsigned radix); static String toStringGeneric(VM&, JSGlobalObject*, JSBigInt*, unsigned radix); inline bool isZero() const { ASSERT(length() || !sign()); return length() == 0; } template static JSValue parseInt(JSGlobalObject*, CharType* data, unsigned length, ErrorParseMode); template static JSValue parseInt(JSGlobalObject*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, ParseIntSign = ParseIntSign::Signed, ParseIntMode = ParseIntMode::AllowEmptyString); static JSBigInt* allocateFor(JSGlobalObject*, VM&, unsigned radix, unsigned charcount); template static JSBigInt* copy(JSGlobalObject*, BigIntImpl x); void inplaceMultiplyAdd(Digit multiplier, Digit part); template static ImplResult absoluteAdd(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y, bool resultSign); template static ImplResult absoluteSub(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y, bool resultSign); template static ImplResult leftShiftByAbsolute(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); template static ImplResult rightShiftByAbsolute(JSGlobalObject*, BigIntImpl1 x, BigIntImpl2 y); static ImplResult rightShiftByMaximum(JSGlobalObject*, bool sign); template static Optional toShiftAmount(BigIntImpl x); template static ImplResult asIntNImpl(JSGlobalObject*, uint64_t, BigIntImpl); template static ImplResult asUintNImpl(JSGlobalObject*, uint64_t, BigIntImpl); template static ImplResult truncateToNBits(JSGlobalObject*, int32_t, BigIntImpl); template static ImplResult truncateAndSubFromPowerOfTwo(JSGlobalObject*, int32_t, BigIntImpl, bool resultSign); JS_EXPORT_PRIVATE static uint64_t toBigUInt64Heap(JSBigInt*); JS_EXPORT_PRIVATE static Optional toUint64Heap(JSBigInt*); inline static size_t offsetOfData() { return OBJECT_OFFSETOF(JSBigInt, m_data); } inline Digit* dataStorage() { return m_data.get(m_length); } inline Digit* dataStorageUnsafe() { return m_data.getUnsafe(); } const unsigned m_length; unsigned m_hash { 0 }; bool m_sign { false }; CagedBarrierPtr m_data; }; inline JSBigInt* asHeapBigInt(JSValue value) { ASSERT(value.asCell()->isHeapBigInt()); return jsCast(value.asCell()); } inline JSBigInt::Digit JSBigInt::digit(unsigned n) { ASSERT(n < length()); return dataStorage()[n]; } inline void JSBigInt::setDigit(unsigned n, Digit value) { ASSERT(n < length()); dataStorage()[n] = value; } ALWAYS_INLINE JSBigInt::ComparisonResult invertBigIntCompareResult(JSBigInt::ComparisonResult comparisonResult) { switch (comparisonResult) { case JSBigInt::ComparisonResult::GreaterThan: return JSBigInt::ComparisonResult::LessThan; case JSBigInt::ComparisonResult::LessThan: return JSBigInt::ComparisonResult::GreaterThan; default: return comparisonResult; } } ALWAYS_INLINE JSValue tryConvertToBigInt32(JSBigInt* bigInt) { #if USE(BIGINT32) if (UNLIKELY(!bigInt)) return JSValue(); if (bigInt->length() <= 1) { if (!bigInt->length()) return jsBigInt32(0); JSBigInt::Digit digit = bigInt->digit(0); if (bigInt->sign()) { static constexpr uint64_t maxValue = -static_cast(std::numeric_limits::min()); if (digit <= maxValue) return jsBigInt32(static_cast(-static_cast(digit))); } else { static constexpr uint64_t maxValue = static_cast(std::numeric_limits::max()); if (digit <= maxValue) return jsBigInt32(static_cast(digit)); } } #endif return bigInt; } } // namespace JSC