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