mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2025-04-16 13:59:53 +00:00
259 lines
9.8 KiB
C++
259 lines
9.8 KiB
C++
/*
|
|
* Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
|
|
*
|
|
* 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 "ExceptionHelpers.h"
|
|
#include "JSObject.h"
|
|
#include <wtf/CagedPtr.h>
|
|
#include <wtf/text/StringBuilder.h>
|
|
#include <wtf/text/StringView.h>
|
|
#include <wtf/text/WTFString.h>
|
|
|
|
namespace JSC {
|
|
|
|
class JSBigInt final : public JSCell {
|
|
using Base = JSCell;
|
|
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal | OverridesToThis;
|
|
friend class CachedBigInt;
|
|
|
|
public:
|
|
|
|
JSBigInt(VM&, Structure*, unsigned length);
|
|
|
|
enum class InitializationType { None, WithZero };
|
|
void initialize(InitializationType);
|
|
|
|
static size_t estimatedSize(JSCell*, VM&);
|
|
|
|
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
|
|
static JSBigInt* createZero(VM&);
|
|
static JSBigInt* tryCreateWithLength(ExecState*, unsigned length);
|
|
static JSBigInt* createWithLengthUnchecked(VM&, unsigned length);
|
|
|
|
static JSBigInt* createFrom(VM&, int32_t value);
|
|
static JSBigInt* createFrom(VM&, uint32_t value);
|
|
static JSBigInt* createFrom(VM&, int64_t value);
|
|
static JSBigInt* createFrom(VM&, bool value);
|
|
|
|
static size_t offsetOfLength()
|
|
{
|
|
return OBJECT_OFFSETOF(JSBigInt, m_length);
|
|
}
|
|
|
|
DECLARE_EXPORT_INFO;
|
|
|
|
JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
|
|
|
|
void setSign(bool sign) { m_sign = sign; }
|
|
bool sign() const { return m_sign; }
|
|
|
|
void setLength(unsigned length) { m_length = length; }
|
|
unsigned length() const { return m_length; }
|
|
|
|
enum class ErrorParseMode {
|
|
ThrowExceptions,
|
|
IgnoreExceptions
|
|
};
|
|
|
|
enum class ParseIntMode { DisallowEmptyString, AllowEmptyString };
|
|
enum class ParseIntSign { Unsigned, Signed };
|
|
|
|
static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ErrorParseMode = ErrorParseMode::ThrowExceptions, ParseIntSign = ParseIntSign::Unsigned);
|
|
static JSBigInt* parseInt(ExecState*, StringView, ErrorParseMode = ErrorParseMode::ThrowExceptions);
|
|
static JSBigInt* stringToBigInt(ExecState*, StringView);
|
|
|
|
Optional<uint8_t> singleDigitValueForString();
|
|
String toString(ExecState*, 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);
|
|
static ComparisonResult compare(JSBigInt* x, JSBigInt* y);
|
|
|
|
bool getPrimitiveNumber(ExecState*, double& number, JSValue& result) const;
|
|
double toNumber(ExecState*) const;
|
|
|
|
JSObject* toObject(ExecState*, JSGlobalObject*) const;
|
|
inline bool toBoolean() const { return !isZero(); }
|
|
|
|
static JSBigInt* exponentiate(ExecState*, JSBigInt* base, JSBigInt* exponent);
|
|
|
|
static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
|
|
ComparisonResult static compareToDouble(JSBigInt* x, double y);
|
|
|
|
static JSBigInt* add(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* sub(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* unaryMinus(VM&, JSBigInt* x);
|
|
|
|
static JSBigInt* bitwiseAnd(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* bitwiseOr(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* bitwiseXor(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* bitwiseNot(ExecState*, JSBigInt* x);
|
|
|
|
static JSBigInt* leftShift(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* signedRightShift(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
|
|
private:
|
|
|
|
using Digit = UCPURegister;
|
|
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;
|
|
|
|
// 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 maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
|
|
static constexpr unsigned maxLengthBits = maxInt - sizeof(void*) * bitsPerByte - 1;
|
|
|
|
static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign);
|
|
|
|
static ComparisonResult absoluteCompare(JSBigInt* x, JSBigInt* y);
|
|
static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
|
|
static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
|
|
static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
|
|
static void absoluteDivWithBigIntDivisor(ExecState*, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder);
|
|
|
|
enum class LeftShiftMode {
|
|
SameSizeResult,
|
|
AlwaysAddOneDigit
|
|
};
|
|
|
|
static JSBigInt* absoluteLeftShiftAlwaysCopy(ExecState*, JSBigInt* 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 ExtraDigitsHandling {
|
|
Copy,
|
|
Skip
|
|
};
|
|
|
|
enum class SymmetricOp {
|
|
Symmetric,
|
|
NotSymmetric
|
|
};
|
|
|
|
template<typename BitwiseOp>
|
|
static JSBigInt* absoluteBitwiseOp(VM&, JSBigInt* x, JSBigInt* y, ExtraDigitsHandling, SymmetricOp, BitwiseOp&&);
|
|
|
|
static JSBigInt* absoluteAnd(VM&, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* absoluteOr(VM&, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* absoluteAndNot(VM&, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* absoluteXor(VM&, JSBigInt* x, JSBigInt* y);
|
|
|
|
enum class SignOption {
|
|
Signed,
|
|
Unsigned
|
|
};
|
|
|
|
static JSBigInt* absoluteAddOne(ExecState*, JSBigInt* x, SignOption);
|
|
static JSBigInt* absoluteSubOne(ExecState*, JSBigInt* 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(ExecState*, JSBigInt*, unsigned radix);
|
|
static String toStringGeneric(ExecState*, JSBigInt*, unsigned radix);
|
|
|
|
inline bool isZero() const
|
|
{
|
|
ASSERT(length() || !sign());
|
|
return length() == 0;
|
|
}
|
|
|
|
template <typename CharType>
|
|
static JSBigInt* parseInt(ExecState*, CharType* data, unsigned length, ErrorParseMode);
|
|
|
|
template <typename CharType>
|
|
static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, ParseIntSign = ParseIntSign::Signed, ParseIntMode = ParseIntMode::AllowEmptyString);
|
|
|
|
static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount);
|
|
|
|
static JSBigInt* copy(VM&, JSBigInt* x);
|
|
JSBigInt* rightTrim(VM&);
|
|
|
|
void inplaceMultiplyAdd(Digit multiplier, Digit part);
|
|
static JSBigInt* absoluteAdd(ExecState*, JSBigInt* x, JSBigInt* y, bool resultSign);
|
|
static JSBigInt* absoluteSub(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
|
|
|
|
static JSBigInt* leftShiftByAbsolute(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
static JSBigInt* rightShiftByAbsolute(ExecState*, JSBigInt* x, JSBigInt* y);
|
|
|
|
static JSBigInt* rightShiftByMaximum(VM&, bool sign);
|
|
|
|
static Optional<Digit> toShiftAmount(JSBigInt* x);
|
|
|
|
static size_t allocationSize(unsigned length);
|
|
inline static size_t offsetOfData()
|
|
{
|
|
return WTF::roundUpToMultipleOf<sizeof(Digit)>(sizeof(JSBigInt));
|
|
}
|
|
|
|
inline Digit* dataStorage()
|
|
{
|
|
return bitwise_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData());
|
|
}
|
|
|
|
Digit digit(unsigned);
|
|
void setDigit(unsigned, Digit);
|
|
|
|
unsigned m_length;
|
|
bool m_sign { false };
|
|
};
|
|
|
|
inline JSBigInt* asBigInt(JSValue value)
|
|
{
|
|
ASSERT(value.asCell()->isBigInt());
|
|
return jsCast<JSBigInt*>(value.asCell());
|
|
}
|
|
|
|
} // namespace JSC
|