[ESNext][BigInt] Implement support for "==" operation
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSBigInt.h
1 /*
2  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "ExceptionHelpers.h"
29 #include "JSObject.h"
30 #include "ParseInt.h"
31 #include <wtf/CagedPtr.h>
32 #include <wtf/text/StringBuilder.h>
33 #include <wtf/text/StringView.h>
34 #include <wtf/text/WTFString.h>
35
36 namespace JSC {
37
38 class JSBigInt final : public JSCell {
39     using Base = JSCell;
40     static const unsigned StructureFlags = Base::StructureFlags | OverridesToThis;
41
42 public:
43
44     JSBigInt(VM&, Structure*, int length);
45
46     enum class InitializationType { None, WithZero };
47     void initialize(InitializationType);
48
49     static void visitChildren(JSCell*, SlotVisitor&);
50
51     static size_t estimatedSize(JSCell*);
52     static size_t allocationSize(int length);
53
54     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
55
56     static JSBigInt* createZero(VM&);
57     static JSBigInt* createWithLength(VM&, int length);
58
59     static JSBigInt* createFrom(VM&, int32_t value);
60     static JSBigInt* createFrom(VM&, uint32_t value);
61     static JSBigInt* createFrom(VM&, int64_t value);
62     static JSBigInt* createFrom(VM&, bool value);
63
64     DECLARE_EXPORT_INFO;
65
66     void finishCreation(VM&);
67
68     JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
69
70     void setSign(bool sign) { m_sign = sign; }
71     bool sign() const { return m_sign; }
72
73     void setLength(int length) { m_length = length; }
74     int length() const { return m_length; }
75
76     enum ErrorParseMode {
77         ThrowExceptions,
78         IgnoreExceptions
79     };
80
81     static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ErrorParseMode = ThrowExceptions);
82     static JSBigInt* parseInt(ExecState*, StringView, ErrorParseMode = ThrowExceptions);
83     static JSBigInt* stringToBigInt(ExecState*, StringView);
84
85     std::optional<uint8_t> singleDigitValueForString();
86     String toString(ExecState&, unsigned radix);
87     
88     JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*);
89     bool equalsToNumber(JSValue);
90
91     bool getPrimitiveNumber(ExecState*, double& number, JSValue& result) const;
92     double toNumber(ExecState*) const;
93
94     JSObject* toObject(ExecState*, JSGlobalObject*) const;
95     
96 private:
97
98     enum ComparisonResult {
99         Equal,
100         Undefined,
101         GreaterThan,
102         LessThan
103     };
104
105     using Digit = uintptr_t;
106     static constexpr const int bitsPerByte = 8;
107     static constexpr const int digitBits = sizeof(Digit) * bitsPerByte;
108     static constexpr const int halfDigitBits = digitBits / 2;
109     static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1;
110     static constexpr const int maxInt = 0x7FFFFFFF;
111     
112     // The maximum length that the current implementation supports would be
113     // maxInt / digitBits. However, we use a lower limit for now, because
114     // raising it later is easier than lowering it.
115     // Support up to 1 million bits.
116     static const int maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
117     
118     static uint64_t calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign);
119     
120     static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
121     static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result);
122
123     // Digit arithmetic helpers.
124     static Digit digitAdd(Digit a, Digit b, Digit& carry);
125     static Digit digitSub(Digit a, Digit b, Digit& borrow);
126     static Digit digitMul(Digit a, Digit b, Digit& high);
127     static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder);
128     static Digit digitPow(Digit base, Digit exponent);
129
130     static String toStringGeneric(ExecState&, JSBigInt*, int radix);
131
132     bool isZero();
133
134     ComparisonResult static compareToDouble(JSBigInt* x, double y);
135
136     template <typename CharType>
137     static JSBigInt* parseInt(ExecState*, CharType*  data, unsigned length, ErrorParseMode);
138
139     template <typename CharType>
140     static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, bool allowEmptyString = true);
141
142     static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount);
143
144     JSBigInt* rightTrim(VM&);
145
146     void inplaceMultiplyAdd(Digit multiplier, Digit part);
147     
148     static size_t offsetOfData();
149     Digit* dataStorage();
150
151     Digit digit(int);
152     void setDigit(int, Digit);
153         
154     int m_length;
155     bool m_sign;
156 };
157
158 inline JSBigInt* asBigInt(JSValue value)
159 {
160     ASSERT(value.asCell()->isBigInt());
161     return jsCast<JSBigInt*>(value.asCell());
162 }
163
164 } // namespace JSC