WebKit Bugzilla
Attachment 339634 Details for
Bug 183721
: [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-183721-20180505014653.patch (text/plain), 46.30 KB, created by
Caio Lima
on 2018-05-04 21:46:55 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-05-04 21:46:55 PDT
Size:
46.30 KB
patch
obsolete
>Subversion Revision: 231133 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 6a1191d903d20e12799dccf9580cd17c1e7693a3..975aa6f0bd14d3bd493e8d1810db74b9df514e3c 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,45 @@ >+2018-05-01 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "*" operation >+ https://bugs.webkit.org/show_bug.cgi?id=183721 >+ >+ Reviewed by Saam Barati. >+ >+ Added BigInt support into times binary operator into LLInt and on >+ JITOperations profiledMul and unprofiledMul. We are also replacing all >+ uses of int to unsigned when there is no negative values for >+ variables. >+ >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * jit/JITOperations.cpp: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::JSBigInt): >+ (JSC::JSBigInt::allocationSize): >+ (JSC::JSBigInt::createWithLength): >+ (JSC::JSBigInt::toString): >+ (JSC::JSBigInt::multiply): >+ (JSC::JSBigInt::digitDiv): >+ (JSC::JSBigInt::internalMultiplyAdd): >+ (JSC::JSBigInt::multiplyAccumulate): >+ (JSC::JSBigInt::equals): >+ (JSC::JSBigInt::absoluteDivSmall): >+ (JSC::JSBigInt::calculateMaximumCharactersRequired): >+ (JSC::JSBigInt::toStringGeneric): >+ (JSC::JSBigInt::rightTrim): >+ (JSC::JSBigInt::allocateFor): >+ (JSC::JSBigInt::parseInt): >+ (JSC::JSBigInt::digit): >+ (JSC::JSBigInt::setDigit): >+ * runtime/JSBigInt.h: >+ * runtime/JSCJSValue.h: >+ * runtime/JSCJSValueInlines.h: >+ (JSC::JSValue::toNumeric const): >+ * runtime/Operations.h: >+ (JSC::jsMul): >+ > 2018-04-28 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r231131. >diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >index cee65623431770f4bf402ada0c877358f800b67d..e4650ac3080f6b420b6378b665ced526bb9de5a7 100644 >--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >@@ -146,14 +146,14 @@ private: > JSValue child2Constant = m_state.forNode(node->child2().node()).value(); > > // FIXME: Revisit this condition when introducing BigInt to JSC. >- auto isNonStringCellConstant = [] (JSValue value) { >- return value && value.isCell() && !value.isString(); >+ auto isNonStringOrBigIntCellConstant = [] (JSValue value) { >+ return value && value.isCell() && !value.isString() && !value.isBigInt(); > }; > >- if (isNonStringCellConstant(child1Constant)) { >+ if (isNonStringOrBigIntCellConstant(child1Constant)) { > node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2()); > changed = true; >- } else if (isNonStringCellConstant(child2Constant)) { >+ } else if (isNonStringOrBigIntCellConstant(child2Constant)) { > node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1()); > changed = true; > } >diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp >index 365bb73755a7a454cf085436c6378d1bf73fec4b..74db2624f62acb7a2a0b01761d2cc9bde8c7e962 100644 >--- a/Source/JavaScriptCore/jit/JITOperations.cpp >+++ b/Source/JavaScriptCore/jit/JITOperations.cpp >@@ -2554,21 +2554,21 @@ EncodedJSValue JIT_OPERATION operationValueAddNoOptimize(ExecState* exec, Encode > return JSValue::encode(result); > } > >-ALWAYS_INLINE static EncodedJSValue unprofiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >+ALWAYS_INLINE static EncodedJSValue unprofiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) > { >+ VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > JSValue op1 = JSValue::decode(encodedOp1); > JSValue op2 = JSValue::decode(encodedOp2); > >- double a = op1.toNumber(exec); >+ JSValue jsResult = jsMul(exec, op1, op2); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- scope.release(); >- double b = op2.toNumber(exec); >- return JSValue::encode(jsNumber(a * b)); >+ return JSValue::encode(jsResult); > } > >-ALWAYS_INLINE static EncodedJSValue profiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true) >+ALWAYS_INLINE static EncodedJSValue profiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true) > { >+ VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > JSValue op1 = JSValue::decode(encodedOp1); > JSValue op2 = JSValue::decode(encodedOp2); >@@ -2576,12 +2576,8 @@ ALWAYS_INLINE static EncodedJSValue profiledMul(VM& vm, ExecState* exec, Encoded > if (shouldObserveLHSAndRHSTypes) > arithProfile.observeLHSAndRHS(op1, op2); > >- double a = op1.toNumber(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- double b = op2.toNumber(exec); >+ JSValue result = jsMul(exec, op1, op2); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- >- JSValue result = jsNumber(a * b); > arithProfile.observeResult(result); > return JSValue::encode(result); > } >@@ -2591,7 +2587,7 @@ EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue e > VM* vm = &exec->vm(); > NativeCallFrameTracer tracer(vm, exec); > >- return unprofiledMul(*vm, exec, encodedOp1, encodedOp2); >+ return unprofiledMul(exec, encodedOp1, encodedOp2); > } > > EncodedJSValue JIT_OPERATION operationValueMulNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*) >@@ -2599,7 +2595,7 @@ EncodedJSValue JIT_OPERATION operationValueMulNoOptimize(ExecState* exec, Encode > VM* vm = &exec->vm(); > NativeCallFrameTracer tracer(vm, exec); > >- return unprofiledMul(*vm, exec, encodedOp1, encodedOp2); >+ return unprofiledMul(exec, encodedOp1, encodedOp2); > } > > EncodedJSValue JIT_OPERATION operationValueMulOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC) >@@ -2616,7 +2612,7 @@ EncodedJSValue JIT_OPERATION operationValueMulOptimize(ExecState* exec, EncodedJ > exec->codeBlock()->dumpMathICStats(); > #endif > >- return unprofiledMul(*vm, exec, encodedOp1, encodedOp2); >+ return unprofiledMul(exec, encodedOp1, encodedOp2); > } > > EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile) >@@ -2625,7 +2621,7 @@ EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJ > NativeCallFrameTracer tracer(vm, exec); > > ASSERT(arithProfile); >- return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile); >+ return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile); > } > > EncodedJSValue JIT_OPERATION operationValueMulProfiledOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC) >@@ -2643,7 +2639,7 @@ EncodedJSValue JIT_OPERATION operationValueMulProfiledOptimize(ExecState* exec, > exec->codeBlock()->dumpMathICStats(); > #endif > >- return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile, false); >+ return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile, false); > } > > EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC) >@@ -2653,7 +2649,7 @@ EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(ExecState* exec > > ArithProfile* arithProfile = mulIC->arithProfile(); > ASSERT(arithProfile); >- return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile); >+ return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile); > } > > ALWAYS_INLINE static EncodedJSValue unprofiledNegate(ExecState* exec, EncodedJSValue encodedOperand) >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index e6c1a44d67f42145285fb0d200745dbcb3a7df77..9e91d433f588447afc661a26e761d41aaa54ab66 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -65,6 +65,7 @@ > #include "ThunkGenerators.h" > #include "TypeProfilerLog.h" > #include <wtf/StringPrintStream.h> >+#include <wtf/Variant.h> > > namespace JSC { > >@@ -486,11 +487,8 @@ SLOW_PATH_DECL(slow_path_mul) > BEGIN(); > JSValue left = OP_C(2).jsValue(); > JSValue right = OP_C(3).jsValue(); >- double a = left.toNumber(exec); >- if (UNLIKELY(throwScope.exception())) >- RETURN(JSValue()); >- double b = right.toNumber(exec); >- JSValue result = jsNumber(a * b); >+ JSValue result = jsMul(exec, left, right); >+ CHECK_EXCEPTION(); > RETURN_WITH_PROFILING(result, { > updateArithProfileForBinaryArithOp(exec, pc, result, left, right); > }); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index c51c8b210d93c17f96400efe77daa672a259a6d3..9197b9a1a44dc5112702da78a18898078f2d649f 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -69,7 +69,7 @@ void JSBigInt::visitChildren(JSCell* cell, SlotVisitor& visitor) > Base::visitChildren(thisObject, visitor); > } > >-JSBigInt::JSBigInt(VM& vm, Structure* structure, int length) >+JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length) > : Base(vm, structure) > , m_length(length) > { } >@@ -93,13 +93,13 @@ JSBigInt* JSBigInt::createZero(VM& vm) > return zeroBigInt; > } > >-size_t JSBigInt::allocationSize(int length) >+size_t JSBigInt::allocationSize(unsigned length) > { > size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt)); > return sizeWithPadding + length * sizeof(Digit); > } > >-JSBigInt* JSBigInt::createWithLength(VM& vm, int length) >+JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length) > { > JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length); > bigInt->finishCreation(vm); >@@ -223,7 +223,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t rad > return parseInt(state, vm, s.characters16(), s.length(), 0, radix, false); > } > >-String JSBigInt::toString(ExecState& state, int radix) >+String JSBigInt::toString(ExecState& state, unsigned radix) > { > if (this->isZero()) > return state.vm().smallStrings.singleCharacterStringRep('0'); >@@ -246,6 +246,26 @@ void JSBigInt::inplaceMultiplyAdd(uintptr_t factor, uintptr_t summand) > internalMultiplyAdd(this, factor, summand, length(), this); > } > >+JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y) >+{ >+ VM& vm = state->vm(); >+ >+ if (x->isZero()) >+ return x; >+ if (y->isZero()) >+ return y; >+ >+ unsigned resultLength = x->length() + y->length(); >+ JSBigInt* result = JSBigInt::createWithLength(vm, resultLength); >+ 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); >+} >+ > #if USE(JSVALUE32_64) > #define HAVE_TWO_DIGIT 1 > typedef uint64_t TwoDigit; >@@ -378,9 +398,9 @@ JSBigInt::Digit JSBigInt::digitDiv(Digit high, Digit low, Digit divisor, Digit& > static const Digit kHalfDigitBase = 1ull << halfDigitBits; > // Adapted from Warren, Hacker's Delight, p. 152. > #if USE(JSVALUE64) >- int s = clz64(divisor); >+ unsigned s = clz64(divisor); > #else >- int s = clz32(divisor); >+ unsigned s = clz32(divisor); > #endif > divisor <<= s; > >@@ -423,14 +443,14 @@ JSBigInt::Digit JSBigInt::digitDiv(Digit high, Digit low, Digit divisor, Digit& > > // 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, int n, JSBigInt* result) >+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 (int i = 0; i < n; i++) { >+ for (unsigned i = 0; i < n; i++) { > Digit current = source->digit(i); > Digit newCarry = 0; > >@@ -458,6 +478,49 @@ void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand > 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()) >@@ -466,7 +529,7 @@ bool JSBigInt::equals(JSBigInt* x, JSBigInt* y) > if (x->length() != y->length()) > return false; > >- for (int i = 0; i < x->length(); i++) { >+ for (unsigned i = 0; i < x->length(); i++) { > if (x->digit(i) != y->digit(i)) > return false; > } >@@ -494,7 +557,7 @@ void JSBigInt::absoluteDivSmall(ExecState& state, JSBigInt* x, Digit divisor, JS > return; > } > >- int length = x->length(); >+ unsigned length = x->length(); > if (quotient != nullptr) { > if (*quotient == nullptr) > *quotient = JSBigInt::createWithLength(vm, length); >@@ -521,14 +584,14 @@ constexpr uint8_t maxBitsPerCharTable[] = { > 162, 163, 165, 166, // 33..36 > }; > >-static const int bitsPerCharTableShift = 5; >+static const unsigned bitsPerCharTableShift = 5; > static const 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(int length, int radix, Digit lastDigit, bool sign) >+uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign) > { >- int leadingZeros; >+ unsigned leadingZeros; > if (sizeof(lastDigit) == 8) > leadingZeros = clz64(lastDigit); > else >@@ -556,7 +619,7 @@ uint64_t JSBigInt::calculateMaximumCharactersRequired(int length, int radix, Dig > return maximumCharactersRequired; > } > >-String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix) >+String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix) > { > // FIXME: [JSC] Revisit usage of StringVector into JSBigInt::toString > // https://bugs.webkit.org/show_bug.cgi?id=18067 >@@ -565,7 +628,7 @@ String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix) > ASSERT(radix >= 2 && radix <= 36); > ASSERT(!x->isZero()); > >- int length = x->length(); >+ unsigned length = x->length(); > bool sign = x->sign(); > > uint8_t maxBitsPerChar = maxBitsPerCharTable[radix]; >@@ -581,12 +644,12 @@ String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix) > if (length == 1) > lastDigit = x->digit(0); > else { >- int chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar; >+ unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar; > Digit chunkDivisor = digitPow(radix, chunkChars); > > // By construction of chunkChars, there can't have been overflow. > ASSERT(chunkDivisor); >- int nonZeroDigit = length - 1; >+ unsigned nonZeroDigit = length - 1; > ASSERT(x->digit(nonZeroDigit)); > > // {rest} holds the part of the BigInt that we haven't looked at yet. >@@ -602,7 +665,7 @@ String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix) > ASSERT(rest); > > dividend = &rest; >- for (int i = 0; i < chunkChars; i++) { >+ for (unsigned i = 0; i < chunkChars; i++) { > resultString.append(radixDigits[chunk % radix]); > chunk /= radix; > } >@@ -627,7 +690,7 @@ String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix) > ASSERT(resultString.size() <= static_cast<size_t>(maximumCharactersRequired)); > > // Remove leading zeroes. >- int newSizeNoLeadingZeroes = resultString.size(); >+ unsigned newSizeNoLeadingZeroes = resultString.size(); > while (newSizeNoLeadingZeroes > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0') > newSizeNoLeadingZeroes--; > >@@ -646,14 +709,16 @@ JSBigInt* JSBigInt::rightTrim(VM& vm) > if (isZero()) > return this; > >+ ASSERT(m_length); >+ > int nonZeroIndex = m_length - 1; > while (nonZeroIndex >= 0 && !digit(nonZeroIndex)) > nonZeroIndex--; > >- if (nonZeroIndex == m_length - 1) >+ if (nonZeroIndex == static_cast<int>(m_length - 1)) > return this; > >- int newLength = nonZeroIndex + 1; >+ unsigned newLength = nonZeroIndex + 1; > JSBigInt* trimmedBigInt = createWithLength(vm, newLength); > RELEASE_ASSERT(trimmedBigInt); > std::copy(dataStorage(), dataStorage() + newLength, trimmedBigInt->dataStorage()); >@@ -663,14 +728,14 @@ JSBigInt* JSBigInt::rightTrim(VM& vm) > return trimmedBigInt; > } > >-JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, int charcount) >+JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount) > { > ASSERT(2 <= radix && radix <= 36); > ASSERT(charcount >= 0); > > size_t bitsPerChar = maxBitsPerCharTable[radix]; > size_t chars = charcount; >- const int roundup = bitsPerCharTableMultiplier - 1; >+ const unsigned roundup = bitsPerCharTableMultiplier - 1; > if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) { > size_t bitsMin = bitsPerChar * chars; > >@@ -678,7 +743,7 @@ JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, int charcou > bitsMin = (bitsMin + roundup) >> bitsPerCharTableShift; > if (bitsMin <= static_cast<size_t>(maxInt)) { > // Divide by kDigitsBits, rounding up. >- int length = (static_cast<int>(bitsMin) + digitBits - 1) / digitBits; >+ unsigned length = (bitsMin + digitBits - 1) / digitBits; > if (length <= maxLength) { > JSBigInt* result = JSBigInt::createWithLength(vm, length); > return result; >@@ -719,11 +784,11 @@ 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) > { > VM& vm = state->vm(); > >- int p = 0; >+ unsigned p = 0; > while (p < length && isStrWhiteSpace(data[p])) > ++p; > >@@ -758,10 +823,10 @@ 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, bool allowEmptyString) > { > ASSERT(length >= 0); >- int p = startIndex; >+ unsigned p = startIndex; > > auto scope = DECLARE_THROW_SCOPE(vm); > >@@ -777,7 +842,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; >@@ -785,16 +850,16 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int lengt > if (p == length) > return createZero(vm); > >- int limit0 = '0' + (radix < 10 ? radix : 10); >- int limita = 'a' + (radix - 10); >- int limitA = 'A' + (radix - 10); >+ unsigned limit0 = '0' + (radix < 10 ? radix : 10); >+ unsigned limita = 'a' + (radix - 10); >+ unsigned limitA = 'A' + (radix - 10); > > JSBigInt* result = allocateFor(state, vm, radix, length - p); > RETURN_IF_EXCEPTION(scope, nullptr); > > 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'; >@@ -822,13 +887,13 @@ JSBigInt::Digit* JSBigInt::dataStorage() > return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData()); > } > >-JSBigInt::Digit JSBigInt::digit(int n) >+JSBigInt::Digit JSBigInt::digit(unsigned n) > { > ASSERT(n >= 0 && n < length()); > return dataStorage()[n]; > } > >-void JSBigInt::setDigit(int n, Digit value) >+void JSBigInt::setDigit(unsigned n, Digit value) > { > ASSERT(n >= 0 && n < length()); > dataStorage()[n] = value; >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 298c348cd2b4e5ab5c92c7bb799a30f3ebfa6231..eb12c00466e356ffdadfa366414c07cd03bc46f7 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -41,7 +41,7 @@ class JSBigInt final : public JSCell { > > public: > >- JSBigInt(VM&, Structure*, int length); >+ JSBigInt(VM&, Structure*, unsigned length); > > enum class InitializationType { None, WithZero }; > void initialize(InitializationType); >@@ -49,12 +49,11 @@ public: > static void visitChildren(JSCell*, SlotVisitor&); > > static size_t estimatedSize(JSCell*); >- static size_t allocationSize(int length); >+ static size_t allocationSize(unsigned length); > > static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); >- > static JSBigInt* createZero(VM&); >- static JSBigInt* createWithLength(VM&, int length); >+ static JSBigInt* createWithLength(VM&, unsigned length); > > static JSBigInt* createFrom(VM&, int32_t value); > static JSBigInt* createFrom(VM&, uint32_t value); >@@ -70,14 +69,14 @@ public: > void setSign(bool sign) { m_sign = sign; } > bool sign() const { return m_sign; } > >- void setLength(int length) { m_length = length; } >- int length() const { return m_length; } >+ void setLength(unsigned length) { m_length = length; } >+ unsigned length() const { return m_length; } > > static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix); > static JSBigInt* parseInt(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*); > >@@ -85,12 +84,14 @@ public: > double toNumber(ExecState*) const; > > JSObject* toObject(ExecState*, JSGlobalObject*) const; >+ >+ static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y); > > private: > using Digit = uintptr_t; >- static constexpr const int bitsPerByte = 8; >- static constexpr const int digitBits = sizeof(Digit) * bitsPerByte; >- static constexpr const int halfDigitBits = digitBits / 2; >+ static constexpr const unsigned bitsPerByte = 8; >+ static constexpr const unsigned digitBits = sizeof(Digit) * bitsPerByte; >+ static constexpr const unsigned halfDigitBits = digitBits / 2; > static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1; > static constexpr const int maxInt = 0x7FFFFFFF; > >@@ -98,12 +99,13 @@ private: > // 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 const int maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte); >+ static const unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte); > >- static uint64_t calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign); >+ static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); > > static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); >- static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result); >+ static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result); >+ static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex); > > // Digit arithmetic helpers. > static Digit digitAdd(Digit a, Digit b, Digit& carry); >@@ -112,17 +114,17 @@ private: > static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder); > static Digit digitPow(Digit base, Digit exponent); > >- static String toStringGeneric(ExecState&, JSBigInt*, int radix); >+ static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix); > > bool isZero(); > > template <typename CharType> >- static JSBigInt* parseInt(ExecState*, CharType* data, int length); >+ static JSBigInt* parseInt(ExecState*, CharType* data, unsigned length); > > 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, bool allowEmptyString = true); > >- static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount); >+ static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); > > JSBigInt* rightTrim(VM&); > >@@ -131,10 +133,10 @@ private: > static size_t offsetOfData(); > Digit* dataStorage(); > >- Digit digit(int); >- void setDigit(int, Digit); >+ Digit digit(unsigned); >+ void setDigit(unsigned, Digit); > >- int m_length; >+ unsigned m_length; > bool m_sign; > }; > >diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h >index 21e80f87503c7ef91b7b2105eb0c725da2eab763..91dc1a40f14e37672f4101604c0690e6097e18fc 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValue.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValue.h >@@ -39,6 +39,7 @@ > namespace JSC { > > class AssemblyHelpers; >+class JSBigInt; > class ExecState; > class JSCell; > class JSValueSource; >@@ -257,6 +258,8 @@ public: > // toNumber conversion is expected to be side effect free if an exception has > // been set in the ExecState already. > double toNumber(ExecState*) const; >+ >+ Variant<JSBigInt*, double> toNumeric(ExecState*) const; > > // toNumber conversion if it can be done without side effects. > std::optional<double> toNumberFromPrimitive() const; >diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >index d0d3799fb39ec3182dcd2149607060e35b5b279a..a87267c21ad1ab44bd5d730d28e0a043354295f3 100644 >--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h >@@ -37,6 +37,7 @@ > #include "JSProxy.h" > #include "JSStringInlines.h" > #include "MathCommon.h" >+#include <wtf/Variant.h> > #include <wtf/text/StringImpl.h> > > namespace JSC { >@@ -728,6 +729,26 @@ ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const > return toNumberSlowCase(exec); > } > >+ALWAYS_INLINE Variant<JSBigInt*, double> JSValue::toNumeric(ExecState* exec) const >+{ >+ if (isInt32()) >+ return asInt32(); >+ if (isDouble()) >+ return asDouble(); >+ if (isBigInt()) >+ return asBigInt(*this); >+ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ JSValue primValue = this->toPrimitive(exec, PreferNumber); >+ RETURN_IF_EXCEPTION(scope, 0); >+ if (primValue.isBigInt()) >+ return asBigInt(primValue); >+ double value = primValue.toNumber(exec); >+ RETURN_IF_EXCEPTION(scope, 0); >+ return value; >+} >+ > inline JSObject* JSValue::toObject(ExecState* exec) const > { > return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); >diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h >index 1349aec16a7a83a8a8a590acefd54b179c97bf1f..495590bb886ea0af3ba5d81ef20ffd745500a75e 100644 >--- a/Source/JavaScriptCore/runtime/Operations.h >+++ b/Source/JavaScriptCore/runtime/Operations.h >@@ -23,7 +23,9 @@ > > #include "CallFrame.h" > #include "ExceptionHelpers.h" >+#include "JSBigInt.h" > #include "JSCJSValue.h" >+#include <wtf/Variant.h> > > namespace JSC { > >@@ -256,6 +258,29 @@ ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2) > return jsAddSlowCase(callFrame, v1, v2); > } > >+ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2) >+{ >+ VM& vm = state->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ Variant<JSBigInt*, double> leftNumeric = v1.toNumeric(state); >+ RETURN_IF_EXCEPTION(scope, { }); >+ Variant<JSBigInt*, double> rightNumeric = v2.toNumeric(state); >+ RETURN_IF_EXCEPTION(scope, { }); >+ >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) >+ return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >+ >+ throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in multiplication.")); >+ return { }; >+ } >+ >+ double leftValue = WTF::get<double>(leftNumeric); >+ double rightValue = WTF::get<double>(rightNumeric); >+ return jsNumber(leftValue * rightValue); >+} >+ > inline bool scribbleFreeCells() > { > return !ASSERT_DISABLED || Options::scribbleFreeCells(); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 1392a0da98f3a9a1428c97c3d626879e077d5274..c99325b4aaacfa9c8766b2648532e785f82568f3 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,19 @@ >+2018-05-01 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement support for "*" operation >+ https://bugs.webkit.org/show_bug.cgi?id=183721 >+ >+ Reviewed by Saam Barati. >+ >+ * bigIntTests.yaml: >+ * stress/big-int-mul-jit.js: Added. >+ * stress/big-int-mul-to-primitive-precedence.js: Added. >+ * stress/big-int-mul-to-primitive.js: Added. >+ * stress/big-int-mul-type-error.js: Added. >+ * stress/big-int-mul-wrapped-value.js: Added. >+ * stress/big-int-multiplication.js: Added. >+ * stress/big-int-multiply-memory-stress.js: Added. >+ > 2018-04-28 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r231131. >diff --git a/JSTests/bigIntTests.yaml b/JSTests/bigIntTests.yaml >index 7ae22cb1bb2aff62cc4ddf496299f96a0744f7ae..e947dc2945adf90d077fc837d5583a1d08e3bc91 100644 >--- a/JSTests/bigIntTests.yaml >+++ b/JSTests/bigIntTests.yaml >@@ -97,3 +97,24 @@ > - path: stress/big-int-to-string.js > cmd: runBigIntEnabled > >+- path: stress/big-int-mul-jit.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-mul-to-primitive-precedence.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-mul-to-primitive.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-mul-type-error.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-mul-wrapped-value.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-multiplication.js >+ cmd: runBigIntEnabled >+ >+- path: stress/big-int-multiply-memory-stress.js >+ cmd: runBigIntEnabled >+ >diff --git a/JSTests/stress/big-int-mul-jit.js b/JSTests/stress/big-int-mul-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..0cbede31875d21fb3822e7f28ff05bcaca1c9f7a >--- /dev/null >+++ b/JSTests/stress/big-int-mul-jit.js >@@ -0,0 +1,19 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntMul(x, y) { >+ return x * y; >+} >+noInline(bigIntMul); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntMul(3n, 10n); >+ assert.sameValue(r, 30n, 3n + " * " + 10n + " = " + r); >+} >+ >diff --git a/JSTests/stress/big-int-mul-to-primitive-precedence.js b/JSTests/stress/big-int-mul-to-primitive-precedence.js >new file mode 100644 >index 0000000000000000000000000000000000000000..7149a19687e14aee7013b36864492e682bd5e75e >--- /dev/null >+++ b/JSTests/stress/big-int-mul-to-primitive-precedence.js >@@ -0,0 +1,39 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testMul(x, y, z, message) { >+ assert.sameValue(x * y, z, message); >+ assert.sameValue(y * x, z, message); >+} >+ >+testMul(Object(2n), 1n, 2n, "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"); >+ } >+}; >+testMul(o, 1n, 2n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ }, >+ toString: function () { >+ throw new Error("Should never execute it"); >+ } >+}; >+testMul(o, 1n, 2n, "ToPrimitive: valueOf"); >+ >diff --git a/JSTests/stress/big-int-mul-to-primitive.js b/JSTests/stress/big-int-mul-to-primitive.js >new file mode 100644 >index 0000000000000000000000000000000000000000..642e2e8e29119e27d13577cb57ac2f97350fe6cc >--- /dev/null >+++ b/JSTests/stress/big-int-mul-to-primitive.js >@@ -0,0 +1,35 @@ >+//@ runBigIntEnabled >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+assert.sameValue = function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+} >+ >+function testMul(x, y, z) { >+ assert.sameValue(x * y, z, x + " * " + y + " = " + z); >+ assert.sameValue(y * x, z, y + " * " + x + " = " + z); >+} >+ >+let o = { >+ [Symbol.toPrimitive]: function () { return 300000000000000n; } >+} >+ >+testMul(500000000000438n, o, 150000000000131400000000000000n); >+ >+o.valueOf = function () { >+ throw new Error("Should never execute it"); >+}; >+ >+testMul(700000000000438n, o, 210000000000131400000000000000n); >+ >+o.toString = function () { >+ throw new Error("Should never execute it"); >+}; >+ >+testMul(700000000000438n, o, 210000000000131400000000000000n); >+ >diff --git a/JSTests/stress/big-int-mul-type-error.js b/JSTests/stress/big-int-mul-type-error.js >new file mode 100644 >index 0000000000000000000000000000000000000000..b5178457fb623757fd0e773577dc396f2f30fe60 >--- /dev/null >+++ b/JSTests/stress/big-int-mul-type-error.js >@@ -0,0 +1,106 @@ >+//@ runBigIntEnabled >+ >+function assert(a, message) { >+ if (!a) >+ throw new Error(message); >+} >+ >+function assertThrowTypeError(a, b, message) { >+ try { >+ let n = a * b; >+ assert(false, message + ": Should throw TypeError, but executed without exception"); >+ } catch (e) { >+ assert(e instanceof TypeError, message + ": expected TypeError, got: " + e); >+ } >+} >+ >+assertThrowTypeError(30n, "foo", "BigInt * String"); >+assertThrowTypeError("bar", 18757382984821n, "String * BigInt"); >+assertThrowTypeError(30n, Symbol("foo"), "BigInt * Symbol"); >+assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol * BigInt"); >+assertThrowTypeError(30n, 3320, "BigInt * Int32"); >+assertThrowTypeError(33256, 18757382984821n, "Int32 * BigInt"); >+assertThrowTypeError(30n, 0.543, "BigInt * Double"); >+assertThrowTypeError(230.19293, 18757382984821n, "Double * BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt * NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN * BigInt"); >+assertThrowTypeError(30n, NaN, "BigInt * NaN"); >+assertThrowTypeError(NaN, 18757382984821n, "NaN * BigInt"); >+assertThrowTypeError(30n, +Infinity, "BigInt * NaN"); >+assertThrowTypeError(+Infinity, 18757382984821n, "NaN * BigInt"); >+assertThrowTypeError(30n, -Infinity, "BigInt * -Infinity"); >+assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity * BigInt"); >+assertThrowTypeError(30n, null, "BigInt * null"); >+assertThrowTypeError(null, 18757382984821n, "null * BigInt"); >+assertThrowTypeError(30n, undefined, "BigInt * undefined"); >+assertThrowTypeError(undefined, 18757382984821n, "undefined * BigInt"); >+assertThrowTypeError(30n, true, "BigInt * true"); >+assertThrowTypeError(true, 18757382984821n, "true * BigInt"); >+assertThrowTypeError(30n, false, "BigInt * false"); >+assertThrowTypeError(false, 18757382984821n, "false * BigInt"); >+ >+// Error when returning from object >+ >+let o = { >+ valueOf: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.valueOf returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol * BigInt"); >+ >+o = { >+ valueOf: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.valueOf returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 * BigInt"); >+ >+o = { >+ valueOf: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.valueOf returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double * BigInt"); >+ >+o = { >+ toString: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.toString returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol * BigInt"); >+ >+o = { >+ toString: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.toString returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 * BigInt"); >+ >+o = { >+ toString: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.toString returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double * BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return Symbol("Foo"); } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.@@toPrimitive returning Symbol"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol * BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 33256; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.@@toPrimitive returning Int32"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 * BigInt"); >+ >+o = { >+ [Symbol.toPrimitive]: function () { return 0.453; } >+}; >+ >+assertThrowTypeError(30n, o, "BigInt * Object.@@toPrimitive returning Double"); >+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double * BigInt"); >+ >diff --git a/JSTests/stress/big-int-mul-wrapped-value.js b/JSTests/stress/big-int-mul-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..b673d8a60302faf66dfa6cfa1eb1370ec8c22c3a >--- /dev/null >+++ b/JSTests/stress/big-int-mul-wrapped-value.js >@@ -0,0 +1,37 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testMul(x, y, z, message) { >+ assert.sameValue(x * y, z, message); >+ assert.sameValue(y * x, z, message); >+} >+ >+testMul(Object(2n), 1n, 2n, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 2n; >+ } >+}; >+testMul(o, 1n, 2n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 2n; >+ } >+}; >+testMul(o, 1n, 2n, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 2n; >+ } >+} >+testMul(o, 1n, 2n, "ToPrimitive: toString"); >+ >diff --git a/JSTests/stress/big-int-multiplication.js b/JSTests/stress/big-int-multiplication.js >new file mode 100644 >index 0000000000000000000000000000000000000000..3ecd636d7f89a24acfbb81d72d755c228fe6fad9 >--- /dev/null >+++ b/JSTests/stress/big-int-multiplication.js >@@ -0,0 +1,83 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Robin Templeton. All rights reserved. >+// This code is governed by the BSD license found in the LICENSE file. >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testMul(x, y, z) { >+ assert.sameValue(x * y, z, x + " * " + y + " = " + z); >+ assert.sameValue(y * x, z, y + " * " + x + " = " + z); >+} >+ >+testMul(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0xFDBAC097C8DC5ACCDEEC6CD7A44A4100n); >+testMul(0xFEDCBA9876543210n, 0xFEDCBA98n, 0xFDBAC097530ECA86541D5980n); >+testMul(0xFEDCBA9876543210n, 0x1234n, 0x121F49F49F49F49F4B40n); >+testMul(0xFEDCBA9876543210n, 0x3n, 0x2FC962FC962FC9630n); >+testMul(0xFEDCBA9876543210n, 0x2n, 0x1FDB97530ECA86420n); >+testMul(0xFEDCBA9876543210n, 0x1n, 0xFEDCBA9876543210n); >+testMul(0xFEDCBA9876543210n, 0x0n, 0x0n); >+testMul(0xFEDCBA9876543210n, BigInt("-1"), BigInt("-18364758544493064720")); >+testMul(0xFEDCBA9876543210n, BigInt("-2"), BigInt("-36729517088986129440")); >+testMul(0xFEDCBA9876543210n, BigInt("-3"), BigInt("-55094275633479194160")); >+testMul(0xFEDCBA9876543210n, BigInt("-4660"), BigInt("-85579774817337681595200")); >+testMul(0xFEDCBA9876543210n, BigInt("-4275878551"), BigInt("-78525477154691874604502820720")); >+testMul(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0xFDBAC097C8DC5ACAE132F7A6B7A1DCE1n); >+testMul(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0xFDBAC09654320FECDEEC6CD9n); >+testMul(0xFEDCBA987654320Fn, 0x3n, 0x2FC962FC962FC962Dn); >+testMul(0xFEDCBA987654320Fn, 0x2n, 0x1FDB97530ECA8641En); >+testMul(0xFEDCBA987654320Fn, 0x1n, 0xFEDCBA987654320Fn); >+testMul(0xFEDCBA987654320Fn, 0x0n, 0x0n); >+testMul(0xFEDCBA987654320Fn, BigInt("-1"), BigInt("-18364758544493064719")); >+testMul(0xFEDCBA987654320Fn, BigInt("-2"), BigInt("-36729517088986129438")); >+testMul(0xFEDCBA987654320Fn, BigInt("-3"), BigInt("-55094275633479194157")); >+testMul(0xFEDCBA987654320Fn, BigInt("-4275878551"), BigInt("-78525477154691874600226942169")); >+testMul(0xFEDCBA987654320Fn, BigInt("-18364758544493064720"), BigInt("-337264356397531028976608289633615613680")); >+testMul(0xFEDCBA98n, 0xFEDCBA98n, 0xFDBAC096DD413A40n); >+testMul(0xFEDCBA98n, 0x1234n, 0x121F49F496E0n); >+testMul(0xFEDCBA98n, 0x3n, 0x2FC962FC8n); >+testMul(0xFEDCBA98n, 0x2n, 0x1FDB97530n); >+testMul(0xFEDCBA98n, 0x1n, 0xFEDCBA98n); >+testMul(0xFEDCBA98n, 0x0n, 0x0n); >+testMul(0xFEDCBA98n, BigInt("-1"), BigInt("-4275878552")); >+testMul(0xFEDCBA98n, BigInt("-2"), BigInt("-8551757104")); >+testMul(0xFEDCBA98n, BigInt("-3"), BigInt("-12827635656")); >+testMul(0xFEDCBA98n, BigInt("-4275878551"), BigInt("-18283137387177738152")); >+testMul(0xFEDCBA98n, BigInt("-18364758544493064720"), BigInt("-78525477173056633148995885440")); >+testMul(0x3n, 0x3n, 0x9n); >+testMul(0x3n, 0x2n, 0x6n); >+testMul(0x3n, 0x1n, 0x3n); >+testMul(0x3n, 0x0n, 0x0n); >+testMul(0x3n, BigInt("-1"), BigInt("-3")); >+testMul(0x3n, BigInt("-2"), BigInt("-6")); >+testMul(0x3n, BigInt("-3"), BigInt("-9")); >+testMul(0x3n, BigInt("-4660"), BigInt("-13980")); >+testMul(0x3n, BigInt("-4275878552"), BigInt("-12827635656")); >+testMul(0x3n, BigInt("-18364758544493064720"), BigInt("-55094275633479194160")); >+testMul(0x0n, 0x0n, 0x0n); >+testMul(0x0n, BigInt("-1"), 0x0n); >+testMul(0x0n, BigInt("-2"), 0x0n); >+testMul(0x0n, BigInt("-3"), 0x0n); >+testMul(0x0n, BigInt("-4275878551"), 0x0n); >+testMul(0x0n, BigInt("-18364758544493064719"), 0x0n); >+testMul(BigInt("-1"), BigInt("-1"), 0x1n); >+testMul(BigInt("-1"), BigInt("-2"), 0x2n); >+testMul(BigInt("-1"), BigInt("-3"), 0x3n); >+testMul(BigInt("-1"), BigInt("-4660"), 0x1234n); >+testMul(BigInt("-1"), BigInt("-4275878551"), 0xFEDCBA97n); >+testMul(BigInt("-1"), BigInt("-4275878552"), 0xFEDCBA98n); >+testMul(BigInt("-1"), BigInt("-18364758544493064719"), 0xFEDCBA987654320Fn); >+testMul(BigInt("-1"), BigInt("-18364758544493064720"), 0xFEDCBA9876543210n); >+testMul(BigInt("-3"), BigInt("-3"), 0x9n); >+testMul(BigInt("-3"), BigInt("-4660"), 0x369Cn); >+testMul(BigInt("-3"), BigInt("-4275878551"), 0x2FC962FC5n); >+testMul(BigInt("-3"), BigInt("-4275878552"), 0x2FC962FC8n); >+testMul(BigInt("-3"), BigInt("-18364758544493064719"), 0x2FC962FC962FC962Dn); >+testMul(BigInt("-3"), BigInt("-18364758544493064720"), 0x2FC962FC962FC9630n); >+testMul(BigInt("-18364758544493064720"), BigInt("-18364758544493064720"), 0xFDBAC097C8DC5ACCDEEC6CD7A44A4100n); >+ >diff --git a/JSTests/stress/big-int-multiply-memory-stress.js b/JSTests/stress/big-int-multiply-memory-stress.js >new file mode 100644 >index 0000000000000000000000000000000000000000..1abaa7e28f9aee65d21c0d36f63df68023b9c897 >--- /dev/null >+++ b/JSTests/stress/big-int-multiply-memory-stress.js >@@ -0,0 +1,15 @@ >+//@ runBigIntEnabled >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+let a = 0n; >+let b = 1n; >+for (let i = 0; i < 1000000; i++) { >+ a = b * 30n; >+} >+ >+assert(a === 30n); >+
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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 183721
:
336016
|
336027
|
336955
|
338110
|
338959
|
338960
|
339014
|
339068
|
339214
|
339218
|
339413
|
339634
|
340159
|
340160
|
340240
|
340242