mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-04-17 14:30:01 +00:00
2056 lines
67 KiB
C++
2056 lines
67 KiB
C++
/*
|
|
* Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
|
|
* Copyright (C) 2017-2018 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.
|
|
*
|
|
* Parts of the implementation below:
|
|
*
|
|
* Copyright 2017 the V8 project authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*
|
|
*
|
|
* Copyright (c) 2014 the Dart project authors. Please see the AUTHORS file [1]
|
|
* for details. All rights reserved. Use of this source code is governed by a
|
|
* BSD-style license that can be found in the LICENSE file [2].
|
|
*
|
|
* [1] https://github.com/dart-lang/sdk/blob/master/AUTHORS
|
|
* [2] https://github.com/dart-lang/sdk/blob/master/LICENSE
|
|
*
|
|
* Copyright 2009 The Go Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style
|
|
* license that can be found in the LICENSE file [3].
|
|
*
|
|
* [3] https://golang.org/LICENSE
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "JSBigInt.h"
|
|
|
|
#include "BigIntObject.h"
|
|
#include "CatchScope.h"
|
|
#include "JSCInlines.h"
|
|
#include "MathCommon.h"
|
|
#include "ParseInt.h"
|
|
#include <algorithm>
|
|
#include <wtf/MathExtras.h>
|
|
|
|
#define STATIC_ASSERT(cond) static_assert(cond, "JSBigInt assumes " #cond)
|
|
|
|
namespace JSC {
|
|
|
|
const ClassInfo JSBigInt::s_info =
|
|
{ "JSBigInt", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSBigInt) };
|
|
|
|
JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length)
|
|
: Base(vm, structure)
|
|
, m_length(length)
|
|
{ }
|
|
|
|
void JSBigInt::initialize(InitializationType initType)
|
|
{
|
|
if (initType == InitializationType::WithZero)
|
|
memset(dataStorage(), 0, length() * sizeof(Digit));
|
|
}
|
|
|
|
Structure* JSBigInt::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
|
|
{
|
|
return Structure::create(vm, globalObject, prototype, TypeInfo(BigIntType, StructureFlags), info());
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createZero(VM& vm)
|
|
{
|
|
JSBigInt* zeroBigInt = createWithLengthUnchecked(vm, 0);
|
|
return zeroBigInt;
|
|
}
|
|
|
|
inline size_t JSBigInt::allocationSize(unsigned length)
|
|
{
|
|
size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt));
|
|
return sizeWithPadding + length * sizeof(Digit);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::tryCreateWithLength(ExecState* exec, unsigned length)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (UNLIKELY(length > maxLength)) {
|
|
throwOutOfMemoryError(exec, scope);
|
|
return nullptr;
|
|
}
|
|
|
|
scope.release();
|
|
|
|
return createWithLengthUnchecked(vm, length);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createWithLengthUnchecked(VM& vm, unsigned length)
|
|
{
|
|
ASSERT(length <= maxLength);
|
|
JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
|
|
bigInt->finishCreation(vm);
|
|
return bigInt;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createFrom(VM& vm, int32_t value)
|
|
{
|
|
if (!value)
|
|
return createZero(vm);
|
|
|
|
JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
|
|
if (value < 0) {
|
|
bigInt->setDigit(0, static_cast<Digit>(-1 * static_cast<int64_t>(value)));
|
|
bigInt->setSign(true);
|
|
} else
|
|
bigInt->setDigit(0, static_cast<Digit>(value));
|
|
|
|
return bigInt;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createFrom(VM& vm, uint32_t value)
|
|
{
|
|
if (!value)
|
|
return createZero(vm);
|
|
|
|
JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
|
|
bigInt->setDigit(0, static_cast<Digit>(value));
|
|
return bigInt;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createFrom(VM& vm, int64_t value)
|
|
{
|
|
if (!value)
|
|
return createZero(vm);
|
|
|
|
if (sizeof(Digit) == 8) {
|
|
JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
|
|
if (value < 0) {
|
|
bigInt->setDigit(0, static_cast<Digit>(static_cast<uint64_t>(-(value + 1)) + 1));
|
|
bigInt->setSign(true);
|
|
} else
|
|
bigInt->setDigit(0, static_cast<Digit>(value));
|
|
|
|
return bigInt;
|
|
}
|
|
|
|
JSBigInt* bigInt = createWithLengthUnchecked(vm, 2);
|
|
uint64_t tempValue;
|
|
bool sign = false;
|
|
if (value < 0) {
|
|
tempValue = static_cast<uint64_t>(-(value + 1)) + 1;
|
|
sign = true;
|
|
} else
|
|
tempValue = value;
|
|
|
|
Digit lowBits = static_cast<Digit>(tempValue & 0xffffffff);
|
|
Digit highBits = static_cast<Digit>((tempValue >> 32) & 0xffffffff);
|
|
|
|
bigInt->setDigit(0, lowBits);
|
|
bigInt->setDigit(1, highBits);
|
|
bigInt->setSign(sign);
|
|
|
|
return bigInt;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::createFrom(VM& vm, bool value)
|
|
{
|
|
if (!value)
|
|
return createZero(vm);
|
|
|
|
JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
|
|
bigInt->setDigit(0, static_cast<Digit>(value));
|
|
return bigInt;
|
|
}
|
|
|
|
JSValue JSBigInt::toPrimitive(ExecState*, PreferredPrimitiveType) const
|
|
{
|
|
return const_cast<JSBigInt*>(this);
|
|
}
|
|
|
|
Optional<uint8_t> JSBigInt::singleDigitValueForString()
|
|
{
|
|
if (isZero())
|
|
return 0;
|
|
|
|
if (length() == 1 && !sign()) {
|
|
Digit rDigit = digit(0);
|
|
if (rDigit <= 9)
|
|
return static_cast<uint8_t>(rDigit);
|
|
}
|
|
return { };
|
|
}
|
|
|
|
JSBigInt* JSBigInt::parseInt(ExecState* exec, StringView s, ErrorParseMode parserMode)
|
|
{
|
|
if (s.is8Bit())
|
|
return parseInt(exec, s.characters8(), s.length(), parserMode);
|
|
return parseInt(exec, s.characters16(), s.length(), parserMode);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign)
|
|
{
|
|
if (s.is8Bit())
|
|
return parseInt(exec, vm, s.characters8(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
|
|
return parseInt(exec, vm, s.characters16(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::stringToBigInt(ExecState* exec, StringView s)
|
|
{
|
|
return parseInt(exec, s, ErrorParseMode::IgnoreExceptions);
|
|
}
|
|
|
|
String JSBigInt::toString(ExecState* exec, unsigned radix)
|
|
{
|
|
if (this->isZero())
|
|
return exec->vm().smallStrings.singleCharacterStringRep('0');
|
|
|
|
if (hasOneBitSet(radix))
|
|
return toStringBasePowerOfTwo(exec, this, radix);
|
|
|
|
return toStringGeneric(exec, this, radix);
|
|
}
|
|
|
|
// Multiplies {this} with {factor} and adds {summand} to the result.
|
|
void JSBigInt::inplaceMultiplyAdd(Digit factor, Digit summand)
|
|
{
|
|
internalMultiplyAdd(this, factor, summand, length(), this);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::exponentiate(ExecState* exec, JSBigInt* base, JSBigInt* exponent)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (exponent->sign()) {
|
|
throwRangeError(exec, scope, "Negative exponent is not allowed"_s);
|
|
return nullptr;
|
|
}
|
|
|
|
// 2. If base is 0n and exponent is 0n, return 1n.
|
|
if (exponent->isZero())
|
|
return JSBigInt::createFrom(vm, 1);
|
|
|
|
// 3. Return a BigInt representing the mathematical value of base raised
|
|
// to the power exponent.
|
|
if (base->isZero())
|
|
return base;
|
|
|
|
if (base->length() == 1 && base->digit(0) == 1) {
|
|
// (-1) ** even_number == 1.
|
|
if (base->sign() && !(exponent->digit(0) & 1))
|
|
return JSBigInt::unaryMinus(vm, base);
|
|
|
|
// (-1) ** odd_number == -1; 1 ** anything == 1.
|
|
return base;
|
|
}
|
|
|
|
// For all bases >= 2, very large exponents would lead to unrepresentable
|
|
// results.
|
|
static_assert(maxLengthBits < std::numeric_limits<Digit>::max(), "maxLengthBits needs to be less than digit::max()");
|
|
if (exponent->length() > 1) {
|
|
throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s);
|
|
return nullptr;
|
|
}
|
|
|
|
Digit expValue = exponent->digit(0);
|
|
if (expValue == 1)
|
|
return base;
|
|
if (expValue >= maxLengthBits) {
|
|
throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s);
|
|
return nullptr;
|
|
}
|
|
|
|
static_assert(maxLengthBits <= maxInt, "maxLengthBits needs to be <= maxInt");
|
|
int n = static_cast<int>(expValue);
|
|
if (base->length() == 1 && base->digit(0) == 2) {
|
|
// Fast path for 2^n.
|
|
int neededDigits = 1 + (n / digitBits);
|
|
JSBigInt* result = JSBigInt::tryCreateWithLength(exec, neededDigits);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
result->initialize(InitializationType::WithZero);
|
|
// All bits are zero. Now set the n-th bit.
|
|
Digit msd = static_cast<Digit>(1) << (n % digitBits);
|
|
result->setDigit(neededDigits - 1, msd);
|
|
// Result is negative for odd powers of -2n.
|
|
if (base->sign())
|
|
result->setSign(static_cast<bool>(n & 1));
|
|
|
|
return result;
|
|
}
|
|
|
|
JSBigInt* result = nullptr;
|
|
JSBigInt* runningSquare = base;
|
|
|
|
// This implicitly sets the result's sign correctly.
|
|
if (n & 1)
|
|
result = base;
|
|
|
|
n >>= 1;
|
|
for (; n; n >>= 1) {
|
|
JSBigInt* maybeResult = JSBigInt::multiply(exec, runningSquare, runningSquare);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
runningSquare = maybeResult;
|
|
if (n & 1) {
|
|
if (!result)
|
|
result = runningSquare;
|
|
else {
|
|
maybeResult = JSBigInt::multiply(exec, result, runningSquare);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result = maybeResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (x->isZero())
|
|
return x;
|
|
if (y->isZero())
|
|
return y;
|
|
|
|
unsigned resultLength = x->length() + y->length();
|
|
JSBigInt* result = JSBigInt::tryCreateWithLength(exec, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result->initialize(InitializationType::WithZero);
|
|
|
|
for (unsigned i = 0; i < x->length(); i++)
|
|
multiplyAccumulate(y, x->digit(i), result, i);
|
|
|
|
result->setSign(x->sign() != y->sign());
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::divide(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
// 1. If y is 0n, throw a RangeError exception.
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (y->isZero()) {
|
|
throwRangeError(exec, scope, "0 is an invalid divisor value."_s);
|
|
return nullptr;
|
|
}
|
|
|
|
// 2. Let quotient be the mathematical value of x divided by y.
|
|
// 3. Return a BigInt representing quotient rounded towards 0 to the next
|
|
// integral value.
|
|
if (absoluteCompare(x, y) == ComparisonResult::LessThan)
|
|
return createZero(vm);
|
|
|
|
JSBigInt* quotient = nullptr;
|
|
bool resultSign = x->sign() != y->sign();
|
|
if (y->length() == 1) {
|
|
Digit divisor = y->digit(0);
|
|
if (divisor == 1)
|
|
return resultSign == x->sign() ? x : unaryMinus(vm, x);
|
|
|
|
Digit remainder;
|
|
absoluteDivWithDigitDivisor(vm, x, divisor, "ient, remainder);
|
|
} else {
|
|
absoluteDivWithBigIntDivisor(exec, x, y, "ient, nullptr);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
}
|
|
|
|
quotient->setSign(resultSign);
|
|
return quotient->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::copy(VM& vm, JSBigInt* x)
|
|
{
|
|
ASSERT(!x->isZero());
|
|
|
|
JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, x->length());
|
|
std::copy(x->dataStorage(), x->dataStorage() + x->length(), result->dataStorage());
|
|
result->setSign(x->sign());
|
|
return result;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::unaryMinus(VM& vm, JSBigInt* x)
|
|
{
|
|
if (x->isZero())
|
|
return x;
|
|
|
|
JSBigInt* result = copy(vm, x);
|
|
result->setSign(!x->sign());
|
|
return result;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::remainder(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
// 1. If y is 0n, throw a RangeError exception.
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (y->isZero()) {
|
|
throwRangeError(exec, scope, "0 is an invalid divisor value."_s);
|
|
return nullptr;
|
|
}
|
|
|
|
// 2. Return the JSBigInt representing x modulo y.
|
|
// See https://github.com/tc39/proposal-bigint/issues/84 though.
|
|
if (absoluteCompare(x, y) == ComparisonResult::LessThan)
|
|
return x;
|
|
|
|
JSBigInt* remainder;
|
|
if (y->length() == 1) {
|
|
Digit divisor = y->digit(0);
|
|
if (divisor == 1)
|
|
return createZero(vm);
|
|
|
|
Digit remainderDigit;
|
|
absoluteDivWithDigitDivisor(vm, x, divisor, nullptr, remainderDigit);
|
|
if (!remainderDigit)
|
|
return createZero(vm);
|
|
|
|
remainder = createWithLengthUnchecked(vm, 1);
|
|
remainder->setDigit(0, remainderDigit);
|
|
} else {
|
|
absoluteDivWithBigIntDivisor(exec, x, y, nullptr, &remainder);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
}
|
|
|
|
remainder->setSign(x->sign());
|
|
return remainder->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::add(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
bool xSign = x->sign();
|
|
|
|
// x + y == x + y
|
|
// -x + -y == -(x + y)
|
|
if (xSign == y->sign())
|
|
return absoluteAdd(exec, x, y, xSign);
|
|
|
|
// x + -y == x - y == -(y - x)
|
|
// -x + y == y - x == -(x - y)
|
|
ComparisonResult comparisonResult = absoluteCompare(x, y);
|
|
if (comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal)
|
|
return absoluteSub(vm, x, y, xSign);
|
|
|
|
return absoluteSub(vm, y, x, !xSign);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::sub(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
bool xSign = x->sign();
|
|
if (xSign != y->sign()) {
|
|
// x - (-y) == x + y
|
|
// (-x) - y == -(x + y)
|
|
return absoluteAdd(exec, x, y, xSign);
|
|
}
|
|
// x - y == -(y - x)
|
|
// (-x) - (-y) == y - x == -(x - y)
|
|
ComparisonResult comparisonResult = absoluteCompare(x, y);
|
|
if (comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal)
|
|
return absoluteSub(vm, x, y, xSign);
|
|
|
|
return absoluteSub(vm, y, x, !xSign);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::bitwiseAnd(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (!x->sign() && !y->sign()) {
|
|
scope.release();
|
|
return absoluteAnd(vm, x, y);
|
|
}
|
|
|
|
if (x->sign() && y->sign()) {
|
|
int resultLength = std::max(x->length(), y->length()) + 1;
|
|
// (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
|
|
// == -(((x-1) | (y-1)) + 1)
|
|
JSBigInt* result = absoluteSubOne(exec, x, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result = absoluteOr(vm, result, y1);
|
|
scope.release();
|
|
return absoluteAddOne(exec, result, SignOption::Signed);
|
|
}
|
|
|
|
ASSERT(x->sign() != y->sign());
|
|
// Assume that x is the positive BigInt.
|
|
if (x->sign())
|
|
std::swap(x, y);
|
|
|
|
// x & (-y) == x & ~(y-1) == x & ~(y-1)
|
|
JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
return absoluteAndNot(vm, x, y1);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::bitwiseOr(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
unsigned resultLength = std::max(x->length(), y->length());
|
|
|
|
if (!x->sign() && !y->sign()) {
|
|
scope.release();
|
|
return absoluteOr(vm, x, y);
|
|
}
|
|
|
|
if (x->sign() && y->sign()) {
|
|
// (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
|
|
// == -(((x-1) & (y-1)) + 1)
|
|
JSBigInt* result = absoluteSubOne(exec, x, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result = absoluteAnd(vm, result, y1);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
scope.release();
|
|
return absoluteAddOne(exec, result, SignOption::Signed);
|
|
}
|
|
|
|
ASSERT(x->sign() != y->sign());
|
|
|
|
// Assume that x is the positive BigInt.
|
|
if (x->sign())
|
|
std::swap(x, y);
|
|
|
|
// x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
|
|
JSBigInt* result = absoluteSubOne(exec, y, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result = absoluteAndNot(vm, result, x);
|
|
|
|
scope.release();
|
|
return absoluteAddOne(exec, result, SignOption::Signed);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::bitwiseXor(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (!x->sign() && !y->sign()) {
|
|
scope.release();
|
|
return absoluteXor(vm, x, y);
|
|
}
|
|
|
|
if (x->sign() && y->sign()) {
|
|
int resultLength = std::max(x->length(), y->length());
|
|
|
|
// (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
|
|
JSBigInt* result = absoluteSubOne(exec, x, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
scope.release();
|
|
return absoluteXor(vm, result, y1);
|
|
}
|
|
ASSERT(x->sign() != y->sign());
|
|
int resultLength = std::max(x->length(), y->length()) + 1;
|
|
|
|
// Assume that x is the positive BigInt.
|
|
if (x->sign())
|
|
std::swap(x, y);
|
|
|
|
// x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
|
JSBigInt* result = absoluteSubOne(exec, y, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
result = absoluteXor(vm, result, x);
|
|
scope.release();
|
|
return absoluteAddOne(exec, result, SignOption::Signed);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::leftShift(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
if (y->isZero() || x->isZero())
|
|
return x;
|
|
|
|
if (y->sign())
|
|
return rightShiftByAbsolute(exec, x, y);
|
|
|
|
return leftShiftByAbsolute(exec, x, y);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::signedRightShift(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
if (y->isZero() || x->isZero())
|
|
return x;
|
|
|
|
if (y->sign())
|
|
return leftShiftByAbsolute(exec, x, y);
|
|
|
|
return rightShiftByAbsolute(exec, x, y);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::bitwiseNot(ExecState* exec, JSBigInt* x)
|
|
{
|
|
if (x->sign()) {
|
|
// ~(-x) == ~(~(x-1)) == x-1
|
|
return absoluteSubOne(exec, x, x->length());
|
|
}
|
|
// ~x == -x-1 == -(x+1)
|
|
return absoluteAddOne(exec, x, SignOption::Signed);
|
|
}
|
|
|
|
#if USE(JSVALUE32_64)
|
|
#define HAVE_TWO_DIGIT 1
|
|
typedef uint64_t TwoDigit;
|
|
#elif HAVE(INT128_T)
|
|
#define HAVE_TWO_DIGIT 1
|
|
typedef __uint128_t TwoDigit;
|
|
#else
|
|
#define HAVE_TWO_DIGIT 0
|
|
#endif
|
|
|
|
// {carry} must point to an initialized Digit and will either be incremented
|
|
// by one or left alone.
|
|
inline JSBigInt::Digit JSBigInt::digitAdd(Digit a, Digit b, Digit& carry)
|
|
{
|
|
Digit result = a + b;
|
|
carry += static_cast<bool>(result < a);
|
|
return result;
|
|
}
|
|
|
|
// {borrow} must point to an initialized Digit and will either be incremented
|
|
// by one or left alone.
|
|
inline JSBigInt::Digit JSBigInt::digitSub(Digit a, Digit b, Digit& borrow)
|
|
{
|
|
Digit result = a - b;
|
|
borrow += static_cast<bool>(result > a);
|
|
return result;
|
|
}
|
|
|
|
// Returns the low half of the result. High half is in {high}.
|
|
inline JSBigInt::Digit JSBigInt::digitMul(Digit a, Digit b, Digit& high)
|
|
{
|
|
#if HAVE(TWO_DIGIT)
|
|
TwoDigit result = static_cast<TwoDigit>(a) * static_cast<TwoDigit>(b);
|
|
high = result >> digitBits;
|
|
|
|
return static_cast<Digit>(result);
|
|
#else
|
|
// Multiply in half-pointer-sized chunks.
|
|
// For inputs [AH AL]*[BH BL], the result is:
|
|
//
|
|
// [AL*BL] // rLow
|
|
// + [AL*BH] // rMid1
|
|
// + [AH*BL] // rMid2
|
|
// + [AH*BH] // rHigh
|
|
// = [R4 R3 R2 R1] // high = [R4 R3], low = [R2 R1]
|
|
//
|
|
// Where of course we must be careful with carries between the columns.
|
|
Digit aLow = a & halfDigitMask;
|
|
Digit aHigh = a >> halfDigitBits;
|
|
Digit bLow = b & halfDigitMask;
|
|
Digit bHigh = b >> halfDigitBits;
|
|
|
|
Digit rLow = aLow * bLow;
|
|
Digit rMid1 = aLow * bHigh;
|
|
Digit rMid2 = aHigh * bLow;
|
|
Digit rHigh = aHigh * bHigh;
|
|
|
|
Digit carry = 0;
|
|
Digit low = digitAdd(rLow, rMid1 << halfDigitBits, carry);
|
|
low = digitAdd(low, rMid2 << halfDigitBits, carry);
|
|
|
|
high = (rMid1 >> halfDigitBits) + (rMid2 >> halfDigitBits) + rHigh + carry;
|
|
|
|
return low;
|
|
#endif
|
|
}
|
|
|
|
// Raises {base} to the power of {exponent}. Does not check for overflow.
|
|
inline JSBigInt::Digit JSBigInt::digitPow(Digit base, Digit exponent)
|
|
{
|
|
Digit result = 1ull;
|
|
while (exponent > 0) {
|
|
if (exponent & 1)
|
|
result *= base;
|
|
|
|
exponent >>= 1;
|
|
base *= base;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Returns the quotient.
|
|
// quotient = (high << digitBits + low - remainder) / divisor
|
|
inline JSBigInt::Digit JSBigInt::digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder)
|
|
{
|
|
ASSERT(high < divisor);
|
|
#if CPU(X86_64) && COMPILER(GCC_COMPATIBLE)
|
|
Digit quotient;
|
|
Digit rem;
|
|
__asm__("divq %[divisor]"
|
|
// Outputs: {quotient} will be in rax, {rem} in rdx.
|
|
: "=a"(quotient), "=d"(rem)
|
|
// Inputs: put {high} into rdx, {low} into rax, and {divisor} into
|
|
// any register or stack slot.
|
|
: "d"(high), "a"(low), [divisor] "rm"(divisor));
|
|
remainder = rem;
|
|
return quotient;
|
|
#elif CPU(X86) && COMPILER(GCC_COMPATIBLE)
|
|
Digit quotient;
|
|
Digit rem;
|
|
__asm__("divl %[divisor]"
|
|
// Outputs: {quotient} will be in eax, {rem} in edx.
|
|
: "=a"(quotient), "=d"(rem)
|
|
// Inputs: put {high} into edx, {low} into eax, and {divisor} into
|
|
// any register or stack slot.
|
|
: "d"(high), "a"(low), [divisor] "rm"(divisor));
|
|
remainder = rem;
|
|
return quotient;
|
|
#else
|
|
static constexpr Digit halfDigitBase = 1ull << halfDigitBits;
|
|
// Adapted from Warren, Hacker's Delight, p. 152.
|
|
unsigned s = clz(divisor);
|
|
// If {s} is digitBits here, it causes an undefined behavior.
|
|
// But {s} is never digitBits since {divisor} is never zero here.
|
|
ASSERT(s != digitBits);
|
|
divisor <<= s;
|
|
|
|
Digit vn1 = divisor >> halfDigitBits;
|
|
Digit vn0 = divisor & halfDigitMask;
|
|
|
|
// {sZeroMask} which is 0 if s == 0 and all 1-bits otherwise.
|
|
// {s} can be 0. If {s} is 0, performing "low >> (digitBits - s)" must not be done since it causes an undefined behavior
|
|
// since `>> digitBits` is undefied in C++. Quoted from C++ spec, "The type of the result is that of the promoted left operand.
|
|
// The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted
|
|
// left operand". We mask the right operand of the shift by {shiftMask} (`digitBits - 1`), which makes `digitBits - 0` zero.
|
|
// This shifting produces a value which covers 0 < {s} <= (digitBits - 1) cases. {s} == digitBits never happen as we asserted.
|
|
// Since {sZeroMask} clears the value in the case of {s} == 0, {s} == 0 case is also covered.
|
|
STATIC_ASSERT(sizeof(CPURegister) == sizeof(Digit));
|
|
Digit sZeroMask = static_cast<Digit>((-static_cast<CPURegister>(s)) >> (digitBits - 1));
|
|
static constexpr unsigned shiftMask = digitBits - 1;
|
|
Digit un32 = (high << s) | ((low >> ((digitBits - s) & shiftMask)) & sZeroMask);
|
|
|
|
Digit un10 = low << s;
|
|
Digit un1 = un10 >> halfDigitBits;
|
|
Digit un0 = un10 & halfDigitMask;
|
|
Digit q1 = un32 / vn1;
|
|
Digit rhat = un32 - q1 * vn1;
|
|
|
|
while (q1 >= halfDigitBase || q1 * vn0 > rhat * halfDigitBase + un1) {
|
|
q1--;
|
|
rhat += vn1;
|
|
if (rhat >= halfDigitBase)
|
|
break;
|
|
}
|
|
|
|
Digit un21 = un32 * halfDigitBase + un1 - q1 * divisor;
|
|
Digit q0 = un21 / vn1;
|
|
rhat = un21 - q0 * vn1;
|
|
|
|
while (q0 >= halfDigitBase || q0 * vn0 > rhat * halfDigitBase + un0) {
|
|
q0--;
|
|
rhat += vn1;
|
|
if (rhat >= halfDigitBase)
|
|
break;
|
|
}
|
|
|
|
remainder = (un21 * halfDigitBase + un0 - q0 * divisor) >> s;
|
|
return q1 * halfDigitBase + q0;
|
|
#endif
|
|
}
|
|
|
|
// Multiplies {source} with {factor} and adds {summand} to the result.
|
|
// {result} and {source} may be the same BigInt for inplace modification.
|
|
void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned n, JSBigInt* result)
|
|
{
|
|
ASSERT(source->length() >= n);
|
|
ASSERT(result->length() >= n);
|
|
|
|
Digit carry = summand;
|
|
Digit high = 0;
|
|
for (unsigned i = 0; i < n; i++) {
|
|
Digit current = source->digit(i);
|
|
Digit newCarry = 0;
|
|
|
|
// Compute this round's multiplication.
|
|
Digit newHigh = 0;
|
|
current = digitMul(current, factor, newHigh);
|
|
|
|
// Add last round's carryovers.
|
|
current = digitAdd(current, high, newCarry);
|
|
current = digitAdd(current, carry, newCarry);
|
|
|
|
// Store result and prepare for next round.
|
|
result->setDigit(i, current);
|
|
carry = newCarry;
|
|
high = newHigh;
|
|
}
|
|
|
|
if (result->length() > n) {
|
|
result->setDigit(n++, carry + high);
|
|
|
|
// Current callers don't pass in such large results, but let's be robust.
|
|
while (n < result->length())
|
|
result->setDigit(n++, 0);
|
|
} else
|
|
ASSERT(!(carry + high));
|
|
}
|
|
|
|
// Multiplies {multiplicand} with {multiplier} and adds the result to
|
|
// {accumulator}, starting at {accumulatorIndex} for the least-significant
|
|
// digit.
|
|
// Callers must ensure that {accumulator} is big enough to hold the result.
|
|
void JSBigInt::multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex)
|
|
{
|
|
ASSERT(accumulator->length() > multiplicand->length() + accumulatorIndex);
|
|
if (!multiplier)
|
|
return;
|
|
|
|
Digit carry = 0;
|
|
Digit high = 0;
|
|
for (unsigned i = 0; i < multiplicand->length(); i++, accumulatorIndex++) {
|
|
Digit acc = accumulator->digit(accumulatorIndex);
|
|
Digit newCarry = 0;
|
|
|
|
// Add last round's carryovers.
|
|
acc = digitAdd(acc, high, newCarry);
|
|
acc = digitAdd(acc, carry, newCarry);
|
|
|
|
// Compute this round's multiplication.
|
|
Digit multiplicandDigit = multiplicand->digit(i);
|
|
Digit low = digitMul(multiplier, multiplicandDigit, high);
|
|
acc = digitAdd(acc, low, newCarry);
|
|
|
|
// Store result and prepare for next round.
|
|
accumulator->setDigit(accumulatorIndex, acc);
|
|
carry = newCarry;
|
|
}
|
|
|
|
while (carry || high) {
|
|
ASSERT(accumulatorIndex < accumulator->length());
|
|
Digit acc = accumulator->digit(accumulatorIndex);
|
|
Digit newCarry = 0;
|
|
acc = digitAdd(acc, high, newCarry);
|
|
high = 0;
|
|
acc = digitAdd(acc, carry, newCarry);
|
|
accumulator->setDigit(accumulatorIndex, acc);
|
|
carry = newCarry;
|
|
accumulatorIndex++;
|
|
}
|
|
}
|
|
|
|
bool JSBigInt::equals(JSBigInt* x, JSBigInt* y)
|
|
{
|
|
if (x->sign() != y->sign())
|
|
return false;
|
|
|
|
if (x->length() != y->length())
|
|
return false;
|
|
|
|
for (unsigned i = 0; i < x->length(); i++) {
|
|
if (x->digit(i) != y->digit(i))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
JSBigInt::ComparisonResult JSBigInt::compare(JSBigInt* x, JSBigInt* y)
|
|
{
|
|
bool xSign = x->sign();
|
|
|
|
if (xSign != y->sign())
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
|
|
ComparisonResult result = absoluteCompare(x, y);
|
|
if (result == ComparisonResult::GreaterThan)
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
if (result == ComparisonResult::LessThan)
|
|
return xSign ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
|
|
return ComparisonResult::Equal;
|
|
}
|
|
|
|
inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigInt* y)
|
|
{
|
|
ASSERT(!x->length() || x->digit(x->length() - 1));
|
|
ASSERT(!y->length() || y->digit(y->length() - 1));
|
|
|
|
int diff = x->length() - y->length();
|
|
if (diff)
|
|
return diff < 0 ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
|
|
int i = x->length() - 1;
|
|
while (i >= 0 && x->digit(i) == y->digit(i))
|
|
i--;
|
|
|
|
if (i < 0)
|
|
return ComparisonResult::Equal;
|
|
|
|
return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteAdd(ExecState* exec, JSBigInt* x, JSBigInt* y, bool resultSign)
|
|
{
|
|
VM& vm = exec->vm();
|
|
|
|
if (x->length() < y->length())
|
|
return absoluteAdd(exec, y, x, resultSign);
|
|
|
|
if (x->isZero()) {
|
|
ASSERT(y->isZero());
|
|
return x;
|
|
}
|
|
|
|
if (y->isZero())
|
|
return resultSign == x->sign() ? x : unaryMinus(vm, x);
|
|
|
|
JSBigInt* result = JSBigInt::tryCreateWithLength(exec, x->length() + 1);
|
|
if (!result)
|
|
return nullptr;
|
|
Digit carry = 0;
|
|
unsigned i = 0;
|
|
for (; i < y->length(); i++) {
|
|
Digit newCarry = 0;
|
|
Digit sum = digitAdd(x->digit(i), y->digit(i), newCarry);
|
|
sum = digitAdd(sum, carry, newCarry);
|
|
result->setDigit(i, sum);
|
|
carry = newCarry;
|
|
}
|
|
|
|
for (; i < x->length(); i++) {
|
|
Digit newCarry = 0;
|
|
Digit sum = digitAdd(x->digit(i), carry, newCarry);
|
|
result->setDigit(i, sum);
|
|
carry = newCarry;
|
|
}
|
|
|
|
result->setDigit(i, carry);
|
|
result->setSign(resultSign);
|
|
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteSub(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSign)
|
|
{
|
|
ComparisonResult comparisonResult = absoluteCompare(x, y);
|
|
ASSERT(x->length() >= y->length());
|
|
ASSERT(comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal);
|
|
|
|
if (x->isZero()) {
|
|
ASSERT(y->isZero());
|
|
return x;
|
|
}
|
|
|
|
if (y->isZero())
|
|
return resultSign == x->sign() ? x : unaryMinus(vm, x);
|
|
|
|
if (comparisonResult == ComparisonResult::Equal)
|
|
return JSBigInt::createZero(vm);
|
|
|
|
JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, x->length());
|
|
|
|
Digit borrow = 0;
|
|
unsigned i = 0;
|
|
for (; i < y->length(); i++) {
|
|
Digit newBorrow = 0;
|
|
Digit difference = digitSub(x->digit(i), y->digit(i), newBorrow);
|
|
difference = digitSub(difference, borrow, newBorrow);
|
|
result->setDigit(i, difference);
|
|
borrow = newBorrow;
|
|
}
|
|
|
|
for (; i < x->length(); i++) {
|
|
Digit newBorrow = 0;
|
|
Digit difference = digitSub(x->digit(i), borrow, newBorrow);
|
|
result->setDigit(i, difference);
|
|
borrow = newBorrow;
|
|
}
|
|
|
|
ASSERT(!borrow);
|
|
result->setSign(resultSign);
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
// Divides {x} by {divisor}, returning the result in {quotient} and {remainder}.
|
|
// Mathematically, the contract is:
|
|
// quotient = (x - remainder) / divisor, with 0 <= remainder < divisor.
|
|
// If {quotient} is an empty handle, an appropriately sized BigInt will be
|
|
// allocated for it; otherwise the caller must ensure that it is big enough.
|
|
// {quotient} can be the same as {x} for an in-place division. {quotient} can
|
|
// also be nullptr if the caller is only interested in the remainder.
|
|
void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder)
|
|
{
|
|
ASSERT(divisor);
|
|
|
|
ASSERT(!x->isZero());
|
|
remainder = 0;
|
|
if (divisor == 1) {
|
|
if (quotient != nullptr)
|
|
*quotient = x;
|
|
return;
|
|
}
|
|
|
|
unsigned length = x->length();
|
|
if (quotient != nullptr) {
|
|
if (*quotient == nullptr)
|
|
*quotient = JSBigInt::createWithLengthUnchecked(vm, length);
|
|
|
|
for (int i = length - 1; i >= 0; i--) {
|
|
Digit q = digitDiv(remainder, x->digit(i), divisor, remainder);
|
|
(*quotient)->setDigit(i, q);
|
|
}
|
|
} else {
|
|
for (int i = length - 1; i >= 0; i--)
|
|
digitDiv(remainder, x->digit(i), divisor, remainder);
|
|
}
|
|
}
|
|
|
|
// Divides {dividend} by {divisor}, returning the result in {quotient} and
|
|
// {remainder}. Mathematically, the contract is:
|
|
// quotient = (dividend - remainder) / divisor, with 0 <= remainder < divisor.
|
|
// Both {quotient} and {remainder} are optional, for callers that are only
|
|
// interested in one of them.
|
|
// See Knuth, Volume 2, section 4.3.1, Algorithm D.
|
|
void JSBigInt::absoluteDivWithBigIntDivisor(ExecState* exec, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder)
|
|
{
|
|
ASSERT(divisor->length() >= 2);
|
|
ASSERT(dividend->length() >= divisor->length());
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
// The unusual variable names inside this function are consistent with
|
|
// Knuth's book, as well as with Go's implementation of this algorithm.
|
|
// Maintaining this consistency is probably more useful than trying to
|
|
// come up with more descriptive names for them.
|
|
unsigned n = divisor->length();
|
|
unsigned m = dividend->length() - n;
|
|
|
|
// The quotient to be computed.
|
|
JSBigInt* q = nullptr;
|
|
if (quotient != nullptr)
|
|
q = createWithLengthUnchecked(exec->vm(), m + 1);
|
|
|
|
// In each iteration, {qhatv} holds {divisor} * {current quotient digit}.
|
|
// "v" is the book's name for {divisor}, "qhat" the current quotient digit.
|
|
JSBigInt* qhatv = tryCreateWithLength(exec, n + 1);
|
|
RETURN_IF_EXCEPTION(scope, void());
|
|
|
|
// D1.
|
|
// Left-shift inputs so that the divisor's MSB is set. This is necessary
|
|
// to prevent the digit-wise divisions (see digit_div call below) from
|
|
// overflowing (they take a two digits wide input, and return a one digit
|
|
// result).
|
|
Digit lastDigit = divisor->digit(n - 1);
|
|
unsigned shift = clz(lastDigit);
|
|
|
|
if (shift > 0) {
|
|
divisor = absoluteLeftShiftAlwaysCopy(exec, divisor, shift, LeftShiftMode::SameSizeResult);
|
|
RETURN_IF_EXCEPTION(scope, void());
|
|
}
|
|
|
|
// Holds the (continuously updated) remaining part of the dividend, which
|
|
// eventually becomes the remainder.
|
|
JSBigInt* u = absoluteLeftShiftAlwaysCopy(exec, dividend, shift, LeftShiftMode::AlwaysAddOneDigit);
|
|
RETURN_IF_EXCEPTION(scope, void());
|
|
|
|
// D2.
|
|
// Iterate over the dividend's digit (like the "grad school" algorithm).
|
|
// {vn1} is the divisor's most significant digit.
|
|
Digit vn1 = divisor->digit(n - 1);
|
|
for (int j = m; j >= 0; j--) {
|
|
// D3.
|
|
// Estimate the current iteration's quotient digit (see Knuth for details).
|
|
// {qhat} is the current quotient digit.
|
|
Digit qhat = std::numeric_limits<Digit>::max();
|
|
|
|
// {ujn} is the dividend's most significant remaining digit.
|
|
Digit ujn = u->digit(j + n);
|
|
if (ujn != vn1) {
|
|
// {rhat} is the current iteration's remainder.
|
|
Digit rhat = 0;
|
|
// Estimate the current quotient digit by dividing the most significant
|
|
// digits of dividend and divisor. The result will not be too small,
|
|
// but could be a bit too large.
|
|
qhat = digitDiv(ujn, u->digit(j + n - 1), vn1, rhat);
|
|
|
|
// Decrement the quotient estimate as needed by looking at the next
|
|
// digit, i.e. by testing whether
|
|
// qhat * v_{n-2} > (rhat << digitBits) + u_{j+n-2}.
|
|
Digit vn2 = divisor->digit(n - 2);
|
|
Digit ujn2 = u->digit(j + n - 2);
|
|
while (productGreaterThan(qhat, vn2, rhat, ujn2)) {
|
|
qhat--;
|
|
Digit prevRhat = rhat;
|
|
rhat += vn1;
|
|
// v[n-1] >= 0, so this tests for overflow.
|
|
if (rhat < prevRhat)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// D4.
|
|
// Multiply the divisor with the current quotient digit, and subtract
|
|
// it from the dividend. If there was "borrow", then the quotient digit
|
|
// was one too high, so we must correct it and undo one subtraction of
|
|
// the (shifted) divisor.
|
|
internalMultiplyAdd(divisor, qhat, 0, n, qhatv);
|
|
Digit c = u->absoluteInplaceSub(qhatv, j);
|
|
if (c) {
|
|
c = u->absoluteInplaceAdd(divisor, j);
|
|
u->setDigit(j + n, u->digit(j + n) + c);
|
|
qhat--;
|
|
}
|
|
|
|
if (quotient != nullptr)
|
|
q->setDigit(j, qhat);
|
|
}
|
|
|
|
if (quotient != nullptr) {
|
|
// Caller will right-trim.
|
|
*quotient = q;
|
|
}
|
|
|
|
if (remainder != nullptr) {
|
|
u->inplaceRightShift(shift);
|
|
*remainder = u;
|
|
}
|
|
}
|
|
|
|
// Returns whether (factor1 * factor2) > (high << digitBits) + low.
|
|
inline bool JSBigInt::productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low)
|
|
{
|
|
Digit resultHigh;
|
|
Digit resultLow = digitMul(factor1, factor2, resultHigh);
|
|
return resultHigh > high || (resultHigh == high && resultLow > low);
|
|
}
|
|
|
|
// Adds {summand} onto {this}, starting with {summand}'s 0th digit
|
|
// at {this}'s {startIndex}'th digit. Returns the "carry" (0 or 1).
|
|
JSBigInt::Digit JSBigInt::absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex)
|
|
{
|
|
Digit carry = 0;
|
|
unsigned n = summand->length();
|
|
ASSERT(length() >= startIndex + n);
|
|
for (unsigned i = 0; i < n; i++) {
|
|
Digit newCarry = 0;
|
|
Digit sum = digitAdd(digit(startIndex + i), summand->digit(i), newCarry);
|
|
sum = digitAdd(sum, carry, newCarry);
|
|
setDigit(startIndex + i, sum);
|
|
carry = newCarry;
|
|
}
|
|
|
|
return carry;
|
|
}
|
|
|
|
// Subtracts {subtrahend} from {this}, starting with {subtrahend}'s 0th digit
|
|
// at {this}'s {startIndex}-th digit. Returns the "borrow" (0 or 1).
|
|
JSBigInt::Digit JSBigInt::absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex)
|
|
{
|
|
Digit borrow = 0;
|
|
unsigned n = subtrahend->length();
|
|
ASSERT(length() >= startIndex + n);
|
|
for (unsigned i = 0; i < n; i++) {
|
|
Digit newBorrow = 0;
|
|
Digit difference = digitSub(digit(startIndex + i), subtrahend->digit(i), newBorrow);
|
|
difference = digitSub(difference, borrow, newBorrow);
|
|
setDigit(startIndex + i, difference);
|
|
borrow = newBorrow;
|
|
}
|
|
|
|
return borrow;
|
|
}
|
|
|
|
void JSBigInt::inplaceRightShift(unsigned shift)
|
|
{
|
|
ASSERT(shift < digitBits);
|
|
ASSERT(!(digit(0) & ((static_cast<Digit>(1) << shift) - 1)));
|
|
|
|
if (!shift)
|
|
return;
|
|
|
|
Digit carry = digit(0) >> shift;
|
|
unsigned last = length() - 1;
|
|
for (unsigned i = 0; i < last; i++) {
|
|
Digit d = digit(i + 1);
|
|
setDigit(i, (d << (digitBits - shift)) | carry);
|
|
carry = d >> shift;
|
|
}
|
|
setDigit(last, carry);
|
|
}
|
|
|
|
// Always copies the input, even when {shift} == 0.
|
|
JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(ExecState* exec, JSBigInt* x, unsigned shift, LeftShiftMode mode)
|
|
{
|
|
ASSERT(shift < digitBits);
|
|
ASSERT(!x->isZero());
|
|
|
|
unsigned n = x->length();
|
|
unsigned resultLength = mode == LeftShiftMode::AlwaysAddOneDigit ? n + 1 : n;
|
|
JSBigInt* result = tryCreateWithLength(exec, resultLength);
|
|
if (!result)
|
|
return nullptr;
|
|
|
|
if (!shift) {
|
|
for (unsigned i = 0; i < n; i++)
|
|
result->setDigit(i, x->digit(i));
|
|
if (mode == LeftShiftMode::AlwaysAddOneDigit)
|
|
result->setDigit(n, 0);
|
|
|
|
return result;
|
|
}
|
|
|
|
Digit carry = 0;
|
|
for (unsigned i = 0; i < n; i++) {
|
|
Digit d = x->digit(i);
|
|
result->setDigit(i, (d << shift) | carry);
|
|
carry = d >> (digitBits - shift);
|
|
}
|
|
|
|
if (mode == LeftShiftMode::AlwaysAddOneDigit)
|
|
result->setDigit(n, carry);
|
|
else {
|
|
ASSERT(mode == LeftShiftMode::SameSizeResult);
|
|
ASSERT(!carry);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Helper for Absolute{And,AndNot,Or,Xor}.
|
|
// Performs the given binary {op} on digit pairs of {x} and {y}; when the
|
|
// end of the shorter of the two is reached, {extraDigits} configures how
|
|
// remaining digits in the longer input (if {symmetric} == Symmetric, in
|
|
// {x} otherwise) are handled: copied to the result or ignored.
|
|
// Example:
|
|
// y: [ y2 ][ y1 ][ y0 ]
|
|
// x: [ x3 ][ x2 ][ x1 ][ x0 ]
|
|
// | | | |
|
|
// (Copy) (op) (op) (op)
|
|
// | | | |
|
|
// v v v v
|
|
// result: [ 0 ][ x3 ][ r2 ][ r1 ][ r0 ]
|
|
template<typename BitwiseOp>
|
|
inline JSBigInt* JSBigInt::absoluteBitwiseOp(VM& vm, JSBigInt* x, JSBigInt* y, ExtraDigitsHandling extraDigits, SymmetricOp symmetric, BitwiseOp&& op)
|
|
{
|
|
unsigned xLength = x->length();
|
|
unsigned yLength = y->length();
|
|
unsigned numPairs = yLength;
|
|
if (xLength < yLength) {
|
|
numPairs = xLength;
|
|
if (symmetric == SymmetricOp::Symmetric) {
|
|
std::swap(x, y);
|
|
std::swap(xLength, yLength);
|
|
}
|
|
}
|
|
|
|
ASSERT(numPairs == std::min(xLength, yLength));
|
|
unsigned resultLength = extraDigits == ExtraDigitsHandling::Copy ? xLength : numPairs;
|
|
JSBigInt* result = createWithLengthUnchecked(vm, resultLength);
|
|
unsigned i = 0;
|
|
for (; i < numPairs; i++)
|
|
result->setDigit(i, op(x->digit(i), y->digit(i)));
|
|
|
|
if (extraDigits == ExtraDigitsHandling::Copy) {
|
|
for (; i < xLength; i++)
|
|
result->setDigit(i, x->digit(i));
|
|
}
|
|
|
|
for (; i < resultLength; i++)
|
|
result->setDigit(i, 0);
|
|
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteAnd(VM& vm, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
auto digitOperation = [](Digit a, Digit b) {
|
|
return a & b;
|
|
};
|
|
return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Skip, SymmetricOp::Symmetric, digitOperation);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteOr(VM& vm, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
auto digitOperation = [](Digit a, Digit b) {
|
|
return a | b;
|
|
};
|
|
return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Copy, SymmetricOp::Symmetric, digitOperation);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteAndNot(VM& vm, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
auto digitOperation = [](Digit a, Digit b) {
|
|
return a & ~b;
|
|
};
|
|
return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Copy, SymmetricOp::NotSymmetric, digitOperation);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteXor(VM& vm, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
auto digitOperation = [](Digit a, Digit b) {
|
|
return a ^ b;
|
|
};
|
|
return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Copy, SymmetricOp::Symmetric, digitOperation);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteAddOne(ExecState* exec, JSBigInt* x, SignOption signOption)
|
|
{
|
|
unsigned inputLength = x->length();
|
|
// The addition will overflow into a new digit if all existing digits are
|
|
// at maximum.
|
|
bool willOverflow = true;
|
|
for (unsigned i = 0; i < inputLength; i++) {
|
|
if (std::numeric_limits<Digit>::max() != x->digit(i)) {
|
|
willOverflow = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned resultLength = inputLength + willOverflow;
|
|
JSBigInt* result = tryCreateWithLength(exec, resultLength);
|
|
if (!result)
|
|
return nullptr;
|
|
|
|
Digit carry = 1;
|
|
for (unsigned i = 0; i < inputLength; i++) {
|
|
Digit newCarry = 0;
|
|
result->setDigit(i, digitAdd(x->digit(i), carry, newCarry));
|
|
carry = newCarry;
|
|
}
|
|
if (resultLength > inputLength)
|
|
result->setDigit(inputLength, carry);
|
|
else
|
|
ASSERT(!carry);
|
|
|
|
result->setSign(signOption == SignOption::Signed);
|
|
return result->rightTrim(exec->vm());
|
|
}
|
|
|
|
JSBigInt* JSBigInt::absoluteSubOne(ExecState* exec, JSBigInt* x, unsigned resultLength)
|
|
{
|
|
ASSERT(!x->isZero());
|
|
ASSERT(resultLength >= x->length());
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
JSBigInt* result = tryCreateWithLength(exec, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
unsigned length = x->length();
|
|
Digit borrow = 1;
|
|
for (unsigned i = 0; i < length; i++) {
|
|
Digit newBorrow = 0;
|
|
result->setDigit(i, digitSub(x->digit(i), borrow, newBorrow));
|
|
borrow = newBorrow;
|
|
}
|
|
ASSERT(!borrow);
|
|
for (unsigned i = length; i < resultLength; i++)
|
|
result->setDigit(i, borrow);
|
|
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::leftShiftByAbsolute(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
auto optionalShift = toShiftAmount(y);
|
|
if (!optionalShift) {
|
|
throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s);
|
|
return nullptr;
|
|
}
|
|
|
|
Digit shift = *optionalShift;
|
|
unsigned digitShift = static_cast<unsigned>(shift / digitBits);
|
|
unsigned bitsShift = static_cast<unsigned>(shift % digitBits);
|
|
unsigned length = x->length();
|
|
bool grow = bitsShift && (x->digit(length - 1) >> (digitBits - bitsShift));
|
|
int resultLength = length + digitShift + grow;
|
|
if (static_cast<unsigned>(resultLength) > maxLength) {
|
|
throwRangeError(exec, scope, "BigInt generated from this operation is too big"_s);
|
|
return nullptr;
|
|
}
|
|
|
|
JSBigInt* result = tryCreateWithLength(exec, resultLength);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
if (!bitsShift) {
|
|
unsigned i = 0;
|
|
for (; i < digitShift; i++)
|
|
result->setDigit(i, 0ul);
|
|
|
|
for (; i < static_cast<unsigned>(resultLength); i++)
|
|
result->setDigit(i, x->digit(i - digitShift));
|
|
} else {
|
|
Digit carry = 0;
|
|
for (unsigned i = 0; i < digitShift; i++)
|
|
result->setDigit(i, 0ul);
|
|
|
|
for (unsigned i = 0; i < length; i++) {
|
|
Digit d = x->digit(i);
|
|
result->setDigit(i + digitShift, (d << bitsShift) | carry);
|
|
carry = d >> (digitBits - bitsShift);
|
|
}
|
|
|
|
if (grow)
|
|
result->setDigit(length + digitShift, carry);
|
|
else
|
|
ASSERT(!carry);
|
|
}
|
|
|
|
result->setSign(x->sign());
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::rightShiftByAbsolute(ExecState* exec, JSBigInt* x, JSBigInt* y)
|
|
{
|
|
VM& vm = exec->vm();
|
|
unsigned length = x->length();
|
|
bool sign = x->sign();
|
|
auto optionalShift = toShiftAmount(y);
|
|
if (!optionalShift)
|
|
return rightShiftByMaximum(vm, sign);
|
|
|
|
Digit shift = *optionalShift;
|
|
unsigned digitalShift = static_cast<unsigned>(shift / digitBits);
|
|
unsigned bitsShift = static_cast<unsigned>(shift % digitBits);
|
|
int resultLength = length - digitalShift;
|
|
if (resultLength <= 0)
|
|
return rightShiftByMaximum(vm, sign);
|
|
|
|
// For negative numbers, round down if any bit was shifted out (so that e.g.
|
|
// -5n >> 1n == -3n and not -2n). Check now whether this will happen and
|
|
// whether it can cause overflow into a new digit. If we allocate the result
|
|
// large enough up front, it avoids having to do a second allocation later.
|
|
bool mustRoundDown = false;
|
|
if (sign) {
|
|
const Digit mask = (static_cast<Digit>(1) << bitsShift) - 1;
|
|
if (x->digit(digitalShift) & mask)
|
|
mustRoundDown = true;
|
|
else {
|
|
for (unsigned i = 0; i < digitalShift; i++) {
|
|
if (x->digit(i)) {
|
|
mustRoundDown = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If bitsShift is non-zero, it frees up bits, preventing overflow.
|
|
if (mustRoundDown && !bitsShift) {
|
|
// Overflow cannot happen if the most significant digit has unset bits.
|
|
Digit msd = x->digit(length - 1);
|
|
bool roundingCanOverflow = !static_cast<Digit>(~msd);
|
|
if (roundingCanOverflow)
|
|
resultLength++;
|
|
}
|
|
|
|
ASSERT(static_cast<unsigned>(resultLength) <= length);
|
|
JSBigInt* result = createWithLengthUnchecked(vm, static_cast<unsigned>(resultLength));
|
|
if (!bitsShift) {
|
|
for (unsigned i = digitalShift; i < length; i++)
|
|
result->setDigit(i - digitalShift, x->digit(i));
|
|
} else {
|
|
Digit carry = x->digit(digitalShift) >> bitsShift;
|
|
unsigned last = length - digitalShift - 1;
|
|
for (unsigned i = 0; i < last; i++) {
|
|
Digit d = x->digit(i + digitalShift + 1);
|
|
result->setDigit(i, (d << (digitBits - bitsShift)) | carry);
|
|
carry = d >> bitsShift;
|
|
}
|
|
result->setDigit(last, carry);
|
|
}
|
|
|
|
if (sign) {
|
|
result->setSign(true);
|
|
if (mustRoundDown) {
|
|
// Since the result is negative, rounding down means adding one to
|
|
// its absolute value. This cannot overflow.
|
|
result = result->rightTrim(vm);
|
|
return absoluteAddOne(exec, result, SignOption::Signed);
|
|
}
|
|
}
|
|
|
|
return result->rightTrim(vm);
|
|
}
|
|
|
|
JSBigInt* JSBigInt::rightShiftByMaximum(VM& vm, bool sign)
|
|
{
|
|
if (sign)
|
|
return createFrom(vm, -1);
|
|
|
|
return createZero(vm);
|
|
}
|
|
|
|
// Lookup table for the maximum number of bits required per character of a
|
|
// base-N string representation of a number. To increase accuracy, the array
|
|
// value is the actual value multiplied by 32. To generate this table:
|
|
// for (var i = 0; i <= 36; i++) { print(Math.ceil(Math.log2(i) * 32) + ","); }
|
|
constexpr uint8_t maxBitsPerCharTable[] = {
|
|
0, 0, 32, 51, 64, 75, 83, 90, 96, // 0..8
|
|
102, 107, 111, 115, 119, 122, 126, 128, // 9..16
|
|
131, 134, 136, 139, 141, 143, 145, 147, // 17..24
|
|
149, 151, 153, 154, 156, 158, 159, 160, // 25..32
|
|
162, 163, 165, 166, // 33..36
|
|
};
|
|
|
|
static constexpr unsigned bitsPerCharTableShift = 5;
|
|
static constexpr size_t bitsPerCharTableMultiplier = 1u << bitsPerCharTableShift;
|
|
|
|
// Compute (an overapproximation of) the length of the resulting string:
|
|
// Divide bit length of the BigInt by bits representable per character.
|
|
uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign)
|
|
{
|
|
unsigned leadingZeros = clz(lastDigit);
|
|
|
|
size_t bitLength = length * digitBits - leadingZeros;
|
|
|
|
// Maximum number of bits we can represent with one character. We'll use this
|
|
// to find an appropriate chunk size below.
|
|
uint8_t maxBitsPerChar = maxBitsPerCharTable[radix];
|
|
|
|
// For estimating result length, we have to be pessimistic and work with
|
|
// the minimum number of bits one character can represent.
|
|
uint8_t minBitsPerChar = maxBitsPerChar - 1;
|
|
|
|
// Perform the following computation with uint64_t to avoid overflows.
|
|
uint64_t maximumCharactersRequired = bitLength;
|
|
maximumCharactersRequired *= bitsPerCharTableMultiplier;
|
|
|
|
// Round up.
|
|
maximumCharactersRequired += minBitsPerChar - 1;
|
|
maximumCharactersRequired /= minBitsPerChar;
|
|
maximumCharactersRequired += sign;
|
|
|
|
return maximumCharactersRequired;
|
|
}
|
|
|
|
String JSBigInt::toStringBasePowerOfTwo(ExecState* exec, JSBigInt* x, unsigned radix)
|
|
{
|
|
ASSERT(hasOneBitSet(radix));
|
|
ASSERT(radix >= 2 && radix <= 32);
|
|
ASSERT(!x->isZero());
|
|
VM& vm = exec->vm();
|
|
|
|
const unsigned length = x->length();
|
|
const bool sign = x->sign();
|
|
const unsigned bitsPerChar = ctz(radix);
|
|
const unsigned charMask = radix - 1;
|
|
// Compute the length of the resulting string: divide the bit length of the
|
|
// BigInt by the number of bits representable per character (rounding up).
|
|
const Digit msd = x->digit(length - 1);
|
|
|
|
const unsigned msdLeadingZeros = clz(msd);
|
|
|
|
const size_t bitLength = length * digitBits - msdLeadingZeros;
|
|
const size_t charsRequired = (bitLength + bitsPerChar - 1) / bitsPerChar + sign;
|
|
|
|
if (charsRequired > JSString::MaxLength) {
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
throwOutOfMemoryError(exec, scope);
|
|
return String();
|
|
}
|
|
|
|
Vector<LChar> resultString(charsRequired);
|
|
Digit digit = 0;
|
|
// Keeps track of how many unprocessed bits there are in {digit}.
|
|
unsigned availableBits = 0;
|
|
int pos = static_cast<int>(charsRequired - 1);
|
|
for (unsigned i = 0; i < length - 1; i++) {
|
|
Digit newDigit = x->digit(i);
|
|
// Take any leftover bits from the last iteration into account.
|
|
int current = (digit | (newDigit << availableBits)) & charMask;
|
|
resultString[pos--] = radixDigits[current];
|
|
int consumedBits = bitsPerChar - availableBits;
|
|
digit = newDigit >> consumedBits;
|
|
availableBits = digitBits - consumedBits;
|
|
while (availableBits >= bitsPerChar) {
|
|
resultString[pos--] = radixDigits[digit & charMask];
|
|
digit >>= bitsPerChar;
|
|
availableBits -= bitsPerChar;
|
|
}
|
|
}
|
|
// Take any leftover bits from the last iteration into account.
|
|
int current = (digit | (msd << availableBits)) & charMask;
|
|
resultString[pos--] = radixDigits[current];
|
|
digit = msd >> (bitsPerChar - availableBits);
|
|
while (digit) {
|
|
resultString[pos--] = radixDigits[digit & charMask];
|
|
digit >>= bitsPerChar;
|
|
}
|
|
|
|
if (sign)
|
|
resultString[pos--] = '-';
|
|
|
|
ASSERT(pos == -1);
|
|
return StringImpl::adopt(WTFMove(resultString));
|
|
}
|
|
|
|
String JSBigInt::toStringGeneric(ExecState* exec, JSBigInt* x, unsigned radix)
|
|
{
|
|
// FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString
|
|
// https://bugs.webkit.org/show_bug.cgi?id=18067
|
|
Vector<LChar> resultString;
|
|
|
|
VM& vm = exec->vm();
|
|
|
|
ASSERT(radix >= 2 && radix <= 36);
|
|
ASSERT(!x->isZero());
|
|
|
|
unsigned length = x->length();
|
|
bool sign = x->sign();
|
|
|
|
uint8_t maxBitsPerChar = maxBitsPerCharTable[radix];
|
|
uint64_t maximumCharactersRequired = calculateMaximumCharactersRequired(length, radix, x->digit(length - 1), sign);
|
|
|
|
if (maximumCharactersRequired > JSString::MaxLength) {
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
throwOutOfMemoryError(exec, scope);
|
|
return String();
|
|
}
|
|
|
|
Digit lastDigit;
|
|
if (length == 1)
|
|
lastDigit = x->digit(0);
|
|
else {
|
|
unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
|
|
Digit chunkDivisor = digitPow(radix, chunkChars);
|
|
|
|
// By construction of chunkChars, there can't have been overflow.
|
|
ASSERT(chunkDivisor);
|
|
unsigned nonZeroDigit = length - 1;
|
|
ASSERT(x->digit(nonZeroDigit));
|
|
|
|
// {rest} holds the part of the BigInt that we haven't looked at yet.
|
|
// Not to be confused with "remainder"!
|
|
JSBigInt* rest = nullptr;
|
|
|
|
// In the first round, divide the input, allocating a new BigInt for
|
|
// the result == rest; from then on divide the rest in-place.
|
|
JSBigInt** dividend = &x;
|
|
do {
|
|
Digit chunk;
|
|
absoluteDivWithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk);
|
|
dividend = &rest;
|
|
for (unsigned i = 0; i < chunkChars; i++) {
|
|
resultString.append(radixDigits[chunk % radix]);
|
|
chunk /= radix;
|
|
}
|
|
ASSERT(!chunk);
|
|
|
|
if (!rest->digit(nonZeroDigit))
|
|
nonZeroDigit--;
|
|
|
|
// We can never clear more than one digit per iteration, because
|
|
// chunkDivisor is smaller than max digit value.
|
|
ASSERT(rest->digit(nonZeroDigit));
|
|
} while (nonZeroDigit > 0);
|
|
|
|
lastDigit = rest->digit(0);
|
|
}
|
|
|
|
do {
|
|
resultString.append(radixDigits[lastDigit % radix]);
|
|
lastDigit /= radix;
|
|
} while (lastDigit > 0);
|
|
ASSERT(resultString.size());
|
|
ASSERT(resultString.size() <= static_cast<size_t>(maximumCharactersRequired));
|
|
|
|
// Remove leading zeroes.
|
|
unsigned newSizeNoLeadingZeroes = resultString.size();
|
|
while (newSizeNoLeadingZeroes > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0')
|
|
newSizeNoLeadingZeroes--;
|
|
|
|
resultString.shrink(newSizeNoLeadingZeroes);
|
|
|
|
if (sign)
|
|
resultString.append('-');
|
|
|
|
std::reverse(resultString.begin(), resultString.end());
|
|
|
|
return StringImpl::adopt(WTFMove(resultString));
|
|
}
|
|
|
|
JSBigInt* JSBigInt::rightTrim(VM& vm)
|
|
{
|
|
if (isZero()) {
|
|
ASSERT(!sign());
|
|
return this;
|
|
}
|
|
|
|
int nonZeroIndex = m_length - 1;
|
|
while (nonZeroIndex >= 0 && !digit(nonZeroIndex))
|
|
nonZeroIndex--;
|
|
|
|
if (nonZeroIndex < 0)
|
|
return createZero(vm);
|
|
|
|
if (nonZeroIndex == static_cast<int>(m_length - 1))
|
|
return this;
|
|
|
|
unsigned newLength = nonZeroIndex + 1;
|
|
JSBigInt* trimmedBigInt = createWithLengthUnchecked(vm, newLength);
|
|
std::copy(dataStorage(), dataStorage() + newLength, trimmedBigInt->dataStorage());
|
|
|
|
trimmedBigInt->setSign(this->sign());
|
|
|
|
return trimmedBigInt;
|
|
}
|
|
|
|
JSBigInt* JSBigInt::allocateFor(ExecState* exec, VM& vm, unsigned radix, unsigned charcount)
|
|
{
|
|
ASSERT(2 <= radix && radix <= 36);
|
|
|
|
size_t bitsPerChar = maxBitsPerCharTable[radix];
|
|
size_t chars = charcount;
|
|
const unsigned roundup = bitsPerCharTableMultiplier - 1;
|
|
if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) {
|
|
size_t bitsMin = bitsPerChar * chars;
|
|
|
|
// Divide by 32 (see table), rounding up.
|
|
bitsMin = (bitsMin + roundup) >> bitsPerCharTableShift;
|
|
if (bitsMin <= static_cast<size_t>(maxInt)) {
|
|
// Divide by kDigitsBits, rounding up.
|
|
unsigned length = (bitsMin + digitBits - 1) / digitBits;
|
|
if (length <= maxLength) {
|
|
JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, length);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (exec) {
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
throwOutOfMemoryError(exec, scope);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
size_t JSBigInt::estimatedSize(JSCell* cell, VM& vm)
|
|
{
|
|
return Base::estimatedSize(cell, vm) + jsCast<JSBigInt*>(cell)->m_length * sizeof(Digit);
|
|
}
|
|
|
|
double JSBigInt::toNumber(ExecState* exec) const
|
|
{
|
|
VM& vm = exec->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
throwTypeError(exec, scope, "Conversion from 'BigInt' to 'number' is not allowed."_s);
|
|
return 0.0;
|
|
}
|
|
|
|
bool JSBigInt::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
|
|
{
|
|
result = this;
|
|
number = toNumber(exec);
|
|
return true;
|
|
}
|
|
|
|
template <typename CharType>
|
|
JSBigInt* JSBigInt::parseInt(ExecState* exec, CharType* data, unsigned length, ErrorParseMode errorParseMode)
|
|
{
|
|
VM& vm = exec->vm();
|
|
|
|
unsigned p = 0;
|
|
while (p < length && isStrWhiteSpace(data[p]))
|
|
++p;
|
|
|
|
// Check Radix from frist characters
|
|
if (static_cast<unsigned>(p) + 1 < static_cast<unsigned>(length) && data[p] == '0') {
|
|
if (isASCIIAlphaCaselessEqual(data[p + 1], 'b'))
|
|
return parseInt(exec, vm, data, length, p + 2, 2, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
|
|
|
|
if (isASCIIAlphaCaselessEqual(data[p + 1], 'x'))
|
|
return parseInt(exec, vm, data, length, p + 2, 16, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
|
|
|
|
if (isASCIIAlphaCaselessEqual(data[p + 1], 'o'))
|
|
return parseInt(exec, vm, data, length, p + 2, 8, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
|
|
}
|
|
|
|
ParseIntSign sign = ParseIntSign::Unsigned;
|
|
if (p < length) {
|
|
if (data[p] == '+')
|
|
++p;
|
|
else if (data[p] == '-') {
|
|
sign = ParseIntSign::Signed;
|
|
++p;
|
|
}
|
|
}
|
|
|
|
JSBigInt* result = parseInt(exec, vm, data, length, p, 10, errorParseMode, sign);
|
|
|
|
if (result && !result->isZero())
|
|
result->setSign(sign == ParseIntSign::Signed);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename CharType>
|
|
JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode)
|
|
{
|
|
ASSERT(length >= 0);
|
|
unsigned p = startIndex;
|
|
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
if (parseMode != ParseIntMode::AllowEmptyString && startIndex == length) {
|
|
ASSERT(exec);
|
|
if (errorParseMode == ErrorParseMode::ThrowExceptions)
|
|
throwVMError(exec, scope, createSyntaxError(exec, "Failed to parse String to BigInt"));
|
|
return nullptr;
|
|
}
|
|
|
|
// Skipping leading zeros
|
|
while (p < length && data[p] == '0')
|
|
++p;
|
|
|
|
int endIndex = length - 1;
|
|
// Removing trailing spaces
|
|
while (endIndex >= static_cast<int>(p) && isStrWhiteSpace(data[endIndex]))
|
|
--endIndex;
|
|
|
|
length = endIndex + 1;
|
|
|
|
if (p == length)
|
|
return createZero(vm);
|
|
|
|
unsigned limit0 = '0' + (radix < 10 ? radix : 10);
|
|
unsigned limita = 'a' + (radix - 10);
|
|
unsigned limitA = 'A' + (radix - 10);
|
|
|
|
JSBigInt* result = allocateFor(exec, vm, radix, length - p);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
|
|
result->initialize(InitializationType::WithZero);
|
|
|
|
for (unsigned i = p; i < length; i++, p++) {
|
|
uint32_t digit;
|
|
if (data[i] >= '0' && data[i] < limit0)
|
|
digit = data[i] - '0';
|
|
else if (data[i] >= 'a' && data[i] < limita)
|
|
digit = data[i] - 'a' + 10;
|
|
else if (data[i] >= 'A' && data[i] < limitA)
|
|
digit = data[i] - 'A' + 10;
|
|
else
|
|
break;
|
|
|
|
result->inplaceMultiplyAdd(static_cast<Digit>(radix), static_cast<Digit>(digit));
|
|
}
|
|
|
|
result->setSign(sign == ParseIntSign::Signed ? true : false);
|
|
if (p == length)
|
|
return result->rightTrim(vm);
|
|
|
|
ASSERT(exec);
|
|
if (errorParseMode == ErrorParseMode::ThrowExceptions)
|
|
throwVMError(exec, scope, createSyntaxError(exec, "Failed to parse String to BigInt"));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
JSObject* JSBigInt::toObject(ExecState* exec, JSGlobalObject* globalObject) const
|
|
{
|
|
return BigIntObject::create(exec->vm(), globalObject, const_cast<JSBigInt*>(this));
|
|
}
|
|
|
|
bool JSBigInt::equalsToNumber(JSValue numValue)
|
|
{
|
|
ASSERT(numValue.isNumber());
|
|
|
|
if (numValue.isInt32()) {
|
|
int value = numValue.asInt32();
|
|
if (!value)
|
|
return this->isZero();
|
|
|
|
return (this->length() == 1) && (this->sign() == (value < 0)) && (this->digit(0) == static_cast<Digit>(std::abs(static_cast<int64_t>(value))));
|
|
}
|
|
|
|
double value = numValue.asDouble();
|
|
return compareToDouble(this, value) == ComparisonResult::Equal;
|
|
}
|
|
|
|
JSBigInt::ComparisonResult JSBigInt::compareToDouble(JSBigInt* x, double y)
|
|
{
|
|
// This algorithm expect that the double format is IEEE 754
|
|
|
|
uint64_t doubleBits = bitwise_cast<uint64_t>(y);
|
|
int rawExponent = static_cast<int>(doubleBits >> 52) & 0x7FF;
|
|
|
|
if (rawExponent == 0x7FF) {
|
|
if (std::isnan(y))
|
|
return ComparisonResult::Undefined;
|
|
|
|
return (y == std::numeric_limits<double>::infinity()) ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
}
|
|
|
|
bool xSign = x->sign();
|
|
|
|
// Note that this is different from the double's sign bit for -0. That's
|
|
// intentional because -0 must be treated like 0.
|
|
bool ySign = y < 0;
|
|
if (xSign != ySign)
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
|
|
if (!y) {
|
|
ASSERT(!xSign);
|
|
return x->isZero() ? ComparisonResult::Equal : ComparisonResult::GreaterThan;
|
|
}
|
|
|
|
if (x->isZero())
|
|
return ComparisonResult::LessThan;
|
|
|
|
uint64_t mantissa = doubleBits & 0x000FFFFFFFFFFFFF;
|
|
|
|
// Non-finite doubles are handled above.
|
|
ASSERT(rawExponent != 0x7FF);
|
|
int exponent = rawExponent - 0x3FF;
|
|
if (exponent < 0) {
|
|
// The absolute value of the double is less than 1. Only 0n has an
|
|
// absolute value smaller than that, but we've already covered that case.
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
}
|
|
|
|
int xLength = x->length();
|
|
Digit xMSD = x->digit(xLength - 1);
|
|
int msdLeadingZeros = clz(xMSD);
|
|
|
|
int xBitLength = xLength * digitBits - msdLeadingZeros;
|
|
int yBitLength = exponent + 1;
|
|
if (xBitLength < yBitLength)
|
|
return xSign? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
|
|
if (xBitLength > yBitLength)
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
|
|
// At this point, we know that signs and bit lengths (i.e. position of
|
|
// the most significant bit in exponent-free representation) are identical.
|
|
// {x} is not zero, {y} is finite and not denormal.
|
|
// Now we virtually convert the double to an integer by shifting its
|
|
// mantissa according to its exponent, so it will align with the BigInt {x},
|
|
// and then we compare them bit for bit until we find a difference or the
|
|
// least significant bit.
|
|
// <----- 52 ------> <-- virtual trailing zeroes -->
|
|
// y / mantissa: 1yyyyyyyyyyyyyyyyy 0000000000000000000000000000000
|
|
// x / digits: 0001xxxx xxxxxxxx xxxxxxxx ...
|
|
// <--> <------>
|
|
// msdTopBit digitBits
|
|
//
|
|
mantissa |= 0x0010000000000000;
|
|
const int mantissaTopBit = 52; // 0-indexed.
|
|
|
|
// 0-indexed position of {x}'s most significant bit within the {msd}.
|
|
int msdTopBit = digitBits - 1 - msdLeadingZeros;
|
|
ASSERT(msdTopBit == static_cast<int>((xBitLength - 1) % digitBits));
|
|
|
|
// Shifted chunk of {mantissa} for comparing with {digit}.
|
|
Digit compareMantissa;
|
|
|
|
// Number of unprocessed bits in {mantissa}. We'll keep them shifted to
|
|
// the left (i.e. most significant part) of the underlying uint64_t.
|
|
int remainingMantissaBits = 0;
|
|
|
|
// First, compare the most significant digit against the beginning of
|
|
// the mantissa and then we align them.
|
|
if (msdTopBit < mantissaTopBit) {
|
|
remainingMantissaBits = (mantissaTopBit - msdTopBit);
|
|
compareMantissa = static_cast<Digit>(mantissa >> remainingMantissaBits);
|
|
mantissa = mantissa << (64 - remainingMantissaBits);
|
|
} else {
|
|
compareMantissa = static_cast<Digit>(mantissa << (msdTopBit - mantissaTopBit));
|
|
mantissa = 0;
|
|
}
|
|
|
|
if (xMSD > compareMantissa)
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
|
|
if (xMSD < compareMantissa)
|
|
return xSign ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
|
|
// Then, compare additional digits against any remaining mantissa bits.
|
|
for (int digitIndex = xLength - 2; digitIndex >= 0; digitIndex--) {
|
|
if (remainingMantissaBits > 0) {
|
|
remainingMantissaBits -= digitBits;
|
|
if (sizeof(mantissa) != sizeof(xMSD)) {
|
|
compareMantissa = static_cast<Digit>(mantissa >> (64 - digitBits));
|
|
// "& 63" to appease compilers. digitBits is 32 here anyway.
|
|
mantissa = mantissa << (digitBits & 63);
|
|
} else {
|
|
compareMantissa = static_cast<Digit>(mantissa);
|
|
mantissa = 0;
|
|
}
|
|
} else
|
|
compareMantissa = 0;
|
|
|
|
Digit digit = x->digit(digitIndex);
|
|
if (digit > compareMantissa)
|
|
return xSign ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;
|
|
if (digit < compareMantissa)
|
|
return xSign ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
}
|
|
|
|
// Integer parts are equal; check whether {y} has a fractional part.
|
|
if (mantissa) {
|
|
ASSERT(remainingMantissaBits > 0);
|
|
return xSign ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
|
|
}
|
|
|
|
return ComparisonResult::Equal;
|
|
}
|
|
|
|
Optional<JSBigInt::Digit> JSBigInt::toShiftAmount(JSBigInt* x)
|
|
{
|
|
if (x->length() > 1)
|
|
return WTF::nullopt;
|
|
|
|
Digit value = x->digit(0);
|
|
static_assert(maxLengthBits < std::numeric_limits<Digit>::max(), "maxLengthBits needs to be less than digit");
|
|
|
|
if (value > maxLengthBits)
|
|
return WTF::nullopt;
|
|
|
|
return value;
|
|
}
|
|
|
|
} // namespace JSC
|