WebKit Bugzilla
Attachment 339647 Details for
Bug 184474
: [ESNext][BigInt] Implement support for "==" operation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-184474-20180505121504.patch (text/plain), 25.57 KB, created by
Caio Lima
on 2018-05-05 08:15:06 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-05-05 08:15:06 PDT
Size:
25.57 KB
patch
obsolete
>Subversion Revision: 231396 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index e61aafe70d4e23936e525f18ce92bafdb48c2b50..e18c782411634108787855a92c683be4d49d5286 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,26 @@ >+2018-05-05 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "==" operation >+ https://bugs.webkit.org/show_bug.cgi?id=184474 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch is implementing support of BigInt for equals operator >+ following the spec semantics[1]. >+ >+ [1] - https://tc39.github.io/proposal-bigint/#sec-abstract-equality-comparison >+ >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::parseInt): >+ (JSC::JSBigInt::stringToBigInt): >+ (JSC::JSBigInt::toString): >+ (JSC::JSBigInt::setDigit): >+ (JSC::JSBigInt::equalsToNumber): >+ (JSC::JSBigInt::compareToDouble): >+ * runtime/JSBigInt.h: >+ * runtime/JSCJSValueInlines.h: >+ (JSC::JSValue::equalSlowCaseInline): >+ > 2018-05-04 Keith Miller <keith_miller@apple.com> > > isCacheableArrayLength should return true for undecided arrays >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index 3d1e9f183afb09e3cb825aabf2a047980f107993..c36a06a6c6c21a655781572fd637d600a6a7e798 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -208,21 +208,26 @@ std::optional<uint8_t> JSBigInt::singleDigitValueForString() > return { }; > } > >-JSBigInt* JSBigInt::parseInt(ExecState* state, StringView s) >+JSBigInt* JSBigInt::parseInt(ExecState* state, StringView s, ErrorParseMode parserMode) > { > if (s.is8Bit()) >- return parseInt(state, s.characters8(), s.length()); >- return parseInt(state, s.characters16(), s.length()); >+ return parseInt(state, s.characters8(), s.length(), parserMode); >+ return parseInt(state, s.characters16(), s.length(), parserMode); > } > >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode) > { > if (s.is8Bit()) >- return parseInt(state, vm, s.characters8(), s.length(), 0, radix, false); >- return parseInt(state, vm, s.characters16(), s.length(), 0, radix, false); >+ return parseInt(state, vm, s.characters8(), s.length(), 0, radix, parserMode, false); >+ return parseInt(state, vm, s.characters16(), s.length(), 0, radix, parserMode, false); > } > >-String JSBigInt::toString(ExecState& state, int radix) >+JSBigInt* JSBigInt::stringToBigInt(ExecState* state, StringView s) >+{ >+ return parseInt(state, s, ErrorParseMode::IgnoreExceptions); >+} >+ >+String JSBigInt::toString(ExecState& state, unsigned radix) > { > if (this->isZero()) > return state.vm().smallStrings.singleCharacterStringRep('0'); >@@ -718,24 +723,24 @@ size_t JSBigInt::offsetOfData() > } > > template <typename CharType> >-JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int length) >+JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, unsigned length, ErrorParseMode errorParseMode) > { > VM& vm = state->vm(); > >- int p = 0; >+ 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(state, vm, data, length, p + 2, 2, false); >+ return parseInt(state, vm, data, length, p + 2, 2, errorParseMode, false); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'x')) >- return parseInt(state, vm, data, length, p + 2, 16, false); >+ return parseInt(state, vm, data, length, p + 2, 16, errorParseMode, false); > > if (isASCIIAlphaCaselessEqual(data[p + 1], 'o')) >- return parseInt(state, vm, data, length, p + 2, 8, false); >+ return parseInt(state, vm, data, length, p + 2, 8, errorParseMode, false); > } > > bool sign = false; >@@ -748,7 +753,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int length) > } > } > >- JSBigInt* result = parseInt(state, vm, data, length, p, 10); >+ JSBigInt* result = parseInt(state, vm, data, length, p, 10, errorParseMode); > > if (result && !result->isZero()) > result->setSign(sign); >@@ -757,16 +762,17 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType* data, int length) > } > > template <typename CharType> >-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int length, int startIndex, int radix, bool allowEmptyString) >+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, bool allowEmptyString) > { > ASSERT(length >= 0); >- int p = startIndex; >+ unsigned p = startIndex; > > auto scope = DECLARE_THROW_SCOPE(vm); > > if (!allowEmptyString && startIndex == length) { > ASSERT(state); >- throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); >+ if (errorParseMode == ErrorParseMode::ThrowExceptions) >+ throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); > return nullptr; > } > >@@ -776,7 +782,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int lengt > > int endIndex = length - 1; > // Removing trailing spaces >- while (endIndex >= p && isStrWhiteSpace(data[endIndex])) >+ while (endIndex >= static_cast<int>(p) && isStrWhiteSpace(data[endIndex])) > --endIndex; > > length = endIndex + 1; >@@ -793,7 +799,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int lengt > > result->initialize(InitializationType::WithZero); > >- for (int i = p; i < length; i++, p++) { >+ for (unsigned i = p; i < length; i++, p++) { > uint32_t digit; > if (data[i] >= '0' && data[i] < limit0) > digit = data[i] - '0'; >@@ -811,7 +817,8 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int lengt > return result->rightTrim(vm); > > ASSERT(state); >- throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); >+ if (errorParseMode == ErrorParseMode::ThrowExceptions) >+ throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt")); > > return nullptr; > } >@@ -832,10 +839,151 @@ void JSBigInt::setDigit(int n, Digit value) > ASSERT(n >= 0 && 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 = *(reinterpret_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) >+ 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 = sizeof(xMSD) == 8 ? clz64(xMSD) : clz32(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 == (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; >+} >+ > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 298c348cd2b4e5ab5c92c7bb799a30f3ebfa6231..b9bf7512ffc13b8f4f2ba73ab4a178532b9c7934 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -73,13 +73,20 @@ public: > void setLength(int length) { m_length = length; } > int length() const { return m_length; } > >- static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix); >- static JSBigInt* parseInt(ExecState*, StringView); >+ enum ErrorParseMode { >+ ThrowExceptions, >+ IgnoreExceptions >+ }; >+ >+ static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix, ErrorParseMode = ThrowExceptions); >+ static JSBigInt* parseInt(ExecState*, StringView, ErrorParseMode = ThrowExceptions); >+ static JSBigInt* stringToBigInt(ExecState*, StringView); > > std::optional<uint8_t> singleDigitValueForString(); >- String toString(ExecState&, int radix); >+ String toString(ExecState&, unsigned radix); > > JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*); >+ bool equalsToNumber(JSValue); > > bool getPrimitiveNumber(ExecState*, double& number, JSValue& result) const; > double toNumber(ExecState*) const; >@@ -87,6 +94,14 @@ public: > JSObject* toObject(ExecState*, JSGlobalObject*) const; > > private: >+ >+ enum ComparisonResult { >+ Equal, >+ Undefined, >+ GreaterThan, >+ LessThan >+ }; >+ > using Digit = uintptr_t; > static constexpr const int bitsPerByte = 8; > static constexpr const int digitBits = sizeof(Digit) * bitsPerByte; >@@ -116,11 +131,13 @@ private: > > bool isZero(); > >+ ComparisonResult static compareToDouble(JSBigInt* x, double y); >+ > template <typename CharType> >- static JSBigInt* parseInt(ExecState*, CharType* data, int length); >+ static JSBigInt* parseInt(ExecState*, CharType* data, unsigned length, ErrorParseMode); > > template <typename CharType> >- static JSBigInt* parseInt(ExecState*, VM&, CharType* data, int length, int startIndex, int radix, bool allowEmptyString = true); >+ static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, bool allowEmptyString = true); > > static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount); > >diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >index d0d3799fb39ec3182dcd2149607060e35b5b279a..23d3b26c59542b770e4d3d0a2461262e3de5c9a8 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >@@ -981,6 +981,26 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV > return asString(v1)->equal(exec, asString(v2)); > } > >+ if (v1.isBigInt() && s2) { >+ JSBigInt* n = JSBigInt::stringToBigInt(exec, asString(v2)->value(exec)); >+ RETURN_IF_EXCEPTION(scope, false); >+ if (!n) >+ return false; >+ >+ v2 = JSValue(n); >+ continue; >+ } >+ >+ if (s1 && v2.isBigInt()) { >+ JSBigInt* n = JSBigInt::stringToBigInt(exec, asString(v1)->value(exec)); >+ RETURN_IF_EXCEPTION(scope, false); >+ if (!n) >+ return false; >+ >+ v1 = JSValue(n); >+ continue; >+ } >+ > if (v1.isUndefinedOrNull()) { > if (v2.isUndefinedOrNull()) > return true; >@@ -1034,10 +1054,27 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV > if (v1.isBoolean()) { > if (v2.isNumber()) > return static_cast<double>(v1.asBoolean()) == v2.asNumber(); >+ else if (v2.isBigInt()) { >+ v1 = JSValue(v1.toNumber(exec)); >+ continue; >+ } > } else if (v2.isBoolean()) { > if (v1.isNumber()) > return v1.asNumber() == static_cast<double>(v2.asBoolean()); >+ else if (v1.isBigInt()) { >+ v2 = JSValue(v2.toNumber(exec)); >+ continue; >+ } > } >+ >+ if (v1.isBigInt() && v2.isBigInt()) >+ return JSBigInt::equals(asBigInt(v1), asBigInt(v2)); >+ >+ if (v1.isBigInt() && v2.isNumber()) >+ return asBigInt(v1)->equalsToNumber(v2); >+ >+ if (v2.isBigInt() && v1.isNumber()) >+ return asBigInt(v2)->equalsToNumber(v1); > > return v1 == v2; > } while (true); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 3cc1a48ccd48e2c817ac3751e921c99520e8d73a..899e6becea97403b24d2ab023e3e5939dea85e50 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,14 @@ >+2018-05-05 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "==" operation >+ https://bugs.webkit.org/show_bug.cgi?id=184474 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-equals-basic.js: Added. >+ * stress/big-int-equals-to-primitive-precedence.js: Added. >+ * stress/big-int-equals-wrapped-value.js: Added. >+ > 2018-05-04 Keith Miller <keith_miller@apple.com> > > isCacheableArrayLength should return true for undecided arrays >diff --git a/JSTests/stress/big-int-equals-basic.js b/JSTests/stress/big-int-equals-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..59ba0286f8028e597b62f92b7d0bde1ff63fa6fe >--- /dev/null >+++ b/JSTests/stress/big-int-equals-basic.js >@@ -0,0 +1,124 @@ >+//@ runBigIntEnabled >+ >+function assert(a, e, m) { >+ if (a !== e) >+ throw new Error(m); >+} >+ >+function testEquals(a, b, e) { >+ assert(a == b, e, a + " == " + b + " should be " + e); >+ assert(b == a, e, b + " == " + a + " should be " + e); >+} >+ >+function testEqualsWithMessage(a, b, e, m) { >+ assert(a == b, e, m); >+ assert(b == a, e, m); >+} >+ >+// BigInt - BigInt >+testEquals(1n, 1n, true); >+testEquals(1928392129312n, 1n, false); >+testEquals(0n, 1n, false); >+testEquals(0n, 0n, true); >+testEquals(817283912931n, 817283912931n, true); >+testEquals(0xFFD817283AF9129E31n, 0xFFD817283AF9129E31n, true); >+testEquals(0xAFFD817283AF9129E31n, 0xFFD817283AF9129E31n, false); >+testEquals(4719490697266344402481n, BigInt("-4719490697266344402481"), false); >+testEquals(BigInt("-4719490697266344402481"), BigInt("4719490697266344402481"), false); >+testEquals(BigInt("-4719490697266344402481"), BigInt("-4719490697266344402481"), true); >+testEquals(BigInt("-17"), BigInt("-17"), true); >+ >+// BigInt - String >+ >+testEquals(1n, "1", true); >+testEquals(1928392129312n, "1", false); >+testEquals(0n, "1", false); >+testEquals(0n, "0", true); >+testEquals(817283912931n, "817283912931", true); >+testEquals(0xFFD817283AF9129E31n, "4719490697266344402481", true); >+testEquals(0xAFFD817283AF9129E31n, "4719490697266344402481", false); >+ >+// BigInt - Number >+ >+testEquals(0n, 0, true); >+testEquals(0n, -0, true); >+testEquals(-0, 0n, true); >+testEquals(0n, 0.000000000001, false); >+testEquals(0n, 1, false); >+testEquals(1, 0n, false); >+testEquals(1n, 0.999999999999, false); >+testEquals(1n, 1, true); >+testEquals(0n, Number.MIN_VALUE, false); >+testEquals(0n, -Number.MIN_VALUE, false); >+testEquals(BigInt("-10"), Number.MIN_VALUE, false); >+testEquals(1n, Number.MAX_VALUE, false); >+testEquals(1n, -Number.MAX_VALUE, false); >+testEquals(0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn, Number.MAX_VALUE, false); >+testEquals(0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n, Number.MAX_VALUE, true); >+testEquals(0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n, Number.MAX_VALUE, false); >+testEquals(230000000000000000000, 230000000000000000000n, true); >+testEquals(10n, NaN, false); >+testEquals(10n, undefined, false); >+testEquals(10n, null, false); >+testEquals(10n, Infinity, false); >+testEquals(10n, -Infinity, false); >+testEquals(BigInt("-2147483648"), -2147483648, true); // Testing INT32_MIN >+testEquals(BigInt("-2147483647"), -2147483648, false); >+testEquals(BigInt("2147483647"), -2147483648, false); >+testEquals(BigInt("2147483648"), -2147483648, false); >+testEquals(BigInt("2147483647"), 2147483647, true); >+testEquals(BigInt("2147483648"), 2147483647, false); >+ >+// BigInt - Boolean >+ >+testEquals(BigInt("-1"), false, false); >+testEquals(BigInt("-1"), true, false); >+testEquals(0n, false, true); >+testEquals(0n, true, false); >+testEquals(1n, false, false); >+testEquals(1n, true, true); >+testEquals(2n, false, false); >+testEquals(2n, true, false); >+ >+// BigInt - Object >+ >+testEquals(0n, Object(0n), true); >+testEquals(0n, Object(1n), false); >+testEquals(1n, Object(0n), false); >+testEquals(1n, Object(1n), true); >+testEquals(2n, Object(0n), false); >+testEquals(2n, Object(1n), false); >+testEquals(2n, Object(2n), true); >+testEquals(0n, {}, false); >+testEquals(0n, {valueOf: function() { return 0n; }}, true); >+testEquals(0n, {valueOf: function() { return 1n; }}, false); >+testEquals(0n, {toString: function() { return "0"; }}, true); >+testEquals(0n, {toString: function() { return "1"; }}, false); >+testEquals(900719925474099101n, {valueOf: function() { return 900719925474099101n; }}, true); >+testEquals(900719925474099101n, {valueOf: function() { return 900719925474099102n; }}, false); >+testEquals(900719925474099101n, {toString: function() { return "900719925474099101"; }}, true); >+testEquals(900719925474099101n, {toString: function() { return "900719925474099102"; }}, false); >+ >+try { >+ let o = {valueOf: function() { throw new Error("my error"); }}; >+ o == 1n; >+ throw new Error("Exception in ToPrimitive not catched"); >+} catch(e) { >+ assert(e.message, "my error", "Wrong exception in ToPrimitive"); >+} >+ >+try { >+ let o = {toString: function() { throw new Error("my error"); }}; >+ o == 1n; >+ throw new Error("Exception in ToString not catched"); >+} catch(e) { >+ assert(e.message, "my error", "Wrong exception in ToString"); >+} >+ >+// BigInt - Symbol >+ >+testEqualsWithMessage(0n, Symbol("1"), false, "0n == Symbol(1)"); >+testEqualsWithMessage(Symbol("1"), 0n, false, "Symbol(1) == 0n"); >+testEqualsWithMessage(1n, Symbol("1"), false, "1n == Symbol(1)"); >+testEqualsWithMessage(Symbol("1"), 1n, false, "Symbol(1) == 1n"); >+ >diff --git a/JSTests/stress/big-int-equals-to-primitive-precedence.js b/JSTests/stress/big-int-equals-to-primitive-precedence.js >new file mode 100644 >index 0000000000000000000000000000000000000000..f5ed564dd7c1043290c5f6c8f93ab6ef6b227abd >--- /dev/null >+++ b/JSTests/stress/big-int-equals-to-primitive-precedence.js >@@ -0,0 +1,39 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testEquals(x, y, z, message) { >+ assert.sameValue(x == y, z, message); >+ assert.sameValue(y == x, z, message); >+} >+ >+testEquals(Object(2n), 1n, false, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 2n; >+ }, >+ valueOf: function () { >+ throw new Error("Should never execute it"); >+ }, >+ toString: function () { >+ throw new Error("Should never execute it"); >+ } >+}; >+testEquals(o, 2n, true, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ }, >+ toString: function () { >+ throw new Error("Should never execute it"); >+ } >+}; >+testEquals(o, 1n, false, "ToPrimitive: valueOf"); >+ >diff --git a/JSTests/stress/big-int-equals-wrapped-value.js b/JSTests/stress/big-int-equals-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..6ed89be135ee87a5ef939034d331c95eb4f33bc1 >--- /dev/null >+++ b/JSTests/stress/big-int-equals-wrapped-value.js >@@ -0,0 +1,37 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testEquals(x, y, z, message) { >+ assert.sameValue(x == y, z, message); >+ assert.sameValue(y == x, z, message); >+} >+ >+testEquals(Object(2n), 1n, false, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 1n; >+ } >+}; >+testEquals(o, 1n, true, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ } >+}; >+testEquals(o, 2n, true, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 2n; >+ } >+} >+testEquals(o, 1n, false, "ToPrimitive: toString"); >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ysuzuki
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 184474
:
338542
|
338556
|
339379
|
339647
|
340066