Changeset 231845 in webkit
- Timestamp:
- May 16, 2018 7:26:30 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r231764 r231845 1 2018-05-16 Caio Lima <ticaiolima@gmail.com> 2 3 [ESNext][BigInt] Implement support for "/" operation 4 https://bugs.webkit.org/show_bug.cgi?id=183996 5 6 Reviewed by Yusuke Suzuki. 7 8 * bigIntTests.yaml: 9 * stress/big-int-div-jit.js: Added. 10 * stress/big-int-div-memory-stress.js: Added. 11 * stress/big-int-div-to-primitive-precedence.js: Added. 12 * stress/big-int-div-to-primitive.js: Added. 13 * stress/big-int-div-type-error.js: Added. 14 * stress/big-int-div-wrapped-value.js: Added. 15 * stress/big-int-division.js: Added. 16 1 17 2018-05-14 Leo Balter <leonardo.balter@gmail.com> 2 18 -
trunk/JSTests/bigIntTests.yaml
r231733 r231845 119 119 cmd: runBigIntEnabled 120 120 121 - path: stress/big-int-div-jit.js 122 cmd: runBigIntEnabled 123 124 - path: stress/big-int-div-memory-stress.js 125 cmd: runBigIntEnabled 126 127 - path: stress/big-int-div-to-primitive.js 128 cmd: runBigIntEnabled 129 130 - path: stress/big-int-div-type-error.js 131 cmd: runBigIntEnabled 132 133 - path: stress/big-int-div-wrapped-value.js 134 cmd: runBigIntEnabled 135 136 - path: stress/big-int-division.js 137 cmd: runBigIntEnabled -
trunk/Source/JavaScriptCore/ChangeLog
r231843 r231845 1 2018-05-16 Caio Lima <ticaiolima@gmail.com> 2 3 [ESNext][BigInt] Implement support for "/" operation 4 https://bugs.webkit.org/show_bug.cgi?id=183996 5 6 Reviewed by Yusuke Suzuki. 7 8 This patch is introducing the support for BigInt into divide 9 operation int LLInt and JIT layers. 10 11 * dfg/DFGOperations.cpp: 12 * runtime/CommonSlowPaths.cpp: 13 (JSC::SLOW_PATH_DECL): 14 * runtime/JSBigInt.cpp: 15 (JSC::JSBigInt::divide): 16 (JSC::JSBigInt::copy): 17 (JSC::JSBigInt::unaryMinus): 18 (JSC::JSBigInt::absoluteCompare): 19 (JSC::JSBigInt::absoluteDivLarge): 20 (JSC::JSBigInt::productGreaterThan): 21 (JSC::JSBigInt::inplaceAdd): 22 (JSC::JSBigInt::inplaceSub): 23 (JSC::JSBigInt::inplaceRightShift): 24 (JSC::JSBigInt::specialLeftShift): 25 (JSC::JSBigInt::digit): 26 (JSC::JSBigInt::setDigit): 27 * runtime/JSBigInt.h: 28 1 29 2018-05-16 Alberto Garcia <berto@igalia.com> 2 30 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r231839 r231845 76 76 #include "VMInlines.h" 77 77 #include <wtf/InlineASM.h> 78 #include <wtf/Variant.h> 78 79 79 80 #if ENABLE(JIT) … … 425 426 JSValue op2 = JSValue::decode(encodedOp2); 426 427 427 double a = op1.toNumber(exec);428 auto leftNumeric = op1.toNumeric(exec); 428 429 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 429 443 scope.release(); 430 double b = op2.toNumber(exec); 444 445 double a = WTF::get<double>(leftNumeric); 446 double b = WTF::get<double>(rightNumeric); 431 447 return JSValue::encode(jsNumber(a / b)); 432 448 } -
trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp
r228500 r231845 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
r231733 r231845 517 517 JSValue left = OP_C(2).jsValue(); 518 518 JSValue right = OP_C(3).jsValue(); 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()); 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); 525 538 JSValue result = jsNumber(a / b); 526 539 RETURN_WITH_PROFILING(result, { -
trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp
r231733 r231845 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 next 286 // 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 } else 300 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; 271 324 } 272 325 … … 523 576 } 524 577 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 525 597 // Divides {x} by {divisor}, returning the result in {quotient} and {remainder}. 526 598 // Mathematically, the contract is: … … 530 602 // {quotient} can be the same as {x} for an in-place division. {quotient} can 531 603 // also be nullptr if the caller is only interested in the remainder. 532 void JSBigInt::absoluteDiv Small(ExecState& state, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder)604 void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder) 533 605 { 534 606 ASSERT(divisor); 535 607 536 VM& vm = state.vm();537 608 ASSERT(!x->isZero()); 538 609 remainder = 0; … … 556 627 digitDiv(remainder, x->digit(i), divisor, remainder); 557 628 } 629 } 630 631 // Divides {dividend} by {divisor}, returning the result in {quotient} and 632 // {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 only 635 // 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 with 643 // Knuth's book, as well as with Go's implementation of this algorithm. 644 // Maintaining this consistency is probably more useful than trying to 645 // 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 necessary 660 // to prevent the digit-wise divisions (see digit_div call below) from 661 // overflowing (they take a two digits wide input, and return a one digit 662 // 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, which 670 // 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 significant 689 // 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 next 694 // digit, i.e. by testing whether 695 // 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 subtract 710 // it from the dividend. If there was "borrow", then the quotient digit 711 // was one too high, so we must correct it and undo one subtraction of 712 // 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 digit 745 // 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 digit 763 // 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; 558 832 } 559 833 … … 605 879 } 606 880 607 String JSBigInt::toStringGeneric(ExecState &state, JSBigInt* x, unsigned radix)881 String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix) 608 882 { 609 883 // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString … … 611 885 Vector<LChar> resultString; 612 886 887 VM& vm = state->vm(); 888 613 889 ASSERT(radix >= 2 && radix <= 36); 614 890 ASSERT(!x->isZero()); … … 621 897 622 898 if (maximumCharactersRequired > JSString::MaxLength) { 623 auto scope = DECLARE_THROW_SCOPE( state.vm());624 throwOutOfMemoryError( &state, scope);899 auto scope = DECLARE_THROW_SCOPE(vm); 900 throwOutOfMemoryError(state, scope); 625 901 return String(); 626 902 } … … 647 923 do { 648 924 Digit chunk; 649 absoluteDiv Small(state, *dividend, chunkDivisor, &rest, chunk);925 absoluteDivWithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk); 650 926 ASSERT(rest); 651 927 … … 695 971 return this; 696 972 697 ASSERT(m_length); 698 699 int nonZeroIndex = m_length - 1; 700 while (nonZeroIndex >= 0 && !digit(nonZeroIndex)) 973 unsigned nonZeroIndex = m_length - 1; 974 while (!digit(nonZeroIndex)) 701 975 nonZeroIndex--; 702 976 703 if (nonZeroIndex == static_cast<int>(m_length - 1))977 if (nonZeroIndex == m_length - 1) 704 978 return this; 705 979 … … 875 1149 } 876 1150 877 JSBigInt::Digit JSBigInt::digit(unsigned n)878 { 879 ASSERT(n >= 0 && n< length());1151 inline JSBigInt::Digit JSBigInt::digit(unsigned n) 1152 { 1153 ASSERT(n < length()); 880 1154 return dataStorage()[n]; 881 1155 } 882 1156 883 void JSBigInt::setDigit(unsigned n, Digit value)884 { 885 ASSERT(n >= 0 && n< length());1157 inline void JSBigInt::setDigit(unsigned n, Digit value) 1158 { 1159 ASSERT(n < length()); 886 1160 dataStorage()[n] = value; 887 1161 } -
trunk/Source/JavaScriptCore/runtime/JSBigInt.h
r231733 r231845 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 97 100 private: 98 101 99 enum ComparisonResult {102 enum class ComparisonResult { 100 103 Equal, 101 104 Undefined, … … 119 122 static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); 120 123 121 static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); 124 static ComparisonResult absoluteCompare(JSBigInt* x, JSBigInt* y); 125 static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); 122 126 static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result); 123 127 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 AlwaysAddOneDigit 133 }; 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); 124 141 125 142 // Digit arithmetic helpers. … … 130 147 static Digit digitPow(Digit base, Digit exponent); 131 148 132 static String toStringGeneric(ExecState &, JSBigInt*, unsigned radix);149 static String toStringGeneric(ExecState*, JSBigInt*, unsigned radix); 133 150 134 151 bool isZero(); … … 144 161 static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); 145 162 163 static JSBigInt* copy(VM&, JSBigInt* x); 146 164 JSBigInt* rightTrim(VM&); 147 165 -
trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp
r229410 r231845 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.