Changeset 231878 in webkit
- Timestamp:
- May 16, 2018 4:38:15 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 6 deleted
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r231871 r231878 1 2018-05-16 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, rolling out r231845. 4 https://bugs.webkit.org/show_bug.cgi?id=185702 5 6 it is breaking Apple High Sierra 32-bit JSC bot (Requested by 7 caiolima on #webkit). 8 9 Reverted changeset: 10 11 "[ESNext][BigInt] Implement support for "/" operation" 12 https://bugs.webkit.org/show_bug.cgi?id=183996 13 https://trac.webkit.org/changeset/231845 14 1 15 2018-05-16 Filip Pizlo <fpizlo@apple.com> 2 16 -
trunk/JSTests/bigIntTests.yaml
r231845 r231878 119 119 cmd: runBigIntEnabled 120 120 121 - path: stress/big-int-div-jit.js122 cmd: runBigIntEnabled123 124 - path: stress/big-int-div-memory-stress.js125 cmd: runBigIntEnabled126 127 - path: stress/big-int-div-to-primitive.js128 cmd: runBigIntEnabled129 130 - path: stress/big-int-div-type-error.js131 cmd: runBigIntEnabled132 133 - path: stress/big-int-div-wrapped-value.js134 cmd: runBigIntEnabled135 136 - path: stress/big-int-division.js137 cmd: runBigIntEnabled -
trunk/Source/JavaScriptCore/ChangeLog
r231871 r231878 1 2018-05-16 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, rolling out r231845. 4 https://bugs.webkit.org/show_bug.cgi?id=185702 5 6 it is breaking Apple High Sierra 32-bit JSC bot (Requested by 7 caiolima on #webkit). 8 9 Reverted changeset: 10 11 "[ESNext][BigInt] Implement support for "/" operation" 12 https://bugs.webkit.org/show_bug.cgi?id=183996 13 https://trac.webkit.org/changeset/231845 14 1 15 2018-05-16 Filip Pizlo <fpizlo@apple.com> 2 16 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r231845 r231878 76 76 #include "VMInlines.h" 77 77 #include <wtf/InlineASM.h> 78 #include <wtf/Variant.h>79 78 80 79 #if ENABLE(JIT) … … 426 425 JSValue op2 = JSValue::decode(encodedOp2); 427 426 428 auto leftNumeric = op1.toNumeric(exec);427 double a = op1.toNumber(exec); 429 428 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 430 auto rightNumeric = op2.toNumeric(exec);431 RETURN_IF_EXCEPTION(scope, encodedJSValue());432 433 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {434 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {435 JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));436 RETURN_IF_EXCEPTION(scope, encodedJSValue());437 return JSValue::encode(result);438 }439 440 return throwVMTypeError(exec, scope, "Invalid operand in BigInt operation.");441 }442 443 429 scope.release(); 444 445 double a = WTF::get<double>(leftNumeric); 446 double b = WTF::get<double>(rightNumeric); 430 double b = op2.toNumber(exec); 447 431 return JSValue::encode(jsNumber(a / b)); 448 432 } -
trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp
r231845 r231878 104 104 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 105 105 106 String resultString = value->toString( state, radix);106 String resultString = value->toString(*state, radix); 107 107 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 108 108 scope.release(); -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r231845 r231878 517 517 JSValue left = OP_C(2).jsValue(); 518 518 JSValue right = OP_C(3).jsValue(); 519 auto leftNumeric = left.toNumeric(exec); 520 CHECK_EXCEPTION(); 521 auto rightNumeric = right.toNumeric(exec); 522 CHECK_EXCEPTION(); 523 524 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { 525 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { 526 JSValue result(JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))); 527 CHECK_EXCEPTION(); 528 RETURN_WITH_PROFILING(result, { 529 updateArithProfileForBinaryArithOp(exec, pc, result, left, right); 530 }); 531 } 532 533 THROW(createTypeError(exec, "Invalid mix of BigInt and other type in division.")); 534 } 535 536 double a = WTF::get<double>(leftNumeric); 537 double b = WTF::get<double>(rightNumeric); 519 double a = left.toNumber(exec); 520 if (UNLIKELY(throwScope.exception())) 521 RETURN(JSValue()); 522 double b = right.toNumber(exec); 523 if (UNLIKELY(throwScope.exception())) 524 RETURN(JSValue()); 538 525 JSValue result = jsNumber(a / b); 539 526 RETURN_WITH_PROFILING(result, { -
trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp
r231845 r231878 228 228 } 229 229 230 String JSBigInt::toString(ExecState *state, unsigned radix)230 String JSBigInt::toString(ExecState& state, unsigned radix) 231 231 { 232 232 if (this->isZero()) 233 return state ->vm().smallStrings.singleCharacterStringRep('0');233 return state.vm().smallStrings.singleCharacterStringRep('0'); 234 234 235 235 return toStringGeneric(state, this, radix); … … 269 269 result->setSign(x->sign() != y->sign()); 270 270 return result->rightTrim(vm); 271 }272 273 JSBigInt* JSBigInt::divide(ExecState* state, JSBigInt* x, JSBigInt* y)274 {275 // 1. If y is 0n, throw a RangeError exception.276 VM& vm = state->vm();277 auto scope = DECLARE_THROW_SCOPE(vm);278 279 if (y->isZero()) {280 throwRangeError(state, scope, ASCIILiteral("0 is an invalid divisor value."));281 return nullptr;282 }283 284 // 2. Let quotient be the mathematical value of x divided by y.285 // 3. Return a BigInt representing quotient rounded towards 0 to the next286 // integral value.287 if (absoluteCompare(x, y) == ComparisonResult::LessThan)288 return createZero(vm);289 290 JSBigInt* quotient = nullptr;291 bool resultSign = x->sign() != y->sign();292 if (y->length() == 1) {293 Digit divisor = y->digit(0);294 if (divisor == 1)295 return resultSign == x->sign() ? x : unaryMinus(vm, x);296 297 Digit remainder;298 absoluteDivWithDigitDivisor(vm, x, divisor, "ient, remainder);299 } else300 absoluteDivWithBigIntDivisor(vm, x, y, "ient, nullptr);301 302 quotient->setSign(resultSign);303 return quotient->rightTrim(vm);304 }305 306 JSBigInt* JSBigInt::copy(VM& vm, JSBigInt* x)307 {308 ASSERT(!x->isZero());309 310 JSBigInt* result = JSBigInt::createWithLength(vm, x->length());311 std::copy(x->dataStorage(), x->dataStorage() + x->length(), result->dataStorage());312 result->setSign(x->sign());313 return result;314 }315 316 JSBigInt* JSBigInt::unaryMinus(VM& vm, JSBigInt* x)317 {318 if (x->isZero())319 return x;320 321 JSBigInt* result = copy(vm, x);322 result->setSign(!x->sign());323 return result;324 271 } 325 272 … … 576 523 } 577 524 578 inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigInt* y)579 {580 ASSERT(!x->length() || x->digit(0));581 ASSERT(!y->length() || y->digit(0));582 583 int diff = x->length() - y->length();584 if (diff)585 return diff < 0 ? ComparisonResult::LessThan : ComparisonResult::GreaterThan;586 587 int i = x->length() - 1;588 while (i >= 0 && x->digit(i) == y->digit(i))589 i--;590 591 if (i < 0)592 return ComparisonResult::Equal;593 594 return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;595 }596 597 525 // Divides {x} by {divisor}, returning the result in {quotient} and {remainder}. 598 526 // Mathematically, the contract is: … … 602 530 // {quotient} can be the same as {x} for an in-place division. {quotient} can 603 531 // also be nullptr if the caller is only interested in the remainder. 604 void JSBigInt::absoluteDiv WithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder)532 void JSBigInt::absoluteDivSmall(ExecState& state, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder) 605 533 { 606 534 ASSERT(divisor); 607 535 536 VM& vm = state.vm(); 608 537 ASSERT(!x->isZero()); 609 538 remainder = 0; … … 627 556 digitDiv(remainder, x->digit(i), divisor, remainder); 628 557 } 629 }630 631 // Divides {dividend} by {divisor}, returning the result in {quotient} and632 // {remainder}. Mathematically, the contract is:633 // quotient = (dividend - remainder) / divisor, with 0 <= remainder < divisor.634 // Both {quotient} and {remainder} are optional, for callers that are only635 // interested in one of them.636 // See Knuth, Volume 2, section 4.3.1, Algorithm D.637 void JSBigInt::absoluteDivWithBigIntDivisor(VM& vm, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder)638 {639 ASSERT(divisor->length() >= 2);640 ASSERT(dividend->length() >= divisor->length());641 642 // The unusual variable names inside this function are consistent with643 // Knuth's book, as well as with Go's implementation of this algorithm.644 // Maintaining this consistency is probably more useful than trying to645 // come up with more descriptive names for them.646 unsigned n = divisor->length();647 unsigned m = dividend->length() - n;648 649 // The quotient to be computed.650 JSBigInt* q = nullptr;651 if (quotient != nullptr)652 q = createWithLength(vm, m + 1);653 654 // In each iteration, {qhatv} holds {divisor} * {current quotient digit}.655 // "v" is the book's name for {divisor}, "qhat" the current quotient digit.656 JSBigInt* qhatv = createWithLength(vm, m + 1);657 658 // D1.659 // Left-shift inputs so that the divisor's MSB is set. This is necessary660 // to prevent the digit-wise divisions (see digit_div call below) from661 // overflowing (they take a two digits wide input, and return a one digit662 // result).663 Digit lastDigit = divisor->digit(n - 1);664 unsigned shift = sizeof(lastDigit) == 8 ? clz64(lastDigit) : clz32(lastDigit);665 666 if (shift > 0)667 divisor = absoluteLeftShiftAlwaysCopy(vm, divisor, shift, LeftShiftMode::SameSizeResult);668 669 // Holds the (continuously updated) remaining part of the dividend, which670 // eventually becomes the remainder.671 JSBigInt* u = absoluteLeftShiftAlwaysCopy(vm, dividend, shift, LeftShiftMode::AlwaysAddOneDigit);672 673 // D2.674 // Iterate over the dividend's digit (like the "grad school" algorithm).675 // {vn1} is the divisor's most significant digit.676 Digit vn1 = divisor->digit(n - 1);677 for (int j = m; j >= 0; j--) {678 // D3.679 // Estimate the current iteration's quotient digit (see Knuth for details).680 // {qhat} is the current quotient digit.681 Digit qhat = std::numeric_limits<Digit>::max();682 683 // {ujn} is the dividend's most significant remaining digit.684 Digit ujn = u->digit(j + n);685 if (ujn != vn1) {686 // {rhat} is the current iteration's remainder.687 Digit rhat = 0;688 // Estimate the current quotient digit by dividing the most significant689 // digits of dividend and divisor. The result will not be too small,690 // but could be a bit too large.691 qhat = digitDiv(ujn, u->digit(j + n - 1), vn1, rhat);692 693 // Decrement the quotient estimate as needed by looking at the next694 // digit, i.e. by testing whether695 // qhat * v_{n-2} > (rhat << digitBits) + u_{j+n-2}.696 Digit vn2 = divisor->digit(n - 2);697 Digit ujn2 = u->digit(j + n - 2);698 while (productGreaterThan(qhat, vn2, rhat, ujn2)) {699 qhat--;700 Digit prevRhat = rhat;701 rhat += vn1;702 // v[n-1] >= 0, so this tests for overflow.703 if (rhat < prevRhat)704 break;705 }706 }707 708 // D4.709 // Multiply the divisor with the current quotient digit, and subtract710 // it from the dividend. If there was "borrow", then the quotient digit711 // was one too high, so we must correct it and undo one subtraction of712 // the (shifted) divisor.713 internalMultiplyAdd(divisor, qhat, 0, n, qhatv);714 Digit c = u->absoluteInplaceSub(qhatv, j);715 if (c) {716 c = u->absoluteInplaceAdd(divisor, j);717 u->setDigit(j + n, u->digit(j + n) + c);718 qhat--;719 }720 721 if (quotient != nullptr)722 q->setDigit(j, qhat);723 }724 725 if (quotient != nullptr) {726 // Caller will right-trim.727 *quotient = q;728 }729 730 if (remainder != nullptr) {731 u->inplaceRightShift(shift);732 *remainder = u;733 }734 }735 736 // Returns whether (factor1 * factor2) > (high << kDigitBits) + low.737 inline bool JSBigInt::productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low)738 {739 Digit resultHigh;740 Digit resultLow = digitMul(factor1, factor2, resultHigh);741 return resultHigh > high || (resultHigh == high && resultLow > low);742 }743 744 // Adds {summand} onto {this}, starting with {summand}'s 0th digit745 // at {this}'s {startIndex}'th digit. Returns the "carry" (0 or 1).746 JSBigInt::Digit JSBigInt::absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex)747 {748 Digit carry = 0;749 unsigned n = summand->length();750 ASSERT(length() >= startIndex + n);751 for (unsigned i = 0; i < n; i++) {752 Digit newCarry = 0;753 Digit sum = digitAdd(digit(startIndex + i), summand->digit(i), newCarry);754 sum = digitAdd(sum, carry, newCarry);755 setDigit(startIndex + i, sum);756 carry = newCarry;757 }758 759 return carry;760 }761 762 // Subtracts {subtrahend} from {this}, starting with {subtrahend}'s 0th digit763 // at {this}'s {startIndex}-th digit. Returns the "borrow" (0 or 1).764 JSBigInt::Digit JSBigInt::absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex)765 {766 Digit borrow = 0;767 unsigned n = subtrahend->length();768 ASSERT(length() >= startIndex + n);769 for (unsigned i = 0; i < n; i++) {770 Digit newBorrow = 0;771 Digit difference = digitSub(digit(startIndex + i), subtrahend->digit(i), newBorrow);772 difference = digitSub(difference, borrow, newBorrow);773 setDigit(startIndex + i, difference);774 borrow = newBorrow;775 }776 777 return borrow;778 }779 780 void JSBigInt::inplaceRightShift(unsigned shift)781 {782 ASSERT(shift < digitBits);783 ASSERT(!(digit(0) & ((static_cast<Digit>(1) << shift) - 1)));784 785 if (!shift)786 return;787 788 Digit carry = digit(0) >> shift;789 unsigned last = length() - 1;790 for (unsigned i = 0; i < last; i++) {791 Digit d = digit(i + 1);792 setDigit(i, (d << (digitBits - shift)) | carry);793 carry = d >> shift;794 }795 setDigit(last, carry);796 }797 798 // Always copies the input, even when {shift} == 0.799 JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(VM& vm, JSBigInt* x, unsigned shift, LeftShiftMode mode)800 {801 ASSERT(shift < digitBits);802 ASSERT(!x->isZero());803 804 unsigned n = x->length();805 unsigned resultLength = mode == LeftShiftMode::AlwaysAddOneDigit ? n + 1 : n;806 JSBigInt* result = createWithLength(vm, resultLength);807 808 if (!shift) {809 for (unsigned i = 0; i < n; i++)810 result->setDigit(i, x->digit(i));811 if (mode == LeftShiftMode::AlwaysAddOneDigit)812 result->setDigit(n, 0);813 814 return result;815 }816 817 Digit carry = 0;818 for (unsigned i = 0; i < n; i++) {819 Digit d = x->digit(i);820 result->setDigit(i, (d << shift) | carry);821 carry = d >> (digitBits - shift);822 }823 824 if (mode == LeftShiftMode::AlwaysAddOneDigit)825 result->setDigit(n, carry);826 else {827 ASSERT(mode == LeftShiftMode::SameSizeResult);828 ASSERT(!carry);829 }830 831 return result;832 558 } 833 559 … … 879 605 } 880 606 881 String JSBigInt::toStringGeneric(ExecState *state, JSBigInt* x, unsigned radix)607 String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix) 882 608 { 883 609 // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString … … 885 611 Vector<LChar> resultString; 886 612 887 VM& vm = state->vm();888 889 613 ASSERT(radix >= 2 && radix <= 36); 890 614 ASSERT(!x->isZero()); … … 897 621 898 622 if (maximumCharactersRequired > JSString::MaxLength) { 899 auto scope = DECLARE_THROW_SCOPE( vm);900 throwOutOfMemoryError( state, scope);623 auto scope = DECLARE_THROW_SCOPE(state.vm()); 624 throwOutOfMemoryError(&state, scope); 901 625 return String(); 902 626 } … … 923 647 do { 924 648 Digit chunk; 925 absoluteDiv WithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk);649 absoluteDivSmall(state, *dividend, chunkDivisor, &rest, chunk); 926 650 ASSERT(rest); 927 651 … … 971 695 return this; 972 696 973 unsigned nonZeroIndex = m_length - 1; 974 while (!digit(nonZeroIndex)) 697 ASSERT(m_length); 698 699 int nonZeroIndex = m_length - 1; 700 while (nonZeroIndex >= 0 && !digit(nonZeroIndex)) 975 701 nonZeroIndex--; 976 702 977 if (nonZeroIndex == m_length - 1)703 if (nonZeroIndex == static_cast<int>(m_length - 1)) 978 704 return this; 979 705 … … 1149 875 } 1150 876 1151 inlineJSBigInt::Digit JSBigInt::digit(unsigned n)1152 { 1153 ASSERT(n < length());877 JSBigInt::Digit JSBigInt::digit(unsigned n) 878 { 879 ASSERT(n >= 0 && n < length()); 1154 880 return dataStorage()[n]; 1155 881 } 1156 882 1157 inlinevoid JSBigInt::setDigit(unsigned n, Digit value)1158 { 1159 ASSERT(n < length());883 void JSBigInt::setDigit(unsigned n, Digit value) 884 { 885 ASSERT(n >= 0 && n < length()); 1160 886 dataStorage()[n] = value; 1161 887 } -
trunk/Source/JavaScriptCore/runtime/JSBigInt.h
r231845 r231878 83 83 84 84 std::optional<uint8_t> singleDigitValueForString(); 85 String toString(ExecState *, unsigned radix);85 String toString(ExecState&, unsigned radix); 86 86 87 87 JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*); … … 95 95 static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y); 96 96 97 static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);98 static JSBigInt* unaryMinus(VM&, JSBigInt* x);99 100 97 private: 101 98 102 enum classComparisonResult {99 enum ComparisonResult { 103 100 Equal, 104 101 Undefined, … … 122 119 static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); 123 120 124 static ComparisonResult absoluteCompare(JSBigInt* x, JSBigInt* y); 125 static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); 121 static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); 126 122 static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result); 127 123 static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex); 128 static void absoluteDivWithBigIntDivisor(VM&, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder);129 130 enum class LeftShiftMode {131 SameSizeResult,132 AlwaysAddOneDigit133 };134 135 static JSBigInt* absoluteLeftShiftAlwaysCopy(VM&, JSBigInt* x, unsigned shift, LeftShiftMode);136 static bool productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low);137 138 Digit absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex);139 Digit absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex);140 void inplaceRightShift(unsigned shift);141 124 142 125 // Digit arithmetic helpers. … … 147 130 static Digit digitPow(Digit base, Digit exponent); 148 131 149 static String toStringGeneric(ExecState *, JSBigInt*, unsigned radix);132 static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix); 150 133 151 134 bool isZero(); … … 161 144 static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); 162 145 163 static JSBigInt* copy(VM&, JSBigInt* x);164 146 JSBigInt* rightTrim(VM&); 165 147 -
trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp
r231845 r231878 383 383 if (auto digit = bigInt->singleDigitValueForString()) 384 384 return vm.smallStrings.singleCharacterString(*digit + '0'); 385 JSString* returnString = jsNontrivialString(&vm, bigInt->toString( exec, 10));385 JSString* returnString = jsNontrivialString(&vm, bigInt->toString(*exec, 10)); 386 386 RETURN_IF_EXCEPTION(scope, errorValue()); 387 387 return returnString;
Note: See TracChangeset
for help on using the changeset viewer.