Teach the bytecode that arithmetic operations can return bigints
https://bugs.webkit.org/show_bug.cgi?id=205416
Reviewed by Yusuke Suzuki.
JSTests:
This file crashes in debug mode without the fix.
* stress/big-int-arithmetic-return-big-int.js: Added.
(fooAdd):
(fooSub):
(fooMul):
(fooDiv):
Source/JavaScriptCore:
Add already has the correct ResultType, but previously Sub/Mult/Div/Mod/Pow/Negate were always claimed to return Number,
and when BigInt is enabled they can also return BigInt.
UnaryPlus is left unchanged as it is invalid on a BigInt (to keep asm.js working as intended).
* parser/NodeConstructors.h:
(JSC::NegateNode::NegateNode):
(JSC::PowNode::PowNode):
(JSC::MultNode::MultNode):
(JSC::DivNode::DivNode):
(JSC::ModNode::ModNode):
(JSC::SubNode::SubNode):
* parser/ResultType.h:
(JSC::ResultType::bigIntOrNumberType): Added.
(JSC::ResultType::forNonAddArith):
(JSC::ResultType::forUnaryArith):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@254716 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 1a0a529..8f4f3a9 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,18 @@
+2020-01-16 Robin Morisset <rmorisset@apple.com>
+
+ Teach the bytecode that arithmetic operations can return bigints
+ https://bugs.webkit.org/show_bug.cgi?id=205416
+
+ Reviewed by Yusuke Suzuki.
+
+ This file crashes in debug mode without the fix.
+
+ * stress/big-int-arithmetic-return-big-int.js: Added.
+ (fooAdd):
+ (fooSub):
+ (fooMul):
+ (fooDiv):
+
2020-01-16 Mark Lam <mark.lam@apple.com>
operationToObject() should check for a null errorMessage.
diff --git a/JSTests/stress/big-int-arithmetic-return-big-int.js b/JSTests/stress/big-int-arithmetic-return-big-int.js
new file mode 100644
index 0000000..b0b2861
--- /dev/null
+++ b/JSTests/stress/big-int-arithmetic-return-big-int.js
@@ -0,0 +1,33 @@
+//@ runBigIntEnabled
+
+function fooAdd()
+{
+ return (1n+1n) / 1;
+}
+function fooSub()
+{
+ return (1n-1n) / 1;
+}
+function fooMul()
+{
+ return (1n*1n) / 1;
+}
+function fooDiv()
+{
+ return (1n/1n) / 1;
+}
+
+for (var i = 0; i < 10000 ; ++i) {
+ try {
+ fooAdd()
+ } catch {}
+ try {
+ fooSub()
+ } catch {}
+ try {
+ fooMul()
+ } catch {}
+ try {
+ fooDiv()
+ } catch {}
+}
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index b8866e0..327fe71 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,28 @@
2020-01-16 Robin Morisset <rmorisset@apple.com>
+ Teach the bytecode that arithmetic operations can return bigints
+ https://bugs.webkit.org/show_bug.cgi?id=205416
+
+ Reviewed by Yusuke Suzuki.
+
+ Add already has the correct ResultType, but previously Sub/Mult/Div/Mod/Pow/Negate were always claimed to return Number,
+ and when BigInt is enabled they can also return BigInt.
+ UnaryPlus is left unchanged as it is invalid on a BigInt (to keep asm.js working as intended).
+
+ * parser/NodeConstructors.h:
+ (JSC::NegateNode::NegateNode):
+ (JSC::PowNode::PowNode):
+ (JSC::MultNode::MultNode):
+ (JSC::DivNode::DivNode):
+ (JSC::ModNode::ModNode):
+ (JSC::SubNode::SubNode):
+ * parser/ResultType.h:
+ (JSC::ResultType::bigIntOrNumberType): Added.
+ (JSC::ResultType::forNonAddArith):
+ (JSC::ResultType::forUnaryArith):
+
+2020-01-16 Robin Morisset <rmorisset@apple.com>
+
Use dataLogIf more regularly
https://bugs.webkit.org/show_bug.cgi?id=206332
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
index 003d089..fd97a0c 100644
--- a/Source/JavaScriptCore/parser/NodeConstructors.h
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -516,13 +516,15 @@
{
}
+ // UnaryPlus is guaranteed to always return a number, never a BigInt.
+ // See https://tc39.es/ecma262/#sec-unary-plus-operator-runtime-semantics-evaluation
inline UnaryPlusNode::UnaryPlusNode(const JSTokenLocation& location, ExpressionNode* expr)
: UnaryOpNode(location, ResultType::numberType(), expr, op_to_number)
{
}
inline NegateNode::NegateNode(const JSTokenLocation& location, ExpressionNode* expr)
- : UnaryOpNode(location, ResultType::numberType(), expr, op_negate)
+ : UnaryOpNode(location, ResultType::forUnaryArith(expr->resultDescriptor()), expr, op_negate)
{
}
@@ -555,23 +557,23 @@
}
inline PowNode::PowNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
- : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_pow, rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forNonAddArith(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_pow, rightHasAssignments)
{
}
inline MultNode::MultNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
- : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_mul, rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forNonAddArith(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_mul, rightHasAssignments)
{
}
inline DivNode::DivNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
- : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_div, rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forNonAddArith(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_div, rightHasAssignments)
{
}
inline ModNode::ModNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
- : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_mod, rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forNonAddArith(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_mod, rightHasAssignments)
{
}
@@ -581,7 +583,7 @@
}
inline SubNode::SubNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
- : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_sub, rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forNonAddArith(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_sub, rightHasAssignments)
{
}
diff --git a/Source/JavaScriptCore/parser/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h
index 5622f28..2ee3eb2 100644
--- a/Source/JavaScriptCore/parser/ResultType.h
+++ b/Source/JavaScriptCore/parser/ResultType.h
@@ -157,6 +157,11 @@
return ResultType(TypeMaybeBigInt | TypeInt32 | TypeMaybeNumber);
}
+ static constexpr ResultType bigIntOrNumberType()
+ {
+ return ResultType(TypeMaybeBigInt | TypeMaybeNumber);
+ }
+
static constexpr ResultType unknownType()
{
return ResultType(TypeBits);
@@ -173,6 +178,24 @@
return addResultType();
}
+ static constexpr ResultType forNonAddArith(ResultType op1, ResultType op2)
+ {
+ if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+ return numberType();
+ if (op1.definitelyIsBigInt() && op2.definitelyIsBigInt())
+ return bigIntType();
+ return bigIntOrNumberType();
+ }
+
+ static constexpr ResultType forUnaryArith(ResultType op)
+ {
+ if (op.definitelyIsNumber())
+ return numberType();
+ if (op.definitelyIsBigInt())
+ return bigIntType();
+ return bigIntOrNumberType();
+ }
+
// Unlike in C, a logical op produces the value of the
// last expression evaluated (and not true or false).
static constexpr ResultType forLogicalOp(ResultType op1, ResultType op2)