Title: [260834] trunk
Revision
260834
Author
[email protected]
Date
2020-04-28 11:04:53 -0700 (Tue, 28 Apr 2020)

Log Message

[JSC] NumberConstructor should accept BigInt
https://bugs.webkit.org/show_bug.cgi?id=210835

Reviewed by Mark Lam.

JSTests:

* stress/number-constructor-bigint-dfg.js: Added.
(shouldBe):
(convert):
* stress/number-constructor-bigint.js: Added.
(shouldBe):
* test262/expectations.yaml:

Source/_javascript_Core:

This patch fixes our Number constructor behavior to accept BigInt. According to the spec[1],
Number constructor should accept BigInt and should generate numbers from that.

We port V8's BigInt to double conversion code as we did for the other HeapBigInt runtime functions.

And we introduce CallNumberConstructor DFG node and handle Number constructor call with BigInt correctly
in DFG and FTL. Previously we were emitting ToNumber DFG node for Number constructor. But this is wrong
now since ToNumber does not accept BigInt and throws an error, and Number constructor should not use
ToNumber to implement its implementation. So we should introduce slightly different semantics: CallNumberConstructor
as we introduced CallStringConstructor in addition to ToString DFG node. And we add appropriate BigInt32 path
to emit efficient CallNumberConstructor machine code.

[1]: https://tc39.es/ecma262/#sec-number-constructor-number-value

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupToNumberOrToNumericOrCallNumberConstructor):
(JSC::DFG::FixupPhase::fixupToNumeric): Deleted.
(JSC::DFG::FixupPhase::fixupToNumber): Deleted.
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToNumeric):
(JSC::DFG::SpeculativeJIT::compileCallNumberConstructor):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCallNumberConstructor):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::decideRounding):
(JSC::JSBigInt::toNumberHeap):
* runtime/JSBigInt.h:
* runtime/NumberConstructor.cpp:
(JSC::constructNumberConstructor):
(JSC::callNumberConstructor):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (260833 => 260834)


--- trunk/JSTests/ChangeLog	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/JSTests/ChangeLog	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1,3 +1,17 @@
+2020-04-28  Yusuke Suzuki  <[email protected]>
+
+        [JSC] NumberConstructor should accept BigInt
+        https://bugs.webkit.org/show_bug.cgi?id=210835
+
+        Reviewed by Mark Lam.
+
+        * stress/number-constructor-bigint-dfg.js: Added.
+        (shouldBe):
+        (convert):
+        * stress/number-constructor-bigint.js: Added.
+        (shouldBe):
+        * test262/expectations.yaml:
+
 2020-04-27  Yusuke Suzuki  <[email protected]>
 
         [JSC] Throw OutOfMemoryError instead of RangeError if BigInt is too big

Added: trunk/JSTests/stress/number-constructor-bigint-dfg.js (0 => 260834)


--- trunk/JSTests/stress/number-constructor-bigint-dfg.js	                        (rev 0)
+++ trunk/JSTests/stress/number-constructor-bigint-dfg.js	2020-04-28 18:04:53 UTC (rev 260834)
@@ -0,0 +1,53 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function convert(bigInt)
+{
+    return Number(bigInt);
+}
+noInline(convert);
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(convert(0n), 0);
+    shouldBe(convert(0x7fffffffn), 0x7fffffff);
+    shouldBe(convert(-0x7fffffffn - 1n), -0x80000000);
+}
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(convert(0x80000000n), 0x80000000);
+    shouldBe(convert(0x7fffffffn + 1n), 0x80000000);
+    shouldBe(convert(0x7fffffffn + 2n), 0x80000001);
+    shouldBe(convert(-0x7fffffffn - 2n), -0x80000001);
+}
+
+for (var i = 0; i < 1e4; ++i) {
+    shouldBe(convert(0x20000000000000n), 9007199254740992);
+    shouldBe(convert(0x20000000000000n + 1n), 9007199254740992);
+    shouldBe(convert(0x20000000000000n + 2n), 9007199254740994);
+    shouldBe(convert(0x20000000000000n + 3n), 9007199254740996);
+    shouldBe(convert(0x20000000000000n + 4n), 9007199254740996);
+
+    shouldBe(convert(-(0x20000000000000n)), -9007199254740992);
+    shouldBe(convert(-(0x20000000000000n + 1n)), -9007199254740992);
+    shouldBe(convert(-(0x20000000000000n + 2n)), -9007199254740994);
+    shouldBe(convert(-(0x20000000000000n + 3n)), -9007199254740996);
+    shouldBe(convert(-(0x20000000000000n + 4n)), -9007199254740996);
+
+    shouldBe(convert(2n ** (1024n - 1n)), 8.98846567431158e+307);
+    shouldBe(convert(2n ** (1024n - 1n)), 8.98846567431158e+307);
+    shouldBe(convert(0x1fffffffffffffn << 971n), Number.MAX_VALUE);
+    shouldBe(convert(0x20000000000000n << 971n), Infinity);
+    shouldBe(convert(0x1ffffffffffffffn << 966n), 8.98846567431158e+307);
+    shouldBe(convert(0x3fffffffffffffn << 970n), Infinity);
+    shouldBe(convert(0x3fffffffffffffn << 969n), 8.98846567431158e+307);
+
+    shouldBe(convert(-(2n ** (1024n - 1n))), -8.98846567431158e+307);
+    shouldBe(convert(-(2n ** (1024n - 1n))), -8.98846567431158e+307);
+    shouldBe(convert(-0x1fffffffffffffn << 971n), -Number.MAX_VALUE);
+    shouldBe(convert(-0x20000000000000n << 971n), -Infinity);
+    shouldBe(convert(-0x1ffffffffffffffn << 966n), -8.98846567431158e+307);
+    shouldBe(convert(-0x3fffffffffffffn << 970n), -Infinity);
+    shouldBe(convert(-0x3fffffffffffffn << 969n), -8.98846567431158e+307);
+}

Added: trunk/JSTests/stress/number-constructor-bigint.js (0 => 260834)


--- trunk/JSTests/stress/number-constructor-bigint.js	                        (rev 0)
+++ trunk/JSTests/stress/number-constructor-bigint.js	2020-04-28 18:04:53 UTC (rev 260834)
@@ -0,0 +1,108 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+shouldBe(Number(0n), 0);
+
+// Around Int32 max/min.
+shouldBe(Number(0x7fffffffn), 0x7fffffff);
+shouldBe(Number(0x80000000n), 0x80000000);
+shouldBe(Number(0x7fffffffn + 1n), 0x80000000);
+shouldBe(Number(0x7fffffffn + 2n), 0x80000001);
+shouldBe(Number(-0x7fffffffn - 1n), -0x80000000);
+shouldBe(Number(-0x7fffffffn - 2n), -0x80000001);
+
+// Around Int52 max/min.
+shouldBe(Number(0x20000000000000n), 9007199254740992);
+shouldBe(Number(0x20000000000000n + 1n), 9007199254740992);
+shouldBe(Number(0x20000000000000n + 2n), 9007199254740994);
+shouldBe(Number(0x20000000000000n + 3n), 9007199254740996);
+shouldBe(Number(0x20000000000000n + 4n), 9007199254740996);
+
+shouldBe(Number(-(0x20000000000000n)), -9007199254740992);
+shouldBe(Number(-(0x20000000000000n + 1n)), -9007199254740992);
+shouldBe(Number(-(0x20000000000000n + 2n)), -9007199254740994);
+shouldBe(Number(-(0x20000000000000n + 3n)), -9007199254740996);
+shouldBe(Number(-(0x20000000000000n + 4n)), -9007199254740996);
+
+// mantissa rounding.
+shouldBe(Number(0x3fffffffffffffn), 18014398509481984);
+shouldBe(Number(-0x3fffffffffffffn), -18014398509481984);
+shouldBe(Number(0b1000000000000000000000000000000000000111111111111111111111n), 144115188077953020);
+shouldBe(Number(0b1000000000000000000000000000000000000000000000000000000001n), 144115188075855870);
+shouldBe(Number(0b1000000000000000000000000000000000000000000000000001000000n), 144115188075855940);
+shouldBe(Number(0b1000000000000000000000000000000000000000000000000001000001n), 144115188075855940);
+shouldBe(Number(0b1000000000000000000000000000000000000000000000000001000001n), 144115188075855940);
+shouldBe(Number(0b10000000000000000000000000000000000000000000000000001n), 4503599627370497);
+shouldBe(Number(0b100000000000000000000000000000000000000000000000000010n), 9007199254740994);
+shouldBe(Number(0b100000000000000000000000000000000000000000000000000011n), 9007199254740996);
+
+// Around Infinity.
+shouldBe(Number(2n ** (1024n - 1n)), 8.98846567431158e+307);
+shouldBe(Number(2n ** (1024n - 1n)), 8.98846567431158e+307);
+shouldBe(Number(0x1fffffffffffffn << 971n), Number.MAX_VALUE);
+shouldBe(Number(0x20000000000000n << 971n), Infinity);
+shouldBe(Number(0x1ffffffffffffffn << 966n), 8.98846567431158e+307);
+shouldBe(Number(0x3fffffffffffffn << 970n), Infinity);
+shouldBe(Number(0x3fffffffffffffn << 969n), 8.98846567431158e+307);
+
+shouldBe(Number(-(2n ** (1024n - 1n))), -8.98846567431158e+307);
+shouldBe(Number(-(2n ** (1024n - 1n))), -8.98846567431158e+307);
+shouldBe(Number(-0x1fffffffffffffn << 971n), -Number.MAX_VALUE);
+shouldBe(Number(-0x20000000000000n << 971n), -Infinity);
+shouldBe(Number(-0x1ffffffffffffffn << 966n), -8.98846567431158e+307);
+shouldBe(Number(-0x3fffffffffffffn << 970n), -Infinity);
+shouldBe(Number(-0x3fffffffffffffn << 969n), -8.98846567431158e+307);
+
+shouldBe(+new Number(0n), +new Number(0));
+
+// Around Int32 max/min.
+shouldBe(+new Number(0x7fffffffn), +new Number(0x7fffffff));
+shouldBe(+new Number(0x80000000n), +new Number(0x80000000));
+shouldBe(+new Number(0x7fffffffn + 1n), +new Number(0x80000000));
+shouldBe(+new Number(0x7fffffffn + 2n), +new Number(0x80000001));
+shouldBe(+new Number(-0x7fffffffn - 1n), +new Number(-0x80000000));
+shouldBe(+new Number(-0x7fffffffn - 2n), +new Number(-0x80000001));
+
+// Around Int52 max/min.
+shouldBe(+new Number(0x20000000000000n), +new Number(9007199254740992));
+shouldBe(+new Number(0x20000000000000n + 1n), +new Number(9007199254740992));
+shouldBe(+new Number(0x20000000000000n + 2n), +new Number(9007199254740994));
+shouldBe(+new Number(0x20000000000000n + 3n), +new Number(9007199254740996));
+shouldBe(+new Number(0x20000000000000n + 4n), +new Number(9007199254740996));
+
+shouldBe(+new Number(-(0x20000000000000n)), +new Number(-9007199254740992));
+shouldBe(+new Number(-(0x20000000000000n + 1n)), +new Number(-9007199254740992));
+shouldBe(+new Number(-(0x20000000000000n + 2n)), +new Number(-9007199254740994));
+shouldBe(+new Number(-(0x20000000000000n + 3n)), +new Number(-9007199254740996));
+shouldBe(+new Number(-(0x20000000000000n + 4n)), +new Number(-9007199254740996));
+
+// mantissa rounding.
+shouldBe(+new Number(0x3fffffffffffffn), +new Number(18014398509481984));
+shouldBe(+new Number(-0x3fffffffffffffn), +new Number(-18014398509481984));
+shouldBe(+new Number(0b1000000000000000000000000000000000000111111111111111111111n), +new Number(144115188077953020));
+shouldBe(+new Number(0b1000000000000000000000000000000000000000000000000000000001n), +new Number(144115188075855870));
+shouldBe(+new Number(0b1000000000000000000000000000000000000000000000000001000000n), +new Number(144115188075855940));
+shouldBe(+new Number(0b1000000000000000000000000000000000000000000000000001000001n), +new Number(144115188075855940));
+shouldBe(+new Number(0b1000000000000000000000000000000000000000000000000001000001n), +new Number(144115188075855940));
+shouldBe(+new Number(0b10000000000000000000000000000000000000000000000000001n), +new Number(4503599627370497));
+shouldBe(+new Number(0b100000000000000000000000000000000000000000000000000010n), +new Number(9007199254740994));
+shouldBe(+new Number(0b100000000000000000000000000000000000000000000000000011n), +new Number(9007199254740996));
+
+// Around Infinity.
+shouldBe(+new Number(2n ** (1024n - 1n)), +new Number(8.98846567431158e+307));
+shouldBe(+new Number(2n ** (1024n - 1n)), +new Number(8.98846567431158e+307));
+shouldBe(+new Number(0x1fffffffffffffn << 971n), +new Number(Number.MAX_VALUE));
+shouldBe(+new Number(0x20000000000000n << 971n), +new Number(Infinity));
+shouldBe(+new Number(0x1ffffffffffffffn << 966n), +new Number(8.98846567431158e+307));
+shouldBe(+new Number(0x3fffffffffffffn << 970n), +new Number(Infinity));
+shouldBe(+new Number(0x3fffffffffffffn << 969n), +new Number(8.98846567431158e+307));
+
+shouldBe(+new Number(-(2n ** (1024n - 1n))), +new Number(-8.98846567431158e+307));
+shouldBe(+new Number(-(2n ** (1024n - 1n))), +new Number(-8.98846567431158e+307));
+shouldBe(+new Number(-0x1fffffffffffffn << 971n), +new Number(-Number.MAX_VALUE));
+shouldBe(+new Number(-0x20000000000000n << 971n), +new Number(-Infinity));
+shouldBe(+new Number(-0x1ffffffffffffffn << 966n), +new Number(-8.98846567431158e+307));
+shouldBe(+new Number(-0x3fffffffffffffn << 970n), +new Number(-Infinity));
+shouldBe(+new Number(-0x3fffffffffffffn << 969n), +new Number(-8.98846567431158e+307));

Modified: trunk/JSTests/test262/expectations.yaml (260833 => 260834)


--- trunk/JSTests/test262/expectations.yaml	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/JSTests/test262/expectations.yaml	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1068,9 +1068,6 @@
 test/built-ins/JSON/parse/reviver-object-non-configurable-prop-create.js:
   default: 'Test262Error: Expected SameValue(«22», «2») to be true'
   strict mode: 'Test262Error: Expected SameValue(«22», «2») to be true'
-test/built-ins/Number/bigint-conversion.js:
-  default: "TypeError: Conversion from 'BigInt' to 'number' is not allowed."
-  strict mode: "TypeError: Conversion from 'BigInt' to 'number' is not allowed."
 test/built-ins/Object/entries/order-after-define-property.js:
   default: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '
   strict mode: 'Test262Error: Expected [b, a] and [a, b] to have the same contents. '

Modified: trunk/Source/_javascript_Core/ChangeLog (260833 => 260834)


--- trunk/Source/_javascript_Core/ChangeLog	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1,3 +1,70 @@
+2020-04-28  Yusuke Suzuki  <[email protected]>
+
+        [JSC] NumberConstructor should accept BigInt
+        https://bugs.webkit.org/show_bug.cgi?id=210835
+
+        Reviewed by Mark Lam.
+
+        This patch fixes our Number constructor behavior to accept BigInt. According to the spec[1],
+        Number constructor should accept BigInt and should generate numbers from that.
+
+        We port V8's BigInt to double conversion code as we did for the other HeapBigInt runtime functions.
+
+        And we introduce CallNumberConstructor DFG node and handle Number constructor call with BigInt correctly
+        in DFG and FTL. Previously we were emitting ToNumber DFG node for Number constructor. But this is wrong
+        now since ToNumber does not accept BigInt and throws an error, and Number constructor should not use
+        ToNumber to implement its implementation. So we should introduce slightly different semantics: CallNumberConstructor
+        as we introduced CallStringConstructor in addition to ToString DFG node. And we add appropriate BigInt32 path
+        to emit efficient CallNumberConstructor machine code.
+
+        [1]: https://tc39.es/ecma262/#sec-number-constructor-number-value
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupToNumberOrToNumericOrCallNumberConstructor):
+        (JSC::DFG::FixupPhase::fixupToNumeric): Deleted.
+        (JSC::DFG::FixupPhase::fixupToNumber): Deleted.
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasHeapPrediction):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileToNumeric):
+        (JSC::DFG::SpeculativeJIT::compileCallNumberConstructor):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCallNumberConstructor):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::decideRounding):
+        (JSC::JSBigInt::toNumberHeap):
+        * runtime/JSBigInt.h:
+        * runtime/NumberConstructor.cpp:
+        (JSC::constructNumberConstructor):
+        (JSC::callNumberConstructor):
+
 2020-04-27  Yusuke Suzuki  <[email protected]>
 
         [JSC] Throw OutOfMemoryError instead of RangeError if BigInt is too big

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -2711,6 +2711,45 @@
         setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
         break;
     }
+
+    case CallNumberConstructor: {
+        JSValue childConst = forNode(node->child1()).value();
+        if (childConst) {
+            if (childConst.isNumber()) {
+                if (node->child1().useKind() == UntypedUse)
+                    didFoldClobberWorld();
+                setConstant(node, childConst);
+                break;
+            }
+#if USE(BIGINT32)
+            if (childConst.isBigInt32()) {
+                if (node->child1().useKind() == UntypedUse)
+                    didFoldClobberWorld();
+                setConstant(node, jsNumber(childConst.bigInt32AsInt32()));
+                break;
+            }
+#endif
+        }
+
+        ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == BigInt32Use);
+
+        if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
+            m_state.setShouldTryConstantFolding(true);
+            if (node->child1().useKind() == UntypedUse)
+                didFoldClobberWorld();
+            setForNode(node, forNode(node->child1()));
+            break;
+        }
+
+        if (node->child1().useKind() == BigInt32Use) {
+            setTypeForNode(node, SpecInt32Only);
+            break;
+        }
+
+        clobberWorld();
+        setNonCellTypeForNode(node, SpecBytecodeNumber);
+        break;
+    }
         
     case ToString:
     case CallStringConstructor: {

Modified: trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -415,7 +415,8 @@
             
         case ToPrimitive:
         case ToNumber:
-        case ToNumeric: {
+        case ToNumeric:
+        case CallNumberConstructor: {
             node->child1()->mergeFlags(flags);
             break;
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -4027,7 +4027,7 @@
         if (argumentCountIncludingThis <= 1)
             set(result, jsConstant(jsNumber(0)));
         else
-            set(result, addToGraph(ToNumber, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgumentIncludingThis(1, registerOffset))));
+            set(result, addToGraph(CallNumberConstructor, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgumentIncludingThis(1, registerOffset))));
 
         return true;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -692,6 +692,19 @@
         write(Heap);
         return;
 
+    case CallNumberConstructor:
+        switch (node->child1().useKind()) {
+        case BigInt32Use:
+            def(PureValue(node));
+            return;
+        case UntypedUse:
+            read(World);
+            write(Heap);
+            return;
+        default:
+            DFG_CRASH(graph, node, "Bad use kind");
+        }
+
     case Inc:
     case Dec:
         switch (node->child1().useKind()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -951,7 +951,8 @@
                 break;
             }
 
-            case ToNumber: {
+            case ToNumber:
+            case CallNumberConstructor: {
                 if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber)
                     break;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -413,6 +413,15 @@
 #endif // not ASSERT_ENABLED
         return true;
 
+    case CallNumberConstructor:
+        switch (node->child1().useKind()) {
+        case BigInt32Use:
+            return false;
+        default:
+            break;
+        }
+        return true;
+
     case CallStringConstructor:
     case ToString:
         switch (node->child1().useKind()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1536,16 +1536,13 @@
             break;
         }
 
-        case ToNumber: {
-            fixupToNumber(node);
+        case ToNumber:
+        case ToNumeric:
+        case CallNumberConstructor: {
+            fixupToNumberOrToNumericOrCallNumberConstructor(node);
             break;
         }
 
-        case ToNumeric: {
-            fixupToNumeric(node);
-            break;
-        }
-            
         case ToString:
         case CallStringConstructor: {
             fixupToStringOrCallStringConstructor(node);
@@ -3090,29 +3087,37 @@
         }
     }
 
-    void fixupToNumeric(Node* node)
+    void fixupToNumberOrToNumericOrCallNumberConstructor(Node* node)
     {
+#if USE(BIGINT32)
+        if (node->op() == CallNumberConstructor) {
+            if (node->child1()->shouldSpeculateBigInt32()) {
+                fixEdge<BigInt32Use>(node->child1());
+                node->clearFlags(NodeMustGenerate);
+                node->setResult(NodeResultInt32);
+                return;
+            }
+        }
+#endif
+
         // If the prediction of the child is BigInt, we attempt to convert ToNumeric to Identity, since it can only return a BigInt when fed a BigInt.
-        if (node->child1()->shouldSpeculateBigInt()) {
+        if (node->op() == ToNumeric) {
+            if (node->child1()->shouldSpeculateBigInt()) {
 #if USE(BIGINT32)
-            if (node->child1()->shouldSpeculateBigInt32())
-                fixEdge<BigInt32Use>(node->child1());
-            else if (node->child1()->shouldSpeculateHeapBigInt())
+                if (node->child1()->shouldSpeculateBigInt32())
+                    fixEdge<BigInt32Use>(node->child1());
+                else if (node->child1()->shouldSpeculateHeapBigInt())
+                    fixEdge<HeapBigIntUse>(node->child1());
+                else
+                    fixEdge<AnyBigIntUse>(node->child1());
+#else
                 fixEdge<HeapBigIntUse>(node->child1());
-            else
-                fixEdge<AnyBigIntUse>(node->child1());
-#else
-            fixEdge<HeapBigIntUse>(node->child1());
 #endif
-            node->convertToIdentity();
-            return;
+                node->convertToIdentity();
+                return;
+            }
         }
 
-        fixupToNumber(node);
-    }
-
-    void fixupToNumber(Node* node)
-    {
         // At first, attempt to fold Boolean or Int32 to Int32.
         if (node->child1()->shouldSpeculateInt32OrBoolean()) {
             if (isInt32Speculation(node->getHeapPrediction())) {

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1795,6 +1795,7 @@
         case ToNumber:
         case ToNumeric:
         case ToObject:
+        case CallNumberConstructor:
         case ValueBitAnd:
         case ValueBitOr:
         case ValueBitXor:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -412,6 +412,7 @@
     macro(ToObject, NodeResultJS | NodeMustGenerate) \
     macro(CallObjectConstructor, NodeResultJS) \
     macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \
+    macro(CallNumberConstructor, NodeResultJS | NodeMustGenerate) \
     macro(NumberToStringWithRadix, NodeResultJS | NodeMustGenerate) \
     macro(NumberToStringWithValidRadixConstant, NodeResultJS) \
     macro(MakeRope, NodeResultJS) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1531,6 +1531,22 @@
     return JSValue::encode(JSValue::decode(value).toNumeric(globalObject));
 }
 
+EncodedJSValue JIT_OPERATION operationCallNumberConstructor(JSGlobalObject* globalObject, EncodedJSValue encodedValue)
+{
+    VM& vm = globalObject->vm();
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue value = JSValue::decode(encodedValue);
+    JSValue numeric = value.toNumeric(globalObject);
+    RETURN_IF_EXCEPTION(scope, { });
+    if (numeric.isNumber())
+        return JSValue::encode(numeric);
+    ASSERT(numeric.isBigInt());
+    return JSValue::encode(JSBigInt::toNumber(numeric));
+}
+
 EncodedJSValue JIT_OPERATION operationGetByValWithThis(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
 {
     VM& vm = globalObject->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -94,6 +94,7 @@
 EncodedJSValue JIT_OPERATION operationToPropertyKey(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToNumber(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToNumeric(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationCallNumberConstructor(JSGlobalObject*, EncodedJSValue);
 EncodedJSValue JIT_OPERATION operationGetByValWithThis(JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetPrototypeOf(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetPrototypeOfObject(JSGlobalObject*, JSObject*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -897,6 +897,7 @@
         case ToNumber:
         case ToNumeric:
         case ToObject:
+        case CallNumberConstructor:
         case ValueBitAnd:
         case ValueBitXor:
         case ValueBitOr:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -565,6 +565,7 @@
     case ToNumber:
     case ToNumeric:
     case ToObject:
+    case CallNumberConstructor:
     case NumberToStringWithRadix:
     case SetFunctionName:
     case NewStringObject:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -13336,7 +13336,8 @@
     JSValueRegs argumentRegs = argument.jsValueRegs();
     JSValueRegs resultRegs = result.regs();
     GPRReg scratch = temp.gpr();
-    // FIXME: add a fast path for BigInt32 here (and for typeOf, and for boolify or whatever it is called in this file).
+    // FIXME: add a fast path for BigInt32 here.
+    // https://bugs.webkit.org/show_bug.cgi?id=211064
 
     MacroAssembler::JumpList slowCases;
 
@@ -13355,6 +13356,41 @@
     jsValueResult(resultRegs, node, DataFormatJS);
 }
 
+void SpeculativeJIT::compileCallNumberConstructor(Node* node)
+{
+#if USE(BIGINT32)
+    if (node->child1().useKind() == BigInt32Use) {
+        SpeculateBigInt32Operand operand(this, node->child1());
+        GPRTemporary result(this);
+
+        GPRReg operandGPR = operand.gpr();
+        GPRReg resultGPR = result.gpr();
+
+        m_jit.unboxBigInt32(operandGPR, resultGPR);
+        strictInt32Result(resultGPR, node);
+        return;
+    }
+#endif
+
+    DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse, node->child1().useKind());
+    JSValueOperand argument(this, node->child1());
+    JSValueRegsTemporary result(this);
+    GPRTemporary temp(this);
+
+    JSValueRegs argumentRegs = argument.jsValueRegs();
+    JSValueRegs resultRegs = result.regs();
+    GPRReg tempGPR = temp.gpr();
+    // FIXME: add a fast path for BigInt32 here.
+    // https://bugs.webkit.org/show_bug.cgi?id=211064
+
+    CCallHelpers::JumpList slowCases;
+    slowCases.append(m_jit.branchIfNotNumber(argumentRegs, tempGPR));
+    m_jit.moveValueRegs(argumentRegs, resultRegs);
+    addSlowPathGenerator(slowPathCall(slowCases, this, operationCallNumberConstructor, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs));
+
+    jsValueResult(resultRegs, node);
+}
+
 void SpeculativeJIT::compileLogShadowChickenPrologue(Node* node)
 {
     flushRegisters();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1474,6 +1474,7 @@
     void compileToPrimitive(Node*);
     void compileToPropertyKey(Node*);
     void compileToNumeric(Node*);
+    void compileCallNumberConstructor(Node*);
     void compileLogShadowChickenPrologue(Node*);
     void compileLogShadowChickenTail(Node*);
     void compileHasIndexedProperty(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -3151,6 +3151,10 @@
         compileToNumeric(node);
         break;
     }
+
+    case CallNumberConstructor:
+        compileCallNumberConstructor(node);
+        break;
         
     case ToString:
     case CallStringConstructor:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -3720,6 +3720,10 @@
         break;
     }
 
+    case CallNumberConstructor:
+        compileCallNumberConstructor(node);
+        break;
+
     case ToString:
     case CallStringConstructor:
     case StringValueOf: {

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -219,6 +219,7 @@
     case ToObject:
     case CallObjectConstructor:
     case CallStringConstructor:
+    case CallNumberConstructor:
     case ObjectCreate:
     case ObjectKeys:
     case MakeRope:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -1134,6 +1134,9 @@
         case ToNumeric:
             compileToNumeric();
             break;
+        case CallNumberConstructor:
+            compileCallNumberConstructor();
+            break;
         case ToString:
         case CallStringConstructor:
         case StringValueOf:
@@ -7590,6 +7593,35 @@
         } else
             setJSValue(vmCall(Int64, operationToNumeric, weakPointer(globalObject), value));
     }
+
+    void compileCallNumberConstructor()
+    {
+        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+#if USE(BIGINT32)
+        if (m_node->child1().useKind() == BigInt32Use) {
+            LValue value = lowBigInt32(m_node->child1());
+            setInt32(unboxBigInt32(value));
+            return;
+        }
+#endif
+        LValue value = lowJSValue(m_node->child1());
+
+        LBasicBlock notNumber = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        ValueFromBlock fastResult = m_out.anchor(value);
+        m_out.branch(isNumber(value, provenType(m_node->child1())), unsure(continuation), unsure(notNumber));
+
+        // notNumber case.
+        LBasicBlock lastNext = m_out.appendTo(notNumber, continuation);
+        ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, operationCallNumberConstructor, weakPointer(globalObject), value));
+        m_out.jump(continuation);
+
+        // continuation case.
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(Int64, fastResult, slowResult));
+    }
+
     
     void compileToStringOrCallStringConstructorOrStringValueOf()
     {

Modified: trunk/Source/_javascript_Core/runtime/JSBigInt.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/runtime/JSBigInt.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/runtime/JSBigInt.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -2547,4 +2547,118 @@
     return value;
 }
 
+JSBigInt::RoundingResult JSBigInt::decideRounding(JSBigInt* bigInt, int32_t mantissaBitsUnset, int32_t digitIndex, uint64_t currentDigit)
+{
+    if (mantissaBitsUnset > 0)
+        return RoundingResult::RoundDown;
+    int32_t topUnconsumedBit = 0;
+    if (mantissaBitsUnset < 0) {
+        // There are unconsumed bits in currentDigit.
+        topUnconsumedBit = -mantissaBitsUnset - 1;
+    } else {
+        ASSERT(mantissaBitsUnset == 0);
+        // currentDigit fit the mantissa exactly; look at the next digit.
+        if (digitIndex == 0)
+            return RoundingResult::RoundDown;
+        digitIndex--;
+        currentDigit = static_cast<uint64_t>(bigInt->digit(digitIndex));
+        topUnconsumedBit = digitBits - 1;
+    }
+    // If the most significant remaining bit is 0, round down.
+    uint64_t bitmask = static_cast<uint64_t>(1) << topUnconsumedBit;
+    if ((currentDigit & bitmask) == 0)
+        return RoundingResult::RoundDown;
+    // If any other remaining bit is set, round up.
+    bitmask -= 1;
+    if ((currentDigit & bitmask) != 0)
+        return RoundingResult::RoundUp;
+    while (digitIndex > 0) {
+        digitIndex--;
+        if (bigInt->digit(digitIndex) != 0)
+            return RoundingResult::RoundUp;
+    }
+    return RoundingResult::Tie;
+}
+
+JSValue JSBigInt::toNumberHeap(JSBigInt* bigInt)
+{
+    if (bigInt->isZero())
+        return jsNumber(0);
+    ASSERT(bigInt->length());
+
+    // Conversion mechanism is the following.
+    //
+    // 1. Get exponent bits.
+    // 2. Collect mantissa 52 bits.
+    // 3. Add rounding result of unused bits to mantissa and adjust mantissa & exponent bits.
+    // 4. Generate double by combining (1) and (3).
+
+    const unsigned length = bigInt->length();
+    const bool sign = bigInt->sign();
+    const Digit msd = bigInt->digit(length - 1);
+    const unsigned msdLeadingZeros = clz(msd);
+    const size_t bitLength = length * digitBits - msdLeadingZeros;
+    // Double's exponent bits overflow.
+    if (bitLength > 1024)
+        return jsDoubleNumber(sign ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
+    uint64_t exponent = bitLength - 1;
+    uint64_t currentDigit = msd;
+    int32_t digitIndex = length - 1;
+    int32_t shiftAmount = msdLeadingZeros + 1 + (64 - digitBits);
+    ASSERT(1 <= shiftAmount);
+    ASSERT(shiftAmount <= 64);
+    uint64_t mantissa = (shiftAmount == 64) ? 0 : currentDigit << shiftAmount;
+
+    // unsetBits = 64 - setBits - 12 // 12 for non-mantissa bits
+    //     setBits = 64 - (msdLeadingZeros + 1 + bitsNotAvailableDueToDigitSize);  // 1 for hidden mantissa bit.
+    //                 = 64 - (msdLeadingZeros + 1 + (64 - digitBits))
+    //                 = 64 - shiftAmount
+    // Hence, unsetBits = 64 - (64 - shiftAmount) - 12 = shiftAmount - 12
+
+    mantissa >>= 12; // (12 = 64 - 52), we shift 12 bits to put 12 zeros in uint64_t mantissa.
+    int32_t mantissaBitsUnset = shiftAmount - 12;
+
+    // If not all mantissa bits are defined yet, get more digits as needed.
+    // Collect mantissa 52bits from several digits.
+
+    if constexpr (digitBits < 64) {
+        if (mantissaBitsUnset >= static_cast<int32_t>(digitBits) && digitIndex > 0) {
+            digitIndex--;
+            currentDigit = static_cast<uint64_t>(bigInt->digit(digitIndex));
+            mantissa |= (currentDigit << (mantissaBitsUnset - digitBits));
+            mantissaBitsUnset -= digitBits;
+        }
+    }
+
+    if (mantissaBitsUnset > 0 && digitIndex > 0) {
+        ASSERT(mantissaBitsUnset < static_cast<int32_t>(digitBits));
+        digitIndex--;
+        currentDigit = static_cast<uint64_t>(bigInt->digit(digitIndex));
+        mantissa |= (currentDigit >> (digitBits - mantissaBitsUnset));
+        mantissaBitsUnset -= digitBits;
+    }
+
+    // If there are unconsumed digits left, we may have to round.
+    RoundingResult rounding = decideRounding(bigInt, mantissaBitsUnset, digitIndex, currentDigit);
+    if (rounding == RoundingResult::RoundUp || (rounding == RoundingResult::Tie && (mantissa & 1) == 1)) {
+        ++mantissa;
+        // Incrementing the mantissa can overflow the mantissa bits. In that case the new mantissa will be all zero (plus hidden bit).
+        if ((mantissa >> doublePhysicalMantissaSize) != 0) {
+            mantissa = 0;
+            exponent++;
+            // Incrementing the exponent can overflow too.
+            if (exponent > 1023)
+                return jsDoubleNumber(sign ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
+        }
+    }
+
+    uint64_t signBit = sign ? (static_cast<uint64_t>(1) << 63) : 0;
+    exponent = (exponent + 0x3ff) << doublePhysicalMantissaSize; // 0x3ff is double exponent bias.
+    uint64_t doubleBits = signBit | exponent | mantissa;
+    ASSERT((doubleBits & (static_cast<uint64_t>(1) << 63)) == signBit);
+    ASSERT((doubleBits & (static_cast<uint64_t>(0x7ff) << 52)) == exponent);
+    ASSERT((doubleBits & ((static_cast<uint64_t>(1) << 52) - 1)) == mantissa);
+    return jsNumber(bitwise_cast<double>(doubleBits));
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSBigInt.h (260833 => 260834)


--- trunk/Source/_javascript_Core/runtime/JSBigInt.h	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/runtime/JSBigInt.h	2020-04-28 18:04:53 UTC (rev 260834)
@@ -393,6 +393,17 @@
     }
 #endif
 
+    static JSValue toNumberHeap(JSBigInt*);
+    static JSValue toNumber(JSValue bigInt)
+    {
+        ASSERT(bigInt.isBigInt());
+#if USE(BIGINT32)
+        if (bigInt.isBigInt32())
+            return jsNumber(bigInt.bigInt32AsInt32());
+#endif
+        return toNumberHeap(jsCast<JSBigInt*>(bigInt));
+    }
+
     Digit digit(unsigned);
     void setDigit(unsigned, Digit); // Use only when initializing.
     JS_EXPORT_PRIVATE JSBigInt* rightTrim(VM&);
@@ -405,6 +416,8 @@
     static constexpr unsigned halfDigitBits = digitBits / 2;
     static constexpr Digit halfDigitMask = (1ull << halfDigitBits) - 1;
     static constexpr int maxInt = 0x7FFFFFFF;
+
+    static constexpr unsigned doublePhysicalMantissaSize = 52;
     
     // The maximum length that the current implementation supports would be
     // maxInt / digitBits. However, we use a lower limit for now, because
@@ -439,6 +452,14 @@
     Digit absoluteInplaceSub(JSBigInt* subtrahend, unsigned startIndex);
     void inplaceRightShift(unsigned shift);
 
+    enum class RoundingResult {
+        RoundDown,
+        Tie,
+        RoundUp
+    };
+
+    static RoundingResult decideRounding(JSBigInt*, int32_t mantissaBitsUnset, int32_t digitIndex, uint64_t currentDigit);
+
     enum class ExtraDigitsHandling {
         Copy,
         Skip

Modified: trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp (260833 => 260834)


--- trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp	2020-04-28 18:04:41 UTC (rev 260833)
+++ trunk/Source/_javascript_Core/runtime/NumberConstructor.cpp	2020-04-28 18:04:53 UTC (rev 260834)
@@ -90,8 +90,19 @@
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    double n = callFrame->argumentCount() ? callFrame->uncheckedArgument(0).toNumber(globalObject) : 0;
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    double n = 0;
+    if (callFrame->argumentCount()) {
+        JSValue numeric = callFrame->uncheckedArgument(0).toNumeric(globalObject);
+        RETURN_IF_EXCEPTION(scope, { });
+        if (numeric.isNumber())
+            n = numeric.asNumber();
+        else {
+            ASSERT(numeric.isBigInt());
+            numeric = JSBigInt::toNumber(numeric);
+            ASSERT(numeric.isNumber());
+            n = numeric.asNumber();
+        }
+    }
 
     JSObject* newTarget = asObject(callFrame->newTarget());
     Structure* structure = newTarget == callFrame->jsCallee()
@@ -107,7 +118,16 @@
 // ECMA 15.7.2
 static EncodedJSValue JSC_HOST_CALL callNumberConstructor(JSGlobalObject* globalObject, CallFrame* callFrame)
 {
-    return JSValue::encode(jsNumber(!callFrame->argumentCount() ? 0 : callFrame->uncheckedArgument(0).toNumber(globalObject)));
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    if (!callFrame->argumentCount())
+        return JSValue::encode(jsNumber(0));
+    JSValue numeric = callFrame->uncheckedArgument(0).toNumeric(globalObject);
+    RETURN_IF_EXCEPTION(scope, { });
+    if (numeric.isNumber())
+        return JSValue::encode(numeric);
+    ASSERT(numeric.isBigInt());
+    return JSValue::encode(JSBigInt::toNumber(numeric));
 }
 
 // ECMA-262 20.1.2.3
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to