Changeset 231733 in webkit
- Timestamp:
- May 11, 2018 9:32:12 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 7 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r231710 r231733 1 2018-05-11 Caio Lima <ticaiolima@gmail.com> 2 3 [ESNext][BigInt] Implement support for "*" operation 4 https://bugs.webkit.org/show_bug.cgi?id=183721 5 6 Reviewed by Yusuke Suzuki. 7 8 * bigIntTests.yaml: 9 * stress/big-int-mul-jit.js: Added. 10 * stress/big-int-mul-to-primitive-precedence.js: Added. 11 * stress/big-int-mul-to-primitive.js: Added. 12 * stress/big-int-mul-type-error.js: Added. 13 * stress/big-int-mul-wrapped-value.js: Added. 14 * stress/big-int-multiplication.js: Added. 15 * stress/big-int-multiply-memory-stress.js: Added. 16 1 17 2018-05-11 Michael Saboff <msaboff@apple.com> 2 18 -
trunk/JSTests/bigIntTests.yaml
r231147 r231733 98 98 cmd: runBigIntEnabled 99 99 100 - path: stress/big-int-mul-jit.js 101 cmd: runBigIntEnabled 102 103 - path: stress/big-int-mul-to-primitive-precedence.js 104 cmd: runBigIntEnabled 105 106 - path: stress/big-int-mul-to-primitive.js 107 cmd: runBigIntEnabled 108 109 - path: stress/big-int-mul-type-error.js 110 cmd: runBigIntEnabled 111 112 - path: stress/big-int-mul-wrapped-value.js 113 cmd: runBigIntEnabled 114 115 - path: stress/big-int-multiplication.js 116 cmd: runBigIntEnabled 117 118 - path: stress/big-int-multiply-memory-stress.js 119 cmd: runBigIntEnabled 120 -
trunk/Source/JavaScriptCore/ChangeLog
r231719 r231733 1 2018-05-11 Caio Lima <ticaiolima@gmail.com> 2 3 [ESNext][BigInt] Implement support for "*" operation 4 https://bugs.webkit.org/show_bug.cgi?id=183721 5 6 Reviewed by Yusuke Suzuki. 7 8 Added BigInt support into times binary operator into LLInt and on 9 JITOperations profiledMul and unprofiledMul. We are also replacing all 10 uses of int to unsigned when there is no negative values for 11 variables. 12 13 * dfg/DFGConstantFoldingPhase.cpp: 14 (JSC::DFG::ConstantFoldingPhase::foldConstants): 15 * jit/JITOperations.cpp: 16 * runtime/CommonSlowPaths.cpp: 17 (JSC::SLOW_PATH_DECL): 18 * runtime/JSBigInt.cpp: 19 (JSC::JSBigInt::JSBigInt): 20 (JSC::JSBigInt::allocationSize): 21 (JSC::JSBigInt::createWithLength): 22 (JSC::JSBigInt::toString): 23 (JSC::JSBigInt::multiply): 24 (JSC::JSBigInt::digitDiv): 25 (JSC::JSBigInt::internalMultiplyAdd): 26 (JSC::JSBigInt::multiplyAccumulate): 27 (JSC::JSBigInt::equals): 28 (JSC::JSBigInt::absoluteDivSmall): 29 (JSC::JSBigInt::calculateMaximumCharactersRequired): 30 (JSC::JSBigInt::toStringGeneric): 31 (JSC::JSBigInt::rightTrim): 32 (JSC::JSBigInt::allocateFor): 33 (JSC::JSBigInt::parseInt): 34 (JSC::JSBigInt::digit): 35 (JSC::JSBigInt::setDigit): 36 * runtime/JSBigInt.h: 37 * runtime/JSCJSValue.h: 38 * runtime/JSCJSValueInlines.h: 39 (JSC::JSValue::toNumeric const): 40 * runtime/Operations.h: 41 (JSC::jsMul): 42 1 43 2018-05-11 Commit Queue <commit-queue@webkit.org> 2 44 -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r231514 r231733 149 149 150 150 // FIXME: Revisit this condition when introducing BigInt to JSC. 151 auto isNonString CellConstant = [] (JSValue value) {152 return value && value.isCell() && !value.isString() ;151 auto isNonStringOrBigIntCellConstant = [] (JSValue value) { 152 return value && value.isCell() && !value.isString() && !value.isBigInt(); 153 153 }; 154 154 155 if (isNonString CellConstant(child1Constant)) {155 if (isNonStringOrBigIntCellConstant(child1Constant)) { 156 156 node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2()); 157 157 changed = true; 158 } else if (isNonString CellConstant(child2Constant)) {158 } else if (isNonStringOrBigIntCellConstant(child2Constant)) { 159 159 node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1()); 160 160 changed = true; -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r231147 r231733 2555 2555 } 2556 2556 2557 ALWAYS_INLINE static EncodedJSValue unprofiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 2558 { 2557 ALWAYS_INLINE static EncodedJSValue unprofiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 2558 { 2559 JSValue op1 = JSValue::decode(encodedOp1); 2560 JSValue op2 = JSValue::decode(encodedOp2); 2561 2562 return JSValue::encode(jsMul(exec, op1, op2)); 2563 } 2564 2565 ALWAYS_INLINE static EncodedJSValue profiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true) 2566 { 2567 VM& vm = exec->vm(); 2559 2568 auto scope = DECLARE_THROW_SCOPE(vm); 2560 2569 JSValue op1 = JSValue::decode(encodedOp1); 2561 2570 JSValue op2 = JSValue::decode(encodedOp2); 2562 2571 2563 double a = op1.toNumber(exec);2564 RETURN_IF_EXCEPTION(scope, encodedJSValue());2565 scope.release();2566 double b = op2.toNumber(exec);2567 return JSValue::encode(jsNumber(a * b));2568 }2569 2570 ALWAYS_INLINE static EncodedJSValue profiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)2571 {2572 auto scope = DECLARE_THROW_SCOPE(vm);2573 JSValue op1 = JSValue::decode(encodedOp1);2574 JSValue op2 = JSValue::decode(encodedOp2);2575 2576 2572 if (shouldObserveLHSAndRHSTypes) 2577 2573 arithProfile.observeLHSAndRHS(op1, op2); 2578 2574 2579 double a = op1.toNumber(exec);2575 JSValue result = jsMul(exec, op1, op2); 2580 2576 RETURN_IF_EXCEPTION(scope, encodedJSValue()); 2581 double b = op2.toNumber(exec);2582 RETURN_IF_EXCEPTION(scope, encodedJSValue());2583 2584 JSValue result = jsNumber(a * b);2585 2577 arithProfile.observeResult(result); 2586 2578 return JSValue::encode(result); … … 2592 2584 NativeCallFrameTracer tracer(vm, exec); 2593 2585 2594 return unprofiledMul( *vm,exec, encodedOp1, encodedOp2);2586 return unprofiledMul(exec, encodedOp1, encodedOp2); 2595 2587 } 2596 2588 … … 2600 2592 NativeCallFrameTracer tracer(vm, exec); 2601 2593 2602 return unprofiledMul( *vm,exec, encodedOp1, encodedOp2);2594 return unprofiledMul(exec, encodedOp1, encodedOp2); 2603 2595 } 2604 2596 … … 2617 2609 #endif 2618 2610 2619 return unprofiledMul( *vm,exec, encodedOp1, encodedOp2);2611 return unprofiledMul(exec, encodedOp1, encodedOp2); 2620 2612 } 2621 2613 … … 2626 2618 2627 2619 ASSERT(arithProfile); 2628 return profiledMul( *vm,exec, encodedOp1, encodedOp2, *arithProfile);2620 return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile); 2629 2621 } 2630 2622 … … 2644 2636 #endif 2645 2637 2646 return profiledMul( *vm,exec, encodedOp1, encodedOp2, *arithProfile, false);2638 return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile, false); 2647 2639 } 2648 2640 … … 2654 2646 ArithProfile* arithProfile = mulIC->arithProfile(); 2655 2647 ASSERT(arithProfile); 2656 return profiledMul( *vm,exec, encodedOp1, encodedOp2, *arithProfile);2648 return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile); 2657 2649 } 2658 2650 -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r231345 r231733 66 66 #include "TypeProfilerLog.h" 67 67 #include <wtf/StringPrintStream.h> 68 #include <wtf/Variant.h> 68 69 69 70 namespace JSC { … … 489 490 JSValue left = OP_C(2).jsValue(); 490 491 JSValue right = OP_C(3).jsValue(); 491 double a = left.toNumber(exec); 492 if (UNLIKELY(throwScope.exception())) 493 RETURN(JSValue()); 494 double b = right.toNumber(exec); 495 JSValue result = jsNumber(a * b); 492 JSValue result = jsMul(exec, left, right); 493 CHECK_EXCEPTION(); 496 494 RETURN_WITH_PROFILING(result, { 497 495 updateArithProfileForBinaryArithOp(exec, pc, result, left, right); -
trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp
r231629 r231733 69 69 } 70 70 71 JSBigInt::JSBigInt(VM& vm, Structure* structure, intlength)71 JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length) 72 72 : Base(vm, structure) 73 73 , m_length(length) … … 93 93 } 94 94 95 size_t JSBigInt::allocationSize( intlength)95 size_t JSBigInt::allocationSize(unsigned length) 96 96 { 97 97 size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt)); … … 99 99 } 100 100 101 JSBigInt* JSBigInt::createWithLength(VM& vm, intlength)101 JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length) 102 102 { 103 103 JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length); … … 249 249 250 250 internalMultiplyAdd(this, factor, summand, length(), this); 251 } 252 253 JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y) 254 { 255 VM& vm = state->vm(); 256 257 if (x->isZero()) 258 return x; 259 if (y->isZero()) 260 return y; 261 262 unsigned resultLength = x->length() + y->length(); 263 JSBigInt* result = JSBigInt::createWithLength(vm, resultLength); 264 result->initialize(InitializationType::WithZero); 265 266 for (unsigned i = 0; i < x->length(); i++) 267 multiplyAccumulate(y, x->digit(i), result, i); 268 269 result->setSign(x->sign() != y->sign()); 270 return result->rightTrim(vm); 251 271 } 252 272 … … 364 384 // Adapted from Warren, Hacker's Delight, p. 152. 365 385 #if USE(JSVALUE64) 366 ints = clz64(divisor);386 unsigned s = clz64(divisor); 367 387 #else 368 ints = clz32(divisor);388 unsigned s = clz32(divisor); 369 389 #endif 370 390 divisor <<= s; … … 409 429 // Multiplies {source} with {factor} and adds {summand} to the result. 410 430 // {result} and {source} may be the same BigInt for inplace modification. 411 void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, intn, JSBigInt* result)431 void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned n, JSBigInt* result) 412 432 { 413 433 ASSERT(source->length() >= n); … … 416 436 Digit carry = summand; 417 437 Digit high = 0; 418 for ( inti = 0; i < n; i++) {438 for (unsigned i = 0; i < n; i++) { 419 439 Digit current = source->digit(i); 420 440 Digit newCarry = 0; … … 444 464 } 445 465 466 // Multiplies {multiplicand} with {multiplier} and adds the result to 467 // {accumulator}, starting at {accumulatorIndex} for the least-significant 468 // digit. 469 // Callers must ensure that {accumulator} is big enough to hold the result. 470 void JSBigInt::multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex) 471 { 472 ASSERT(accumulator->length() > multiplicand->length() + accumulatorIndex); 473 if (!multiplier) 474 return; 475 476 Digit carry = 0; 477 Digit high = 0; 478 for (unsigned i = 0; i < multiplicand->length(); i++, accumulatorIndex++) { 479 Digit acc = accumulator->digit(accumulatorIndex); 480 Digit newCarry = 0; 481 482 // Add last round's carryovers. 483 acc = digitAdd(acc, high, newCarry); 484 acc = digitAdd(acc, carry, newCarry); 485 486 // Compute this round's multiplication. 487 Digit multiplicandDigit = multiplicand->digit(i); 488 Digit low = digitMul(multiplier, multiplicandDigit, high); 489 acc = digitAdd(acc, low, newCarry); 490 491 // Store result and prepare for next round. 492 accumulator->setDigit(accumulatorIndex, acc); 493 carry = newCarry; 494 } 495 496 while (carry || high) { 497 ASSERT(accumulatorIndex < accumulator->length()); 498 Digit acc = accumulator->digit(accumulatorIndex); 499 Digit newCarry = 0; 500 acc = digitAdd(acc, high, newCarry); 501 high = 0; 502 acc = digitAdd(acc, carry, newCarry); 503 accumulator->setDigit(accumulatorIndex, acc); 504 carry = newCarry; 505 accumulatorIndex++; 506 } 507 } 508 446 509 bool JSBigInt::equals(JSBigInt* x, JSBigInt* y) 447 510 { … … 452 515 return false; 453 516 454 for ( inti = 0; i < x->length(); i++) {517 for (unsigned i = 0; i < x->length(); i++) { 455 518 if (x->digit(i) != y->digit(i)) 456 519 return false; … … 480 543 } 481 544 482 intlength = x->length();545 unsigned length = x->length(); 483 546 if (quotient != nullptr) { 484 547 if (*quotient == nullptr) … … 507 570 }; 508 571 509 static const intbitsPerCharTableShift = 5;572 static const unsigned bitsPerCharTableShift = 5; 510 573 static const size_t bitsPerCharTableMultiplier = 1u << bitsPerCharTableShift; 511 574 512 575 // Compute (an overapproximation of) the length of the resulting string: 513 576 // Divide bit length of the BigInt by bits representable per character. 514 uint64_t JSBigInt::calculateMaximumCharactersRequired( int length, intradix, Digit lastDigit, bool sign)515 { 516 intleadingZeros;577 uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign) 578 { 579 unsigned leadingZeros; 517 580 if (sizeof(lastDigit) == 8) 518 581 leadingZeros = clz64(lastDigit); … … 542 605 } 543 606 544 String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, intradix)607 String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix) 545 608 { 546 609 // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString … … 551 614 ASSERT(!x->isZero()); 552 615 553 intlength = x->length();616 unsigned length = x->length(); 554 617 bool sign = x->sign(); 555 618 … … 567 630 lastDigit = x->digit(0); 568 631 else { 569 intchunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;632 unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar; 570 633 Digit chunkDivisor = digitPow(radix, chunkChars); 571 634 572 635 // By construction of chunkChars, there can't have been overflow. 573 636 ASSERT(chunkDivisor); 574 intnonZeroDigit = length - 1;637 unsigned nonZeroDigit = length - 1; 575 638 ASSERT(x->digit(nonZeroDigit)); 576 639 … … 588 651 589 652 dividend = &rest; 590 for ( inti = 0; i < chunkChars; i++) {653 for (unsigned i = 0; i < chunkChars; i++) { 591 654 resultString.append(radixDigits[chunk % radix]); 592 655 chunk /= radix; … … 613 676 614 677 // Remove leading zeroes. 615 intnewSizeNoLeadingZeroes = resultString.size();678 unsigned newSizeNoLeadingZeroes = resultString.size(); 616 679 while (newSizeNoLeadingZeroes > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0') 617 680 newSizeNoLeadingZeroes--; … … 631 694 if (isZero()) 632 695 return this; 696 697 ASSERT(m_length); 633 698 634 699 int nonZeroIndex = m_length - 1; … … 636 701 nonZeroIndex--; 637 702 638 if (nonZeroIndex == m_length - 1)703 if (nonZeroIndex == static_cast<int>(m_length - 1)) 639 704 return this; 640 705 641 intnewLength = nonZeroIndex + 1;706 unsigned newLength = nonZeroIndex + 1; 642 707 JSBigInt* trimmedBigInt = createWithLength(vm, newLength); 643 708 RELEASE_ASSERT(trimmedBigInt); … … 649 714 } 650 715 651 JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, intcharcount)716 JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount) 652 717 { 653 718 ASSERT(2 <= radix && radix <= 36); … … 656 721 size_t bitsPerChar = maxBitsPerCharTable[radix]; 657 722 size_t chars = charcount; 658 const introundup = bitsPerCharTableMultiplier - 1;723 const unsigned roundup = bitsPerCharTableMultiplier - 1; 659 724 if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) { 660 725 size_t bitsMin = bitsPerChar * chars; … … 664 729 if (bitsMin <= static_cast<size_t>(maxInt)) { 665 730 // Divide by kDigitsBits, rounding up. 666 int length = (static_cast<int>(bitsMin)+ digitBits - 1) / digitBits;731 unsigned length = (bitsMin + digitBits - 1) / digitBits; 667 732 if (length <= maxLength) { 668 733 JSBigInt* result = JSBigInt::createWithLength(vm, length); … … 772 837 return createZero(vm); 773 838 774 intlimit0 = '0' + (radix < 10 ? radix : 10);775 intlimita = 'a' + (radix - 10);776 intlimitA = 'A' + (radix - 10);839 unsigned limit0 = '0' + (radix < 10 ? radix : 10); 840 unsigned limita = 'a' + (radix - 10); 841 unsigned limitA = 'A' + (radix - 10); 777 842 778 843 JSBigInt* result = allocateFor(state, vm, radix, length - p); … … 810 875 } 811 876 812 inline JSBigInt::Digit JSBigInt::digit(intn)877 JSBigInt::Digit JSBigInt::digit(unsigned n) 813 878 { 814 879 ASSERT(n >= 0 && n < length()); … … 816 881 } 817 882 818 inline void JSBigInt::setDigit(intn, Digit value)883 void JSBigInt::setDigit(unsigned n, Digit value) 819 884 { 820 885 ASSERT(n >= 0 && n < length()); -
trunk/Source/JavaScriptCore/runtime/JSBigInt.h
r231629 r231733 42 42 public: 43 43 44 JSBigInt(VM&, Structure*, intlength);44 JSBigInt(VM&, Structure*, unsigned length); 45 45 46 46 enum class InitializationType { None, WithZero }; … … 50 50 51 51 static size_t estimatedSize(JSCell*); 52 static size_t allocationSize( intlength);52 static size_t allocationSize(unsigned length); 53 53 54 54 static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); 55 56 55 static JSBigInt* createZero(VM&); 57 static JSBigInt* createWithLength(VM&, intlength);56 static JSBigInt* createWithLength(VM&, unsigned length); 58 57 59 58 static JSBigInt* createFrom(VM&, int32_t value); … … 71 70 bool sign() const { return m_sign; } 72 71 73 void setLength( intlength) { m_length = length; }74 intlength() const { return m_length; }72 void setLength(unsigned length) { m_length = length; } 73 unsigned length() const { return m_length; } 75 74 76 75 enum ErrorParseMode { … … 93 92 94 93 JSObject* toObject(ExecState*, JSGlobalObject*) const; 94 95 static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y); 95 96 96 97 private: … … 104 105 105 106 using Digit = uintptr_t; 106 static constexpr const intbitsPerByte = 8;107 static constexpr const intdigitBits = sizeof(Digit) * bitsPerByte;108 static constexpr const inthalfDigitBits = digitBits / 2;107 static constexpr const unsigned bitsPerByte = 8; 108 static constexpr const unsigned digitBits = sizeof(Digit) * bitsPerByte; 109 static constexpr const unsigned halfDigitBits = digitBits / 2; 109 110 static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1; 110 111 static constexpr const int maxInt = 0x7FFFFFFF; … … 114 115 // raising it later is easier than lowering it. 115 116 // Support up to 1 million bits. 116 static const intmaxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);117 static const unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte); 117 118 118 static uint64_t calculateMaximumCharactersRequired( int length, intradix, Digit lastDigit, bool sign);119 static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign); 119 120 120 121 static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder); 121 static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result); 122 static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result); 123 static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex); 122 124 123 125 // Digit arithmetic helpers. … … 128 130 static Digit digitPow(Digit base, Digit exponent); 129 131 130 static String toStringGeneric(ExecState&, JSBigInt*, intradix);132 static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix); 131 133 132 134 bool isZero(); … … 140 142 static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, bool allowEmptyString = true); 141 143 142 static JSBigInt* allocateFor(ExecState*, VM&, int radix, intcharcount);144 static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount); 143 145 144 146 JSBigInt* rightTrim(VM&); … … 149 151 Digit* dataStorage(); 150 152 151 Digit digit( int);152 void setDigit( int, Digit);153 Digit digit(unsigned); 154 void setDigit(unsigned, Digit); 153 155 154 intm_length;156 unsigned m_length; 155 157 bool m_sign; 156 158 }; -
trunk/Source/JavaScriptCore/runtime/JSCJSValue.h
r230376 r231733 40 40 41 41 class AssemblyHelpers; 42 class JSBigInt; 42 43 class ExecState; 43 44 class JSCell; … … 258 259 // been set in the ExecState already. 259 260 double toNumber(ExecState*) const; 261 262 Variant<JSBigInt*, double> toNumeric(ExecState*) const; 260 263 261 264 // toNumber conversion if it can be done without side effects. -
trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
r231629 r231733 38 38 #include "JSStringInlines.h" 39 39 #include "MathCommon.h" 40 #include <wtf/Variant.h> 40 41 #include <wtf/text/StringImpl.h> 41 42 … … 727 728 return asDouble(); 728 729 return toNumberSlowCase(exec); 730 } 731 732 ALWAYS_INLINE Variant<JSBigInt*, double> JSValue::toNumeric(ExecState* exec) const 733 { 734 if (isInt32()) 735 return asInt32(); 736 if (isDouble()) 737 return asDouble(); 738 if (isBigInt()) 739 return asBigInt(*this); 740 741 VM& vm = exec->vm(); 742 auto scope = DECLARE_THROW_SCOPE(vm); 743 JSValue primValue = this->toPrimitive(exec, PreferNumber); 744 RETURN_IF_EXCEPTION(scope, 0); 745 if (primValue.isBigInt()) 746 return asBigInt(primValue); 747 double value = primValue.toNumber(exec); 748 RETURN_IF_EXCEPTION(scope, 0); 749 return value; 729 750 } 730 751 -
trunk/Source/JavaScriptCore/runtime/Operations.h
r231147 r231733 24 24 #include "CallFrame.h" 25 25 #include "ExceptionHelpers.h" 26 #include "JSBigInt.h" 26 27 #include "JSCJSValue.h" 28 #include <wtf/Variant.h> 27 29 28 30 namespace JSC { … … 257 259 } 258 260 261 ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2) 262 { 263 VM& vm = state->vm(); 264 auto scope = DECLARE_THROW_SCOPE(vm); 265 266 Variant<JSBigInt*, double> leftNumeric = v1.toNumeric(state); 267 RETURN_IF_EXCEPTION(scope, { }); 268 Variant<JSBigInt*, double> rightNumeric = v2.toNumeric(state); 269 RETURN_IF_EXCEPTION(scope, { }); 270 271 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { 272 if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) 273 return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); 274 275 throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in multiplication.")); 276 return { }; 277 } 278 279 double leftValue = WTF::get<double>(leftNumeric); 280 double rightValue = WTF::get<double>(rightNumeric); 281 return jsNumber(leftValue * rightValue); 282 } 283 259 284 inline bool scribbleFreeCells() 260 285 {
Note: See TracChangeset
for help on using the changeset viewer.