[ESNext][BigInt] Implement support for addition operations
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Jun 2018 16:03:51 +0000 (16:03 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 2 Jun 2018 16:03:51 +0000 (16:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179002

Reviewed by Yusuke Suzuki.

JSTests:

* bigIntTests.yaml:
* stress/addition-order-evaluation.js: Added.
* stress/big-int-add-wrapped-value.js: Added.
* stress/big-int-addition-basic.js: Added.
* stress/big-int-addition-jit.js: Added.
* stress/big-int-addition-memory-stress.js: Added.
* stress/big-int-addition-string-coercion.js: Added.
* stress/big-int-addition-to-primitive-precedence.js: Added.
* stress/big-int-addition-to-primitive.js: Added.
* stress/big-int-addition-type-error.js: Added.
* stress/big-int-no-conversion-to-number.js:
* stress/big-int-sub-wrapped-value.js: Added.
* stress/big-int-subtraction-basic.js: Added.
* stress/big-int-subtraction-jit.js: Added.
* stress/big-int-subtraction-type-error.js: Added.
* stress/sub-order-evaluation.js: Added.

Source/JavaScriptCore:

This patch is implementing support to BigInt Operands into binary "+"
and binary "-" operators. Right now, we have limited support to DFG
and FTL JIT layers, but we plan to fix this support in future
patches.

* jit/JITOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::parseInt):
(JSC::JSBigInt::stringToBigInt):
(JSC::JSBigInt::toString):
(JSC::JSBigInt::multiply):
(JSC::JSBigInt::divide):
(JSC::JSBigInt::remainder):
(JSC::JSBigInt::add):
(JSC::JSBigInt::sub):
(JSC::JSBigInt::absoluteAdd):
(JSC::JSBigInt::absoluteSub):
(JSC::JSBigInt::toStringGeneric):
(JSC::JSBigInt::allocateFor):
(JSC::JSBigInt::toNumber const):
(JSC::JSBigInt::getPrimitiveNumber const):
* runtime/JSBigInt.h:
* runtime/JSCJSValueInlines.h:
* runtime/Operations.cpp:
(JSC::jsAddSlowCase):
* runtime/Operations.h:
(JSC::jsSub):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232439 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
JSTests/ChangeLog
JSTests/bigIntTests.yaml
JSTests/stress/addition-order-evaluation.js [new file with mode: 0644]
JSTests/stress/big-int-add-wrapped-value.js [new file with mode: 0644]
JSTests/stress/big-int-addition-basic.js [new file with mode: 0644]
JSTests/stress/big-int-addition-jit.js [new file with mode: 0644]
JSTests/stress/big-int-addition-memory-stress.js [new file with mode: 0644]
JSTests/stress/big-int-addition-string-coercion.js [new file with mode: 0644]
JSTests/stress/big-int-addition-to-primitive-precedence.js [new file with mode: 0644]
JSTests/stress/big-int-addition-to-primitive.js [new file with mode: 0644]
JSTests/stress/big-int-addition-type-error.js [new file with mode: 0644]
JSTests/stress/big-int-no-conversion-to-number.js
JSTests/stress/big-int-sub-wrapped-value.js [new file with mode: 0644]
JSTests/stress/big-int-subtraction-basic.js [new file with mode: 0644]
JSTests/stress/big-int-subtraction-jit.js [new file with mode: 0644]
JSTests/stress/big-int-subtraction-type-error.js [new file with mode: 0644]
JSTests/stress/sub-order-evaluation.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/JSBigInt.cpp
Source/JavaScriptCore/runtime/JSBigInt.h
Source/JavaScriptCore/runtime/JSCJSValueInlines.h
Source/JavaScriptCore/runtime/Operations.cpp
Source/JavaScriptCore/runtime/Operations.h

index e37f8db..fed1a4d 100644 (file)
@@ -1,3 +1,27 @@
+2018-06-02  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for addition operations
+        https://bugs.webkit.org/show_bug.cgi?id=179002
+
+        Reviewed by Yusuke Suzuki.
+
+        * bigIntTests.yaml:
+        * stress/addition-order-evaluation.js: Added.
+        * stress/big-int-add-wrapped-value.js: Added.
+        * stress/big-int-addition-basic.js: Added.
+        * stress/big-int-addition-jit.js: Added.
+        * stress/big-int-addition-memory-stress.js: Added.
+        * stress/big-int-addition-string-coercion.js: Added.
+        * stress/big-int-addition-to-primitive-precedence.js: Added.
+        * stress/big-int-addition-to-primitive.js: Added.
+        * stress/big-int-addition-type-error.js: Added.
+        * stress/big-int-no-conversion-to-number.js:
+        * stress/big-int-sub-wrapped-value.js: Added.
+        * stress/big-int-subtraction-basic.js: Added.
+        * stress/big-int-subtraction-jit.js: Added.
+        * stress/big-int-subtraction-type-error.js: Added.
+        * stress/sub-order-evaluation.js: Added.
+
 2018-05-29  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Add Symbol.prototype.description getter
index 756e49b..787834a 100644 (file)
 - path: stress/big-int-mod-jit.js
   cmd: runBigIntEnabled
 
+- path: stress/big-int-add-wrapped-value.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-basic.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-jit.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-memory-stress.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-string-coercion.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-to-primitive-precedence.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-to-primitive.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-addition-type-error.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-sub-wrapped-value.js
+  cmd: runBigIntEnabled
+
+- path:stress/big-int-subtraction-basic.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-subtraction-jit.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-subtraction-type-error.js
+  cmd: runBigIntEnabled
diff --git a/JSTests/stress/addition-order-evaluation.js b/JSTests/stress/addition-order-evaluation.js
new file mode 100644 (file)
index 0000000..d06f1aa
--- /dev/null
@@ -0,0 +1,23 @@
+function assert(a, message) {
+    if (!a)
+        throw new Error(message);
+}
+
+let o = {
+    valueOf: function () { throw new Error("Oops"); }
+};
+
+try {
+    let n = Symbol("3") + o;
+    assert(false, message + ": Should throw Error, but executed without exception");
+} catch (e) {
+    assert(e.message === "Oops","Expected Error('Oops'), got: " + e);
+}
+
+try {
+    let n = o + Symbol("3");
+    assert(false, message + ": Should throw Error, but executed without exception");
+} catch (e) {
+    assert(e.message === "Oops","Expected Error('Oops'), got: " + e);
+}
+
diff --git a/JSTests/stress/big-int-add-wrapped-value.js b/JSTests/stress/big-int-add-wrapped-value.js
new file mode 100644 (file)
index 0000000..8a378bf
--- /dev/null
@@ -0,0 +1,37 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testAdd(x, y, z, message) {
+    assert.sameValue(x + y, z, message);
+    assert.sameValue(y + x, z, message);
+}
+
+testAdd(Object(2n), 1n, 3n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    }
+};
+testAdd(o, 1n, 3n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    }
+};
+testAdd(o, 1n, 3n, "ToPrimitive: valueOf");
+
+o = {
+    toString: function() {
+        return 2n;
+    }
+}
+testAdd(o, 1n, 3n, "ToPrimitive: toString");
+
diff --git a/JSTests/stress/big-int-addition-basic.js b/JSTests/stress/big-int-addition-basic.js
new file mode 100644 (file)
index 0000000..9e57feb
--- /dev/null
@@ -0,0 +1,169 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+    if (input !== expected)
+        throw new Error(message);
+    }
+};
+
+function testAdd(x, y, z) {
+    assert.sameValue(x + y, z, x + " + " + y + " = " + z);
+    assert.sameValue(y + x, z, y + " + " + x + " = " + z);
+}
+
+testAdd(10n, 239n, 249n);
+testAdd(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0x1FDB97530ECA86420n);
+testAdd(0xFEDCBA9876543210n, 0xFEDCBA987654320Fn, 0x1FDB97530ECA8641Fn);
+testAdd(0xFEDCBA9876543210n, 0xFEDCBA98n, 0xFEDCBA997530ECA8n);
+testAdd(0xFEDCBA9876543210n, 0xFEDCBA97n, 0xFEDCBA997530ECA7n);
+testAdd(0xFEDCBA9876543210n, 0x1234n, 0xFEDCBA9876544444n);
+testAdd(0xFEDCBA9876543210n, 0x3n, 0xFEDCBA9876543213n);
+testAdd(0xFEDCBA9876543210n, 0x2n, 0xFEDCBA9876543212n);
+testAdd(0xFEDCBA9876543210n, 0x1n, 0xFEDCBA9876543211n);
+testAdd(0xFEDCBA9876543210n, 0x0n, 0xFEDCBA9876543210n);
+testAdd(0xFEDCBA9876543210n, -0x1n, 0xFEDCBA987654320Fn);
+testAdd(0xFEDCBA9876543210n, -0x2n, 0xFEDCBA987654320En);
+testAdd(0xFEDCBA9876543210n, -0x3n, 0xFEDCBA987654320Dn);
+testAdd(0xFEDCBA9876543210n, -0x1234n, 0xFEDCBA9876541FDCn);
+testAdd(0xFEDCBA9876543210n, -0xFEDCBA97n, 0xFEDCBA9777777779n);
+testAdd(0xFEDCBA9876543210n, -0xFEDCBA98n, 0xFEDCBA9777777778n);
+testAdd(0xFEDCBA9876543210n, -0xFEDCBA987654320Fn, 0x1n);
+testAdd(0xFEDCBA9876543210n, -0xFEDCBA9876543210n, 0x0n);
+testAdd(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0x1FDB97530ECA8641En);
+testAdd(0xFEDCBA987654320Fn, 0xFEDCBA98n, 0xFEDCBA997530ECA7n);
+testAdd(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0xFEDCBA997530ECA6n);
+testAdd(0xFEDCBA987654320Fn, 0x1234n, 0xFEDCBA9876544443n);
+testAdd(0xFEDCBA987654320Fn, 0x3n, 0xFEDCBA9876543212n);
+testAdd(0xFEDCBA987654320Fn, 0x2n, 0xFEDCBA9876543211n);
+testAdd(0xFEDCBA987654320Fn, 0x1n, 0xFEDCBA9876543210n);
+testAdd(0xFEDCBA987654320Fn, 0x0n, 0xFEDCBA987654320Fn);
+testAdd(0xFEDCBA987654320Fn, -0x1n, 0xFEDCBA987654320En);
+testAdd(0xFEDCBA987654320Fn, -0x2n, 0xFEDCBA987654320Dn);
+testAdd(0xFEDCBA987654320Fn, -0x3n, 0xFEDCBA987654320Cn);
+testAdd(0xFEDCBA987654320Fn, -0x1234n, 0xFEDCBA9876541FDBn);
+testAdd(0xFEDCBA987654320Fn, -0xFEDCBA97n, 0xFEDCBA9777777778n);
+testAdd(0xFEDCBA987654320Fn, -0xFEDCBA98n, 0xFEDCBA9777777777n);
+testAdd(0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn, 0x0n);
+testAdd(0xFEDCBA987654320Fn, -0xFEDCBA9876543210n, -0x1n);
+testAdd(0xFEDCBA98n, 0xFEDCBA98n, 0x1FDB97530n);
+testAdd(0xFEDCBA98n, 0xFEDCBA97n, 0x1FDB9752Fn);
+testAdd(0xFEDCBA98n, 0x1234n, 0xFEDCCCCCn);
+testAdd(0xFEDCBA98n, 0x3n, 0xFEDCBA9Bn);
+testAdd(0xFEDCBA98n, 0x2n, 0xFEDCBA9An);
+testAdd(0xFEDCBA98n, 0x1n, 0xFEDCBA99n);
+testAdd(0xFEDCBA98n, 0x0n, 0xFEDCBA98n);
+testAdd(0xFEDCBA98n, -0x1n, 0xFEDCBA97n);
+testAdd(0xFEDCBA98n, -0x2n, 0xFEDCBA96n);
+testAdd(0xFEDCBA98n, -0x3n, 0xFEDCBA95n);
+testAdd(0xFEDCBA98n, -0x1234n, 0xFEDCA864n);
+testAdd(0xFEDCBA98n, -0xFEDCBA97n, 0x1n);
+testAdd(0xFEDCBA98n, -0xFEDCBA98n, 0x0n);
+testAdd(0xFEDCBA98n, -0xFEDCBA987654320Fn, -0xFEDCBA9777777777n);
+testAdd(0xFEDCBA98n, -0xFEDCBA9876543210n, -0xFEDCBA9777777778n);
+testAdd(0xFEDCBA97n, 0xFEDCBA97n, 0x1FDB9752En);
+testAdd(0xFEDCBA97n, 0x1234n, 0xFEDCCCCBn);
+testAdd(0xFEDCBA97n, 0x3n, 0xFEDCBA9An);
+testAdd(0xFEDCBA97n, 0x2n, 0xFEDCBA99n);
+testAdd(0xFEDCBA97n, 0x1n, 0xFEDCBA98n);
+testAdd(0xFEDCBA97n, 0x0n, 0xFEDCBA97n);
+testAdd(0xFEDCBA97n, -0x1n, 0xFEDCBA96n);
+testAdd(0xFEDCBA97n, -0x2n, 0xFEDCBA95n);
+testAdd(0xFEDCBA97n, -0x3n, 0xFEDCBA94n);
+testAdd(0xFEDCBA97n, -0x1234n, 0xFEDCA863n);
+testAdd(0xFEDCBA97n, -0xFEDCBA97n, 0x0n);
+testAdd(0xFEDCBA97n, -0xFEDCBA98n, -0x1n);
+testAdd(0xFEDCBA97n, -0xFEDCBA987654320Fn, -0xFEDCBA9777777778n);
+testAdd(0xFEDCBA97n, -0xFEDCBA9876543210n, -0xFEDCBA9777777779n);
+testAdd(0x1234n, 0x1234n, 0x2468n);
+testAdd(0x1234n, 0x3n, 0x1237n);
+testAdd(0x1234n, 0x2n, 0x1236n);
+testAdd(0x1234n, 0x1n, 0x1235n);
+testAdd(0x1234n, 0x0n, 0x1234n);
+testAdd(0x1234n, -0x1n, 0x1233n);
+testAdd(0x1234n, -0x2n, 0x1232n);
+testAdd(0x1234n, -0x3n, 0x1231n);
+testAdd(0x1234n, -0x1234n, 0x0n);
+testAdd(0x1234n, -0xFEDCBA97n, -0xFEDCA863n);
+testAdd(0x1234n, -0xFEDCBA98n, -0xFEDCA864n);
+testAdd(0x1234n, -0xFEDCBA987654320Fn, -0xFEDCBA9876541FDBn);
+testAdd(0x1234n, -0xFEDCBA9876543210n, -0xFEDCBA9876541FDCn);
+testAdd(0x3n, 0x3n, 0x6n);
+testAdd(0x3n, 0x2n, 0x5n);
+testAdd(0x3n, 0x1n, 0x4n);
+testAdd(0x3n, 0x0n, 0x3n);
+testAdd(0x3n, -0x1n, 0x2n);
+testAdd(0x3n, -0x2n, 0x1n);
+testAdd(0x3n, -0x3n, 0x0n);
+testAdd(0x3n, -0x1234n, -0x1231n);
+testAdd(0x3n, -0xFEDCBA97n, -0xFEDCBA94n);
+testAdd(0x3n, -0xFEDCBA98n, -0xFEDCBA95n);
+testAdd(0x3n, -0xFEDCBA987654320Fn, -0xFEDCBA987654320Cn);
+testAdd(0x3n, -0xFEDCBA9876543210n, -0xFEDCBA987654320Dn);
+testAdd(0x2n, 0x2n, 0x4n);
+testAdd(0x2n, 0x1n, 0x3n);
+testAdd(0x2n, 0x0n, 0x2n);
+testAdd(0x2n, -0x1n, 0x1n);
+testAdd(0x2n, -0x2n, 0x0n);
+testAdd(0x2n, -0x3n, -0x1n);
+testAdd(0x2n, -0x1234n, -0x1232n);
+testAdd(0x2n, -0xFEDCBA97n, -0xFEDCBA95n);
+testAdd(0x2n, -0xFEDCBA98n, -0xFEDCBA96n);
+testAdd(0x2n, -0xFEDCBA987654320Fn, -0xFEDCBA987654320Dn);
+testAdd(0x2n, -0xFEDCBA9876543210n, -0xFEDCBA987654320En);
+testAdd(0x1n, 0x1n, 0x2n);
+testAdd(0x1n, 0x0n, 0x1n);
+testAdd(0x1n, -0x1n, 0x0n);
+testAdd(0x1n, -0x2n, -0x1n);
+testAdd(0x1n, -0x3n, -0x2n);
+testAdd(0x1n, -0x1234n, -0x1233n);
+testAdd(0x1n, -0xFEDCBA97n, -0xFEDCBA96n);
+testAdd(0x1n, -0xFEDCBA98n, -0xFEDCBA97n);
+testAdd(0x1n, -0xFEDCBA987654320Fn, -0xFEDCBA987654320En);
+testAdd(0x1n, -0xFEDCBA9876543210n, -0xFEDCBA987654320Fn);
+testAdd(0x0n, 0x0n, 0x0n);
+testAdd(0x0n, -0x1n, -0x1n);
+testAdd(0x0n, -0x2n, -0x2n);
+testAdd(0x0n, -0x3n, -0x3n);
+testAdd(0x0n, -0x1234n, -0x1234n);
+testAdd(0x0n, -0xFEDCBA97n, -0xFEDCBA97n);
+testAdd(0x0n, -0xFEDCBA98n, -0xFEDCBA98n);
+testAdd(0x0n, -0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn);
+testAdd(0x0n, -0xFEDCBA9876543210n, -0xFEDCBA9876543210n);
+testAdd(-0x1n, -0x1n, -0x2n);
+testAdd(-0x1n, -0x2n, -0x3n);
+testAdd(-0x1n, -0x3n, -0x4n);
+testAdd(-0x1n, -0x1234n, -0x1235n);
+testAdd(-0x1n, -0xFEDCBA97n, -0xFEDCBA98n);
+testAdd(-0x1n, -0xFEDCBA98n, -0xFEDCBA99n);
+testAdd(-0x1n, -0xFEDCBA987654320Fn, -0xFEDCBA9876543210n);
+testAdd(-0x1n, -0xFEDCBA9876543210n, -0xFEDCBA9876543211n);
+testAdd(-0x2n, -0x2n, -0x4n);
+testAdd(-0x2n, -0x3n, -0x5n);
+testAdd(-0x2n, -0x1234n, -0x1236n);
+testAdd(-0x2n, -0xFEDCBA97n, -0xFEDCBA99n);
+testAdd(-0x2n, -0xFEDCBA98n, -0xFEDCBA9An);
+testAdd(-0x2n, -0xFEDCBA987654320Fn, -0xFEDCBA9876543211n);
+testAdd(-0x2n, -0xFEDCBA9876543210n, -0xFEDCBA9876543212n);
+testAdd(-0x3n, -0x3n, -0x6n);
+testAdd(-0x3n, -0x1234n, -0x1237n);
+testAdd(-0x3n, -0xFEDCBA97n, -0xFEDCBA9An);
+testAdd(-0x3n, -0xFEDCBA98n, -0xFEDCBA9Bn);
+testAdd(-0x3n, -0xFEDCBA987654320Fn, -0xFEDCBA9876543212n);
+testAdd(-0x3n, -0xFEDCBA9876543210n, -0xFEDCBA9876543213n);
+testAdd(-0x1234n, -0x1234n, -0x2468n);
+testAdd(-0x1234n, -0xFEDCBA97n, -0xFEDCCCCBn);
+testAdd(-0x1234n, -0xFEDCBA98n, -0xFEDCCCCCn);
+testAdd(-0x1234n, -0xFEDCBA987654320Fn, -0xFEDCBA9876544443n);
+testAdd(-0x1234n, -0xFEDCBA9876543210n, -0xFEDCBA9876544444n);
+testAdd(-0xFEDCBA97n, -0xFEDCBA97n, -0x1FDB9752En);
+testAdd(-0xFEDCBA97n, -0xFEDCBA98n, -0x1FDB9752Fn);
+testAdd(-0xFEDCBA97n, -0xFEDCBA987654320Fn, -0xFEDCBA997530ECA6n);
+testAdd(-0xFEDCBA97n, -0xFEDCBA9876543210n, -0xFEDCBA997530ECA7n);
+testAdd(-0xFEDCBA98n, -0xFEDCBA98n, -0x1FDB97530n);
+testAdd(-0xFEDCBA98n, -0xFEDCBA987654320Fn, -0xFEDCBA997530ECA7n);
+testAdd(-0xFEDCBA98n, -0xFEDCBA9876543210n, -0xFEDCBA997530ECA8n);
+testAdd(-0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn, -0x1FDB97530ECA8641En);
+testAdd(-0xFEDCBA987654320Fn, -0xFEDCBA9876543210n, -0x1FDB97530ECA8641Fn);
+testAdd(-0xFEDCBA9876543210n, -0xFEDCBA9876543210n, -0x1FDB97530ECA86420n);
+
diff --git a/JSTests/stress/big-int-addition-jit.js b/JSTests/stress/big-int-addition-jit.js
new file mode 100644 (file)
index 0000000..1158e0a
--- /dev/null
@@ -0,0 +1,19 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntAddition(x, y) {
+    return x + y;
+}
+noInline(bigIntAddition);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntAddition(3n, 10n);
+    assert.sameValue(r, 13n, 3n + " + " + 10n + " = " + r);
+}
+
diff --git a/JSTests/stress/big-int-addition-memory-stress.js b/JSTests/stress/big-int-addition-memory-stress.js
new file mode 100644 (file)
index 0000000..8b1aeb1
--- /dev/null
@@ -0,0 +1,14 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+let a = 0n;
+for (let i = 0; i < 1000000; i++) {
+    a += 30n;
+}
+
+assert(a === 30000000n);
+
diff --git a/JSTests/stress/big-int-addition-string-coercion.js b/JSTests/stress/big-int-addition-string-coercion.js
new file mode 100644 (file)
index 0000000..bbde05a
--- /dev/null
@@ -0,0 +1,25 @@
+//@ runBigIntEnabled
+
+function assert(input, expected) {
+    if (input !== expected)
+        throw new Error("Bad!");
+}
+
+assert(-1n + "", "-1");
+assert("" + -1n, "-1");
+assert(0n + "", "0");
+assert("" + 0n, "0");
+assert(1n + "", "1");
+assert("" + 1n, "1");
+assert(123456789000000000000000n + "", "123456789000000000000000");
+assert("" + 123456789000000000000000n, "123456789000000000000000");
+assert(-123456789000000000000000n + "", "-123456789000000000000000");
+assert("" + -123456789000000000000000n, "-123456789000000000000000");
+
+assert([] + -123456789000000000000000n, "-123456789000000000000000");
+assert(-123456789000000000000000n + [], "-123456789000000000000000");
+
+let a = {};
+assert(a + 3n, "[object Object]3");
+assert(3n + a, "3[object Object]");
+
diff --git a/JSTests/stress/big-int-addition-to-primitive-precedence.js b/JSTests/stress/big-int-addition-to-primitive-precedence.js
new file mode 100644 (file)
index 0000000..cdedc14
--- /dev/null
@@ -0,0 +1,39 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testAdd(x, y, z, message) {
+    assert.sameValue(x + y, z, message);
+    assert.sameValue(y + x, z, message);
+}
+
+testAdd(Object(2n), 1n, 3n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    },
+    valueOf: function () {
+        throw new Error("Should never execute it");
+    },
+    toString: function () {
+        throw new Error("Should never execute it");
+    }
+};
+testAdd(o, 1n, 3n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    },
+    toString: function () {
+        throw new Error("Should never execute it");
+    }
+};
+testAdd(o, 1n, 3n, "ToPrimitive: valueOf");
+
diff --git a/JSTests/stress/big-int-addition-to-primitive.js b/JSTests/stress/big-int-addition-to-primitive.js
new file mode 100644 (file)
index 0000000..2f65f9c
--- /dev/null
@@ -0,0 +1,39 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+assert.sameValue = function (input, expected, message) {
+    if (input !== expected)
+        throw new Error(message);
+}
+
+function testAdd(x, y, z) {
+    assert.sameValue(x + y, z, x + " + " + y + " = " + z);
+    assert.sameValue(y + x, z, y + " + " + x + " = " + z);
+}
+
+let o = {
+    [Symbol.toPrimitive]: function () { return 300000000000000n; }
+}
+
+testAdd(500000000000438n, o, 800000000000438n);
+
+o.valueOf = function () {
+    throw new Error("Should never execute it");
+};
+
+testAdd(700000000000438n, o, 1000000000000438n);
+
+o.toString = function () {
+    throw new Error("Should never execute it");
+};
+
+testAdd(700000000000438n, o, 1000000000000438n);
+
+delete o.valueOf;
+
+testAdd(700000000000438n, o, 1000000000000438n);
+
diff --git a/JSTests/stress/big-int-addition-type-error.js b/JSTests/stress/big-int-addition-type-error.js
new file mode 100644 (file)
index 0000000..e2f824c
--- /dev/null
@@ -0,0 +1,104 @@
+//@ runBigIntEnabled
+
+function assert(a, message) {
+    if (!a)
+        throw new Error(message);
+}
+
+function assertThrowTypeError(a, b, message) {
+    try {
+        let n = a + b;
+        assert(false, message + ": Should throw TypeError, but executed without exception");
+    } catch (e) {
+        assert(e instanceof TypeError, message + ": expected TypeError, got: " + e);
+    }
+}
+
+assertThrowTypeError(30n, Symbol("foo"), "BigInt + Symbol");
+assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol + BigInt");
+assertThrowTypeError(30n, 3320, "BigInt + Int32");
+assertThrowTypeError(33256, 18757382984821n, "Int32 + BigInt");
+assertThrowTypeError(30n, 0.543, "BigInt + Double");
+assertThrowTypeError(230.19293, 18757382984821n, "Double + BigInt");
+assertThrowTypeError(30n, NaN, "BigInt + NaN");
+assertThrowTypeError(NaN, 18757382984821n, "NaN + BigInt");
+assertThrowTypeError(30n, NaN, "BigInt + NaN");
+assertThrowTypeError(NaN, 18757382984821n, "NaN + BigInt");
+assertThrowTypeError(30n, +Infinity, "BigInt + NaN");
+assertThrowTypeError(+Infinity, 18757382984821n, "NaN + BigInt");
+assertThrowTypeError(30n, -Infinity, "BigInt + -Infinity");
+assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity + BigInt");
+assertThrowTypeError(30n, null, "BigInt + null");
+assertThrowTypeError(null, 18757382984821n, "null + BigInt");
+assertThrowTypeError(30n, undefined, "BigInt + undefined");
+assertThrowTypeError(undefined, 18757382984821n, "undefined + BigInt");
+assertThrowTypeError(30n, true, "BigInt + true");
+assertThrowTypeError(true, 18757382984821n, "true + BigInt");
+assertThrowTypeError(30n, false, "BigInt + false");
+assertThrowTypeError(false, 18757382984821n, "false + BigInt");
+
+// Error when returning from object
+
+let o = {
+    valueOf: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.valueOf returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol + BigInt");
+
+o = {
+    valueOf: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.valueOf returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 + BigInt");
+
+o = {
+    valueOf: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.valueOf returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double + BigInt");
+
+o = {
+    toString: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.toString returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol + BigInt");
+
+o = {
+    toString: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.toString returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 + BigInt");
+
+o = {
+    toString: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.toString returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double + BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.@@toPrimitive returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol + BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.@@toPrimitive returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 + BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BigInt + Object.@@toPrimitive returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double + BigInt");
+
index f380b57..1406128 100644 (file)
@@ -7,6 +7,6 @@ try {
   message = error.message;
 }
 
-if (message !== "Conversion from 'BigInt' to 'number' is not allowed.") {
+if (message !== "Invalid mix of BigInt and other type in addition.") {
   throw new Error("Error message has changed to something unexpected");
 }
diff --git a/JSTests/stress/big-int-sub-wrapped-value.js b/JSTests/stress/big-int-sub-wrapped-value.js
new file mode 100644 (file)
index 0000000..5b18880
--- /dev/null
@@ -0,0 +1,36 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testSub(x, y, z, message) {
+    assert.sameValue(x - y, z, message);
+}
+
+testSub(Object(2n), 1n, 1n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    }
+};
+testSub(o, 1n, 1n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    }
+};
+testSub(o, 1n, 1n, "ToPrimitive: valueOf");
+
+o = {
+    toString: function() {
+        return 2n;
+    }
+}
+testSub(o, 1n, 1n, "ToPrimitive: toString");
+
diff --git a/JSTests/stress/big-int-subtraction-basic.js b/JSTests/stress/big-int-subtraction-basic.js
new file mode 100644 (file)
index 0000000..9021324
--- /dev/null
@@ -0,0 +1,303 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testSub(x, y, z) {
+    assert.sameValue(x - y, z, x + " - " + y + " = " + z);
+}
+
+testSub(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0x0n);
+testSub(0xFEDCBA9876543210n, 0xFEDCBA987654320Fn, 0x1n);
+testSub(0xFEDCBA9876543210n, 0xFEDCBA98n, 0xFEDCBA9777777778n);
+testSub(0xFEDCBA9876543210n, 0xFEDCBA97n, 0xFEDCBA9777777779n);
+testSub(0xFEDCBA9876543210n, 0x1234n, 0xFEDCBA9876541FDCn);
+testSub(0xFEDCBA9876543210n, 0x3n, 0xFEDCBA987654320Dn);
+testSub(0xFEDCBA9876543210n, 0x2n, 0xFEDCBA987654320En);
+testSub(0xFEDCBA9876543210n, 0x1n, 0xFEDCBA987654320Fn);
+testSub(0xFEDCBA9876543210n, 0x0n, 0xFEDCBA9876543210n);
+testSub(0xFEDCBA9876543210n, -0x1n, 0xFEDCBA9876543211n);
+testSub(0xFEDCBA9876543210n, -0x2n, 0xFEDCBA9876543212n);
+testSub(0xFEDCBA9876543210n, -0x3n, 0xFEDCBA9876543213n);
+testSub(0xFEDCBA9876543210n, -0x1234n, 0xFEDCBA9876544444n);
+testSub(0xFEDCBA9876543210n, -0xFEDCBA97n, 0xFEDCBA997530ECA7n);
+testSub(0xFEDCBA9876543210n, -0xFEDCBA98n, 0xFEDCBA997530ECA8n);
+testSub(0xFEDCBA9876543210n, -0xFEDCBA987654320Fn, 0x1FDB97530ECA8641Fn);
+testSub(0xFEDCBA9876543210n, -0xFEDCBA9876543210n, 0x1FDB97530ECA86420n);
+testSub(0xFEDCBA987654320Fn, 0xFEDCBA9876543210n, -0x1n);
+testSub(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0x0n);
+testSub(0xFEDCBA987654320Fn, 0xFEDCBA98n, 0xFEDCBA9777777777n);
+testSub(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0xFEDCBA9777777778n);
+testSub(0xFEDCBA987654320Fn, 0x1234n, 0xFEDCBA9876541FDBn);
+testSub(0xFEDCBA987654320Fn, 0x3n, 0xFEDCBA987654320Cn);
+testSub(0xFEDCBA987654320Fn, 0x2n, 0xFEDCBA987654320Dn);
+testSub(0xFEDCBA987654320Fn, 0x1n, 0xFEDCBA987654320En);
+testSub(0xFEDCBA987654320Fn, 0x0n, 0xFEDCBA987654320Fn);
+testSub(0xFEDCBA987654320Fn, -0x1n, 0xFEDCBA9876543210n);
+testSub(0xFEDCBA987654320Fn, -0x2n, 0xFEDCBA9876543211n);
+testSub(0xFEDCBA987654320Fn, -0x3n, 0xFEDCBA9876543212n);
+testSub(0xFEDCBA987654320Fn, -0x1234n, 0xFEDCBA9876544443n);
+testSub(0xFEDCBA987654320Fn, -0xFEDCBA97n, 0xFEDCBA997530ECA6n);
+testSub(0xFEDCBA987654320Fn, -0xFEDCBA98n, 0xFEDCBA997530ECA7n);
+testSub(0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn, 0x1FDB97530ECA8641En);
+testSub(0xFEDCBA987654320Fn, -0xFEDCBA9876543210n, 0x1FDB97530ECA8641Fn);
+testSub(0xFEDCBA98n, 0xFEDCBA9876543210n, -0xFEDCBA9777777778n);
+testSub(0xFEDCBA98n, 0xFEDCBA987654320Fn, -0xFEDCBA9777777777n);
+testSub(0xFEDCBA98n, 0xFEDCBA98n, 0x0n);
+testSub(0xFEDCBA98n, 0xFEDCBA97n, 0x1n);
+testSub(0xFEDCBA98n, 0x1234n, 0xFEDCA864n);
+testSub(0xFEDCBA98n, 0x3n, 0xFEDCBA95n);
+testSub(0xFEDCBA98n, 0x2n, 0xFEDCBA96n);
+testSub(0xFEDCBA98n, 0x1n, 0xFEDCBA97n);
+testSub(0xFEDCBA98n, 0x0n, 0xFEDCBA98n);
+testSub(0xFEDCBA98n, -0x1n, 0xFEDCBA99n);
+testSub(0xFEDCBA98n, -0x2n, 0xFEDCBA9An);
+testSub(0xFEDCBA98n, -0x3n, 0xFEDCBA9Bn);
+testSub(0xFEDCBA98n, -0x1234n, 0xFEDCCCCCn);
+testSub(0xFEDCBA98n, -0xFEDCBA97n, 0x1FDB9752Fn);
+testSub(0xFEDCBA98n, -0xFEDCBA98n, 0x1FDB97530n);
+testSub(0xFEDCBA98n, -0xFEDCBA987654320Fn, 0xFEDCBA997530ECA7n);
+testSub(0xFEDCBA98n, -0xFEDCBA9876543210n, 0xFEDCBA997530ECA8n);
+testSub(0xFEDCBA97n, 0xFEDCBA9876543210n, -0xFEDCBA9777777779n);
+testSub(0xFEDCBA97n, 0xFEDCBA987654320Fn, -0xFEDCBA9777777778n);
+testSub(0xFEDCBA97n, 0xFEDCBA98n, -0x1n);
+testSub(0xFEDCBA97n, 0xFEDCBA97n, 0x0n);
+testSub(0xFEDCBA97n, 0x1234n, 0xFEDCA863n);
+testSub(0xFEDCBA97n, 0x3n, 0xFEDCBA94n);
+testSub(0xFEDCBA97n, 0x2n, 0xFEDCBA95n);
+testSub(0xFEDCBA97n, 0x1n, 0xFEDCBA96n);
+testSub(0xFEDCBA97n, 0x0n, 0xFEDCBA97n);
+testSub(0xFEDCBA97n, -0x1n, 0xFEDCBA98n);
+testSub(0xFEDCBA97n, -0x2n, 0xFEDCBA99n);
+testSub(0xFEDCBA97n, -0x3n, 0xFEDCBA9An);
+testSub(0xFEDCBA97n, -0x1234n, 0xFEDCCCCBn);
+testSub(0xFEDCBA97n, -0xFEDCBA97n, 0x1FDB9752En);
+testSub(0xFEDCBA97n, -0xFEDCBA98n, 0x1FDB9752Fn);
+testSub(0xFEDCBA97n, -0xFEDCBA987654320Fn, 0xFEDCBA997530ECA6n);
+testSub(0xFEDCBA97n, -0xFEDCBA9876543210n, 0xFEDCBA997530ECA7n);
+testSub(0x1234n, 0xFEDCBA9876543210n, -0xFEDCBA9876541FDCn);
+testSub(0x1234n, 0xFEDCBA987654320Fn, -0xFEDCBA9876541FDBn);
+testSub(0x1234n, 0xFEDCBA98n, -0xFEDCA864n);
+testSub(0x1234n, 0xFEDCBA97n, -0xFEDCA863n);
+testSub(0x1234n, 0x1234n, 0x0n);
+testSub(0x1234n, 0x3n, 0x1231n);
+testSub(0x1234n, 0x2n, 0x1232n);
+testSub(0x1234n, 0x1n, 0x1233n);
+testSub(0x1234n, 0x0n, 0x1234n);
+testSub(0x1234n, -0x1n, 0x1235n);
+testSub(0x1234n, -0x2n, 0x1236n);
+testSub(0x1234n, -0x3n, 0x1237n);
+testSub(0x1234n, -0x1234n, 0x2468n);
+testSub(0x1234n, -0xFEDCBA97n, 0xFEDCCCCBn);
+testSub(0x1234n, -0xFEDCBA98n, 0xFEDCCCCCn);
+testSub(0x1234n, -0xFEDCBA987654320Fn, 0xFEDCBA9876544443n);
+testSub(0x1234n, -0xFEDCBA9876543210n, 0xFEDCBA9876544444n);
+testSub(0x3n, 0xFEDCBA9876543210n, -0xFEDCBA987654320Dn);
+testSub(0x3n, 0xFEDCBA987654320Fn, -0xFEDCBA987654320Cn);
+testSub(0x3n, 0xFEDCBA98n, -0xFEDCBA95n);
+testSub(0x3n, 0xFEDCBA97n, -0xFEDCBA94n);
+testSub(0x3n, 0x1234n, -0x1231n);
+testSub(0x3n, 0x3n, 0x0n);
+testSub(0x3n, 0x2n, 0x1n);
+testSub(0x3n, 0x1n, 0x2n);
+testSub(0x3n, 0x0n, 0x3n);
+testSub(0x3n, -0x1n, 0x4n);
+testSub(0x3n, -0x2n, 0x5n);
+testSub(0x3n, -0x3n, 0x6n);
+testSub(0x3n, -0x1234n, 0x1237n);
+testSub(0x3n, -0xFEDCBA97n, 0xFEDCBA9An);
+testSub(0x3n, -0xFEDCBA98n, 0xFEDCBA9Bn);
+testSub(0x3n, -0xFEDCBA987654320Fn, 0xFEDCBA9876543212n);
+testSub(0x3n, -0xFEDCBA9876543210n, 0xFEDCBA9876543213n);
+testSub(0x2n, 0xFEDCBA9876543210n, -0xFEDCBA987654320En);
+testSub(0x2n, 0xFEDCBA987654320Fn, -0xFEDCBA987654320Dn);
+testSub(0x2n, 0xFEDCBA98n, -0xFEDCBA96n);
+testSub(0x2n, 0xFEDCBA97n, -0xFEDCBA95n);
+testSub(0x2n, 0x1234n, -0x1232n);
+testSub(0x2n, 0x3n, -0x1n);
+testSub(0x2n, 0x2n, 0x0n);
+testSub(0x2n, 0x1n, 0x1n);
+testSub(0x2n, 0x0n, 0x2n);
+testSub(0x2n, -0x1n, 0x3n);
+testSub(0x2n, -0x2n, 0x4n);
+testSub(0x2n, -0x3n, 0x5n);
+testSub(0x2n, -0x1234n, 0x1236n);
+testSub(0x2n, -0xFEDCBA97n, 0xFEDCBA99n);
+testSub(0x2n, -0xFEDCBA98n, 0xFEDCBA9An);
+testSub(0x2n, -0xFEDCBA987654320Fn, 0xFEDCBA9876543211n);
+testSub(0x2n, -0xFEDCBA9876543210n, 0xFEDCBA9876543212n);
+testSub(0x1n, 0xFEDCBA9876543210n, -0xFEDCBA987654320Fn);
+testSub(0x1n, 0xFEDCBA987654320Fn, -0xFEDCBA987654320En);
+testSub(0x1n, 0xFEDCBA98n, -0xFEDCBA97n);
+testSub(0x1n, 0xFEDCBA97n, -0xFEDCBA96n);
+testSub(0x1n, 0x1234n, -0x1233n);
+testSub(0x1n, 0x3n, -0x2n);
+testSub(0x1n, 0x2n, -0x1n);
+testSub(0x1n, 0x1n, 0x0n);
+testSub(0x1n, 0x0n, 0x1n);
+testSub(0x1n, -0x1n, 0x2n);
+testSub(0x1n, -0x2n, 0x3n);
+testSub(0x1n, -0x3n, 0x4n);
+testSub(0x1n, -0x1234n, 0x1235n);
+testSub(0x1n, -0xFEDCBA97n, 0xFEDCBA98n);
+testSub(0x1n, -0xFEDCBA98n, 0xFEDCBA99n);
+testSub(0x1n, -0xFEDCBA987654320Fn, 0xFEDCBA9876543210n);
+testSub(0x1n, -0xFEDCBA9876543210n, 0xFEDCBA9876543211n);
+testSub(0x0n, 0xFEDCBA9876543210n, -0xFEDCBA9876543210n);
+testSub(0x0n, 0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn);
+testSub(0x0n, 0xFEDCBA98n, -0xFEDCBA98n);
+testSub(0x0n, 0xFEDCBA97n, -0xFEDCBA97n);
+testSub(0x0n, 0x1234n, -0x1234n);
+testSub(0x0n, 0x3n, -0x3n);
+testSub(0x0n, 0x2n, -0x2n);
+testSub(0x0n, 0x1n, -0x1n);
+testSub(0x0n, 0x0n, 0x0n);
+testSub(0x0n, -0x1n, 0x1n);
+testSub(0x0n, -0x2n, 0x2n);
+testSub(0x0n, -0x3n, 0x3n);
+testSub(0x0n, -0x1234n, 0x1234n);
+testSub(0x0n, -0xFEDCBA97n, 0xFEDCBA97n);
+testSub(0x0n, -0xFEDCBA98n, 0xFEDCBA98n);
+testSub(0x0n, -0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn);
+testSub(0x0n, -0xFEDCBA9876543210n, 0xFEDCBA9876543210n);
+testSub(-0x1n, 0xFEDCBA9876543210n, -0xFEDCBA9876543211n);
+testSub(-0x1n, 0xFEDCBA987654320Fn, -0xFEDCBA9876543210n);
+testSub(-0x1n, 0xFEDCBA98n, -0xFEDCBA99n);
+testSub(-0x1n, 0xFEDCBA97n, -0xFEDCBA98n);
+testSub(-0x1n, 0x1234n, -0x1235n);
+testSub(-0x1n, 0x3n, -0x4n);
+testSub(-0x1n, 0x2n, -0x3n);
+testSub(-0x1n, 0x1n, -0x2n);
+testSub(-0x1n, 0x0n, -0x1n);
+testSub(-0x1n, -0x1n, 0x0n);
+testSub(-0x1n, -0x2n, 0x1n);
+testSub(-0x1n, -0x3n, 0x2n);
+testSub(-0x1n, -0x1234n, 0x1233n);
+testSub(-0x1n, -0xFEDCBA97n, 0xFEDCBA96n);
+testSub(-0x1n, -0xFEDCBA98n, 0xFEDCBA97n);
+testSub(-0x1n, -0xFEDCBA987654320Fn, 0xFEDCBA987654320En);
+testSub(-0x1n, -0xFEDCBA9876543210n, 0xFEDCBA987654320Fn);
+testSub(-0x2n, 0xFEDCBA9876543210n, -0xFEDCBA9876543212n);
+testSub(-0x2n, 0xFEDCBA987654320Fn, -0xFEDCBA9876543211n);
+testSub(-0x2n, 0xFEDCBA98n, -0xFEDCBA9An);
+testSub(-0x2n, 0xFEDCBA97n, -0xFEDCBA99n);
+testSub(-0x2n, 0x1234n, -0x1236n);
+testSub(-0x2n, 0x3n, -0x5n);
+testSub(-0x2n, 0x2n, -0x4n);
+testSub(-0x2n, 0x1n, -0x3n);
+testSub(-0x2n, 0x0n, -0x2n);
+testSub(-0x2n, -0x1n, -0x1n);
+testSub(-0x2n, -0x2n, 0x0n);
+testSub(-0x2n, -0x3n, 0x1n);
+testSub(-0x2n, -0x1234n, 0x1232n);
+testSub(-0x2n, -0xFEDCBA97n, 0xFEDCBA95n);
+testSub(-0x2n, -0xFEDCBA98n, 0xFEDCBA96n);
+testSub(-0x2n, -0xFEDCBA987654320Fn, 0xFEDCBA987654320Dn);
+testSub(-0x2n, -0xFEDCBA9876543210n, 0xFEDCBA987654320En);
+testSub(-0x3n, 0xFEDCBA9876543210n, -0xFEDCBA9876543213n);
+testSub(-0x3n, 0xFEDCBA987654320Fn, -0xFEDCBA9876543212n);
+testSub(-0x3n, 0xFEDCBA98n, -0xFEDCBA9Bn);
+testSub(-0x3n, 0xFEDCBA97n, -0xFEDCBA9An);
+testSub(-0x3n, 0x1234n, -0x1237n);
+testSub(-0x3n, 0x3n, -0x6n);
+testSub(-0x3n, 0x2n, -0x5n);
+testSub(-0x3n, 0x1n, -0x4n);
+testSub(-0x3n, 0x0n, -0x3n);
+testSub(-0x3n, -0x1n, -0x2n);
+testSub(-0x3n, -0x2n, -0x1n);
+testSub(-0x3n, -0x3n, 0x0n);
+testSub(-0x3n, -0x1234n, 0x1231n);
+testSub(-0x3n, -0xFEDCBA97n, 0xFEDCBA94n);
+testSub(-0x3n, -0xFEDCBA98n, 0xFEDCBA95n);
+testSub(-0x3n, -0xFEDCBA987654320Fn, 0xFEDCBA987654320Cn);
+testSub(-0x3n, -0xFEDCBA9876543210n, 0xFEDCBA987654320Dn);
+testSub(-0x1234n, 0xFEDCBA9876543210n, -0xFEDCBA9876544444n);
+testSub(-0x1234n, 0xFEDCBA987654320Fn, -0xFEDCBA9876544443n);
+testSub(-0x1234n, 0xFEDCBA98n, -0xFEDCCCCCn);
+testSub(-0x1234n, 0xFEDCBA97n, -0xFEDCCCCBn);
+testSub(-0x1234n, 0x1234n, -0x2468n);
+testSub(-0x1234n, 0x3n, -0x1237n);
+testSub(-0x1234n, 0x2n, -0x1236n);
+testSub(-0x1234n, 0x1n, -0x1235n);
+testSub(-0x1234n, 0x0n, -0x1234n);
+testSub(-0x1234n, -0x1n, -0x1233n);
+testSub(-0x1234n, -0x2n, -0x1232n);
+testSub(-0x1234n, -0x3n, -0x1231n);
+testSub(-0x1234n, -0x1234n, 0x0n);
+testSub(-0x1234n, -0xFEDCBA97n, 0xFEDCA863n);
+testSub(-0x1234n, -0xFEDCBA98n, 0xFEDCA864n);
+testSub(-0x1234n, -0xFEDCBA987654320Fn, 0xFEDCBA9876541FDBn);
+testSub(-0x1234n, -0xFEDCBA9876543210n, 0xFEDCBA9876541FDCn);
+testSub(-0xFEDCBA97n, 0xFEDCBA9876543210n, -0xFEDCBA997530ECA7n);
+testSub(-0xFEDCBA97n, 0xFEDCBA987654320Fn, -0xFEDCBA997530ECA6n);
+testSub(-0xFEDCBA97n, 0xFEDCBA98n, -0x1FDB9752Fn);
+testSub(-0xFEDCBA97n, 0xFEDCBA97n, -0x1FDB9752En);
+testSub(-0xFEDCBA97n, 0x1234n, -0xFEDCCCCBn);
+testSub(-0xFEDCBA97n, 0x3n, -0xFEDCBA9An);
+testSub(-0xFEDCBA97n, 0x2n, -0xFEDCBA99n);
+testSub(-0xFEDCBA97n, 0x1n, -0xFEDCBA98n);
+testSub(-0xFEDCBA97n, 0x0n, -0xFEDCBA97n);
+testSub(-0xFEDCBA97n, -0x1n, -0xFEDCBA96n);
+testSub(-0xFEDCBA97n, -0x2n, -0xFEDCBA95n);
+testSub(-0xFEDCBA97n, -0x3n, -0xFEDCBA94n);
+testSub(-0xFEDCBA97n, -0x1234n, -0xFEDCA863n);
+testSub(-0xFEDCBA97n, -0xFEDCBA97n, 0x0n);
+testSub(-0xFEDCBA97n, -0xFEDCBA98n, 0x1n);
+testSub(-0xFEDCBA97n, -0xFEDCBA987654320Fn, 0xFEDCBA9777777778n);
+testSub(-0xFEDCBA97n, -0xFEDCBA9876543210n, 0xFEDCBA9777777779n);
+testSub(-0xFEDCBA98n, 0xFEDCBA9876543210n, -0xFEDCBA997530ECA8n);
+testSub(-0xFEDCBA98n, 0xFEDCBA987654320Fn, -0xFEDCBA997530ECA7n);
+testSub(-0xFEDCBA98n, 0xFEDCBA98n, -0x1FDB97530n);
+testSub(-0xFEDCBA98n, 0xFEDCBA97n, -0x1FDB9752Fn);
+testSub(-0xFEDCBA98n, 0x1234n, -0xFEDCCCCCn);
+testSub(-0xFEDCBA98n, 0x3n, -0xFEDCBA9Bn);
+testSub(-0xFEDCBA98n, 0x2n, -0xFEDCBA9An);
+testSub(-0xFEDCBA98n, 0x1n, -0xFEDCBA99n);
+testSub(-0xFEDCBA98n, 0x0n, -0xFEDCBA98n);
+testSub(-0xFEDCBA98n, -0x1n, -0xFEDCBA97n);
+testSub(-0xFEDCBA98n, -0x2n, -0xFEDCBA96n);
+testSub(-0xFEDCBA98n, -0x3n, -0xFEDCBA95n);
+testSub(-0xFEDCBA98n, -0x1234n, -0xFEDCA864n);
+testSub(-0xFEDCBA98n, -0xFEDCBA97n, -0x1n);
+testSub(-0xFEDCBA98n, -0xFEDCBA98n, 0x0n);
+testSub(-0xFEDCBA98n, -0xFEDCBA987654320Fn, 0xFEDCBA9777777777n);
+testSub(-0xFEDCBA98n, -0xFEDCBA9876543210n, 0xFEDCBA9777777778n);
+testSub(-0xFEDCBA987654320Fn, 0xFEDCBA9876543210n, -0x1FDB97530ECA8641Fn);
+testSub(-0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, -0x1FDB97530ECA8641En);
+testSub(-0xFEDCBA987654320Fn, 0xFEDCBA98n, -0xFEDCBA997530ECA7n);
+testSub(-0xFEDCBA987654320Fn, 0xFEDCBA97n, -0xFEDCBA997530ECA6n);
+testSub(-0xFEDCBA987654320Fn, 0x1234n, -0xFEDCBA9876544443n);
+testSub(-0xFEDCBA987654320Fn, 0x3n, -0xFEDCBA9876543212n);
+testSub(-0xFEDCBA987654320Fn, 0x2n, -0xFEDCBA9876543211n);
+testSub(-0xFEDCBA987654320Fn, 0x1n, -0xFEDCBA9876543210n);
+testSub(-0xFEDCBA987654320Fn, 0x0n, -0xFEDCBA987654320Fn);
+testSub(-0xFEDCBA987654320Fn, -0x1n, -0xFEDCBA987654320En);
+testSub(-0xFEDCBA987654320Fn, -0x2n, -0xFEDCBA987654320Dn);
+testSub(-0xFEDCBA987654320Fn, -0x3n, -0xFEDCBA987654320Cn);
+testSub(-0xFEDCBA987654320Fn, -0x1234n, -0xFEDCBA9876541FDBn);
+testSub(-0xFEDCBA987654320Fn, -0xFEDCBA97n, -0xFEDCBA9777777778n);
+testSub(-0xFEDCBA987654320Fn, -0xFEDCBA98n, -0xFEDCBA9777777777n);
+testSub(-0xFEDCBA987654320Fn, -0xFEDCBA987654320Fn, 0x0n);
+testSub(-0xFEDCBA987654320Fn, -0xFEDCBA9876543210n, 0x1n);
+testSub(-0xFEDCBA9876543210n, 0xFEDCBA9876543210n, -0x1FDB97530ECA86420n);
+testSub(-0xFEDCBA9876543210n, 0xFEDCBA987654320Fn, -0x1FDB97530ECA8641Fn);
+testSub(-0xFEDCBA9876543210n, 0xFEDCBA98n, -0xFEDCBA997530ECA8n);
+testSub(-0xFEDCBA9876543210n, 0xFEDCBA97n, -0xFEDCBA997530ECA7n);
+testSub(-0xFEDCBA9876543210n, 0x1234n, -0xFEDCBA9876544444n);
+testSub(-0xFEDCBA9876543210n, 0x3n, -0xFEDCBA9876543213n);
+testSub(-0xFEDCBA9876543210n, 0x2n, -0xFEDCBA9876543212n);
+testSub(-0xFEDCBA9876543210n, 0x1n, -0xFEDCBA9876543211n);
+testSub(-0xFEDCBA9876543210n, 0x0n, -0xFEDCBA9876543210n);
+testSub(-0xFEDCBA9876543210n, -0x1n, -0xFEDCBA987654320Fn);
+testSub(-0xFEDCBA9876543210n, -0x2n, -0xFEDCBA987654320En);
+testSub(-0xFEDCBA9876543210n, -0x3n, -0xFEDCBA987654320Dn);
+testSub(-0xFEDCBA9876543210n, -0x1234n, -0xFEDCBA9876541FDCn);
+testSub(-0xFEDCBA9876543210n, -0xFEDCBA97n, -0xFEDCBA9777777779n);
+testSub(-0xFEDCBA9876543210n, -0xFEDCBA98n, -0xFEDCBA9777777778n);
+testSub(-0xFEDCBA9876543210n, -0xFEDCBA987654320Fn, -0x1n);
+testSub(-0xFEDCBA9876543210n, -0xFEDCBA9876543210n, 0x0n);
+
diff --git a/JSTests/stress/big-int-subtraction-jit.js b/JSTests/stress/big-int-subtraction-jit.js
new file mode 100644 (file)
index 0000000..cb081aa
--- /dev/null
@@ -0,0 +1,19 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntAddition(x, y) {
+    return x - y;
+}
+noInline(bigIntAddition);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntAddition(3n, 10n);
+    assert.sameValue(r, -7n, 3n + " - " + 10n + " = " + r);
+}
+
diff --git a/JSTests/stress/big-int-subtraction-type-error.js b/JSTests/stress/big-int-subtraction-type-error.js
new file mode 100644 (file)
index 0000000..74ac48a
--- /dev/null
@@ -0,0 +1,125 @@
+//@ runBigIntEnabled
+
+function assert(a, message) {
+    if (!a)
+        throw new Error(message);
+}
+
+function assertThrowTypeError(a, b, message) {
+    try {
+        let n = a - b;
+        assert(false, message + ": Should throw TypeError, but executed without exception");
+    } catch (e) {
+        assert(e instanceof TypeError, message + ": expected TypeError, got: " + e);
+    }
+}
+
+assertThrowTypeError(30n, Symbol("foo"), "BingInt - Symbol");
+assertThrowTypeError(Symbol("bar"), 18757382984821n, "Symbol - BigInt");
+assertThrowTypeError(30n, 3320, "BingInt - Int32");
+assertThrowTypeError(33256, 18757382984821n, "Int32 - BigInt");
+assertThrowTypeError(30n, 0.543, "BingInt - Double");
+assertThrowTypeError(230.19293, 18757382984821n, "Double - BigInt");
+assertThrowTypeError(18757382984821n, "abc", "BigInt - String");
+assertThrowTypeError("def", 18757382984821n, "String - BigInt");
+assertThrowTypeError(18757382984821n, "", "BigInt - Empty String");
+assertThrowTypeError("", 18757382984821n, "Empty - BigInt");
+assertThrowTypeError(18757382984821n, NaN, "BigInt - NaN");
+assertThrowTypeError(NaN, 18757382984821n, "NaN - BigInt");
+assertThrowTypeError(18757382984821n, undefined, "BigInt - undefined");
+assertThrowTypeError(undefined, 18757382984821n, "undefined - BigInt");
+assertThrowTypeError(18757382984821n, true, "BigInt - true");
+assertThrowTypeError(true, 18757382984821n, "true - BigInt");
+assertThrowTypeError(18757382984821n, false, "BigInt - false");
+assertThrowTypeError(false, 18757382984821n, "false - BigInt");
+assertThrowTypeError(18757382984821n, +Infinity, "BigInt - Infinity");
+assertThrowTypeError(+Infinity, 18757382984821n, "Infinity - BigInt");
+assertThrowTypeError(18757382984821n, -Infinity, "BigInt - -Infinity");
+assertThrowTypeError(-Infinity, 18757382984821n, "-Infinity - BigInt");
+
+// Error when returning from object
+
+let o = {
+    valueOf: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.valueOf returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Symbol - BigInt");
+
+o = {
+    valueOf: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.valueOf returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Int32 - BigInt");
+
+o = {
+    valueOf: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.valueOf returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning Double - BigInt");
+
+o = {
+    valueOf: function () { return ""; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.valueOf returning String");
+assertThrowTypeError(o, 18757382984821n, "Object.valueOf returning String - BigInt");
+
+o = {
+    toString: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.toString returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Symbol - BigInt");
+
+o = {
+    toString: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.toString returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Int32 - BigInt");
+
+o = {
+    toString: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.toString returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning Double - BigInt");
+
+o = {
+    toString: function () { return "abc"; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.toString returning String");
+assertThrowTypeError(o, 18757382984821n, "Object.toString returning String - BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return Symbol("Foo"); }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.@@toPrimitive returning Symbol");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Symbol - BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return 33256; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.@@toPrimitive returning Int32");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Int32 - BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return 0.453; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.@@toPrimitive returning Double");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning Double - BigInt");
+
+o = {
+    [Symbol.toPrimitive]: function () { return "Abc"; }
+};
+
+assertThrowTypeError(30n, o, "BingInt - Object.@@toPrimitive returning String");
+assertThrowTypeError(o, 18757382984821n, "Object.@@toPrimitive returning String - BigInt");
+
diff --git a/JSTests/stress/sub-order-evaluation.js b/JSTests/stress/sub-order-evaluation.js
new file mode 100644 (file)
index 0000000..21f9234
--- /dev/null
@@ -0,0 +1,27 @@
+function assert(a, message) {
+    if (!a)
+        throw new Error(message);
+}
+
+function assertThrowTypeError(a, b, message) {
+    try {
+        let n = a - b;
+        assert(false, message + ": Should throw TypeError, but executed without exception");
+    } catch (e) {
+        assert(e instanceof TypeError, message + ": expected TypeError, got: " + e);
+    }
+}
+
+let o = {
+    valueOf: function () { throw new Error("Oops"); }
+};
+
+assertThrowTypeError(Symbol("3"), o, "Symbol + Object should throw TypeError");
+
+try {
+    let n = o - Symbol("3");
+    assert(false, message + ": Should throw Error, but executed without exception");
+} catch (e) {
+    assert(e.message === "Oops","Expected Error('Oops'), got: " + e);
+}
+
index 92185c8..eae9dc2 100644 (file)
@@ -1,3 +1,40 @@
+2018-06-02  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for addition operations
+        https://bugs.webkit.org/show_bug.cgi?id=179002
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch is implementing support to BigInt Operands into binary "+"
+        and binary "-" operators. Right now, we have limited support to DFG
+        and FTL JIT layers, but we plan to fix this support in future
+        patches.
+
+        * jit/JITOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::parseInt):
+        (JSC::JSBigInt::stringToBigInt):
+        (JSC::JSBigInt::toString):
+        (JSC::JSBigInt::multiply):
+        (JSC::JSBigInt::divide):
+        (JSC::JSBigInt::remainder):
+        (JSC::JSBigInt::add):
+        (JSC::JSBigInt::sub):
+        (JSC::JSBigInt::absoluteAdd):
+        (JSC::JSBigInt::absoluteSub):
+        (JSC::JSBigInt::toStringGeneric):
+        (JSC::JSBigInt::allocateFor):
+        (JSC::JSBigInt::toNumber const):
+        (JSC::JSBigInt::getPrimitiveNumber const):
+        * runtime/JSBigInt.h:
+        * runtime/JSCJSValueInlines.h:
+        * runtime/Operations.cpp:
+        (JSC::jsAddSlowCase):
+        * runtime/Operations.h:
+        (JSC::jsSub):
+
 2018-06-01  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Fix the watchOS build after r232385
index d381c1d..4bfd122 100644 (file)
@@ -2816,34 +2816,23 @@ EncodedJSValue JIT_OPERATION operationArithNegateOptimize(ExecState* exec, Encod
     return JSValue::encode(jsNumber(-number));
 }
 
-ALWAYS_INLINE static EncodedJSValue unprofiledSub(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+ALWAYS_INLINE static EncodedJSValue unprofiledSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
-    auto scope = DECLARE_THROW_SCOPE(vm);
     JSValue op1 = JSValue::decode(encodedOp1);
     JSValue op2 = JSValue::decode(encodedOp2);
-
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    scope.release();
-    double b = op2.toNumber(exec);
-    return JSValue::encode(jsNumber(a - b));
+    
+    return JSValue::encode(jsSub(exec, op1, op2));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledSub(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
+ALWAYS_INLINE static EncodedJSValue profiledSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
 {
-    auto scope = DECLARE_THROW_SCOPE(vm);
     JSValue op1 = JSValue::decode(encodedOp1);
     JSValue op2 = JSValue::decode(encodedOp2);
 
     if (shouldObserveLHSAndRHSTypes)
         arithProfile.observeLHSAndRHS(op1, op2);
 
-    double a = op1.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    double b = op2.toNumber(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    
-    JSValue result = jsNumber(a - b);
+    JSValue result = jsSub(exec, op1, op2);
     arithProfile.observeResult(result);
     return JSValue::encode(result);
 }
@@ -2852,7 +2841,7 @@ EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue e
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
-    return unprofiledSub(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledSub(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
@@ -2862,7 +2851,7 @@ EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJ
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    return profiledSub(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
+    return profiledSub(exec, encodedOp1, encodedOp2, *arithProfile);
 }
 
 EncodedJSValue JIT_OPERATION operationValueSubOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
@@ -2879,7 +2868,7 @@ EncodedJSValue JIT_OPERATION operationValueSubOptimize(ExecState* exec, EncodedJ
     exec->codeBlock()->dumpMathICStats();
 #endif
 
-    return unprofiledSub(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledSub(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueSubNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*)
@@ -2887,7 +2876,7 @@ EncodedJSValue JIT_OPERATION operationValueSubNoOptimize(ExecState* exec, Encode
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    return unprofiledSub(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledSub(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueSubProfiledOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
@@ -2905,7 +2894,7 @@ EncodedJSValue JIT_OPERATION operationValueSubProfiledOptimize(ExecState* exec,
     exec->codeBlock()->dumpMathICStats();
 #endif
 
-    return profiledSub(*vm, exec, encodedOp1, encodedOp2, *arithProfile, false);
+    return profiledSub(exec, encodedOp1, encodedOp2, *arithProfile, false);
 }
 
 EncodedJSValue JIT_OPERATION operationValueSubProfiledNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC* subIC)
@@ -2915,7 +2904,7 @@ EncodedJSValue JIT_OPERATION operationValueSubProfiledNoOptimize(ExecState* exec
 
     ArithProfile* arithProfile = subIC->arithProfile();
     ASSERT(arithProfile);
-    return profiledSub(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
+    return profiledSub(exec, encodedOp1, encodedOp2, *arithProfile);
 }
 
 void JIT_OPERATION operationProcessTypeProfilerLog(ExecState* exec)
index b7f093e..2b82170 100644 (file)
@@ -405,7 +405,7 @@ SLOW_PATH_DECL(slow_path_negate)
     CHECK_EXCEPTION();
 
     if (primValue.isBigInt()) {
-        JSBigInt* result = JSBigInt::unaryMinus(exec->vm(), asBigInt(primValue));
+        JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
         RETURN_WITH_PROFILING(result, {
             updateArithProfileForUnaryArithOp(pc, result, operand);
         });
@@ -517,10 +517,24 @@ SLOW_PATH_DECL(slow_path_sub)
     BEGIN();
     JSValue left = OP_C(2).jsValue();
     JSValue right = OP_C(3).jsValue();
-    double a = left.toNumber(exec);
-    if (UNLIKELY(throwScope.exception()))
-        RETURN(JSValue());
-    double b = right.toNumber(exec);
+    auto leftNumeric = left.toNumeric(exec);
+    CHECK_EXCEPTION();
+    auto rightNumeric = right.toNumeric(exec);
+    CHECK_EXCEPTION();
+
+    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+            JSBigInt* result = JSBigInt::sub(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            RETURN_WITH_PROFILING(result, {
+                updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
+            });
+        }
+
+        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in subtraction."));
+    }
+
+    double a = WTF::get<double>(leftNumeric);
+    double b = WTF::get<double>(rightNumeric);
     JSValue result = jsNumber(a - b);
     RETURN_WITH_PROFILING(result, {
         updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
@@ -539,7 +553,7 @@ SLOW_PATH_DECL(slow_path_div)
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSValue result(JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)));
+            JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
             RETURN_WITH_PROFILING(result, {
                 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
index 6742d9b..4e89641 100644 (file)
@@ -195,31 +195,31 @@ std::optional<uint8_t> JSBigInt::singleDigitValueForString()
     return { };
 }
 
-JSBigInt* JSBigInt::parseInt(ExecState* state, StringView s, ErrorParseMode parserMode)
+JSBigInt* JSBigInt::parseInt(ExecState* exec, StringView s, ErrorParseMode parserMode)
 {
     if (s.is8Bit())
-        return parseInt(state, s.characters8(), s.length(), parserMode);
-    return parseInt(state, s.characters16(), s.length(), parserMode);
+        return parseInt(exec, s.characters8(), s.length(), parserMode);
+    return parseInt(exec, s.characters16(), s.length(), parserMode);
 }
 
-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign)
+JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign)
 {
     if (s.is8Bit())
-        return parseInt(state, vm, s.characters8(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
-    return parseInt(state, vm, s.characters16(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
+        return parseInt(exec, vm, s.characters8(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
+    return parseInt(exec, vm, s.characters16(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
 }
 
-JSBigInt* JSBigInt::stringToBigInt(ExecState* state, StringView s)
+JSBigInt* JSBigInt::stringToBigInt(ExecState* exec, StringView s)
 {
-    return parseInt(state, s, ErrorParseMode::IgnoreExceptions);
+    return parseInt(exec, s, ErrorParseMode::IgnoreExceptions);
 }
 
-String JSBigInt::toString(ExecState* state, unsigned radix)
+String JSBigInt::toString(ExecState* exec, unsigned radix)
 {
     if (this->isZero())
-        return state->vm().smallStrings.singleCharacterStringRep('0');
+        return exec->vm().smallStrings.singleCharacterStringRep('0');
 
-    return toStringGeneric(state, this, radix);
+    return toStringGeneric(exec, this, radix);
 }
 
 inline bool JSBigInt::isZero()
@@ -237,9 +237,9 @@ inline void JSBigInt::inplaceMultiplyAdd(uintptr_t factor, uintptr_t summand)
     internalMultiplyAdd(this, factor, summand, length(), this);
 }
 
-JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
 
     if (x->isZero())
         return x;
@@ -257,14 +257,14 @@ JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y)
     return result->rightTrim(vm);
 }
 
-JSBigInt* JSBigInt::divide(ExecState* state, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::divide(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
     // 1. If y is 0n, throw a RangeError exception.
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (y->isZero()) {
-        throwRangeError(state, scope, ASCIILiteral("0 is an invalid divisor value."));
+        throwRangeError(exec, scope, ASCIILiteral("0 is an invalid divisor value."));
         return nullptr;
     }
 
@@ -310,14 +310,14 @@ JSBigInt* JSBigInt::unaryMinus(VM& vm, JSBigInt* x)
     return result;
 }
 
-JSBigInt* JSBigInt::remainder(ExecState* state, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::remainder(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
     // 1. If y is 0n, throw a RangeError exception.
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     
     if (y->isZero()) {
-        throwRangeError(state, scope, ASCIILiteral("0 is an invalid divisor value."));
+        throwRangeError(exec, scope, ASCIILiteral("0 is an invalid divisor value."));
         return nullptr;
     }
 
@@ -346,6 +346,40 @@ JSBigInt* JSBigInt::remainder(ExecState* state, JSBigInt* x, JSBigInt* y)
     return remainder->rightTrim(vm);
 }
 
+JSBigInt* JSBigInt::add(VM& vm, JSBigInt* x, JSBigInt* y)
+{
+    bool xSign = x->sign();
+
+    // x + y == x + y
+    // -x + -y == -(x + y)
+    if (xSign == y->sign())
+        return absoluteAdd(vm, x, y, xSign);
+
+    // x + -y == x - y == -(y - x)
+    // -x + y == y - x == -(x - y)
+    ComparisonResult comparisonResult = absoluteCompare(x, y);
+    if (comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal)
+        return absoluteSub(vm, x, y, xSign);
+
+    return absoluteSub(vm, y, x, !xSign);
+}
+
+JSBigInt* JSBigInt::sub(VM& vm, JSBigInt* x, JSBigInt* y)
+{
+    bool xSign = x->sign();
+    if (xSign != y->sign()) {
+        // x - (-y) == x + y
+        // (-x) - y == -(x + y)
+        return absoluteAdd(vm, x, y, xSign);
+    }
+    // x - y == -(y - x)
+    // (-x) - (-y) == y - x == -(x - y)
+    ComparisonResult comparisonResult = absoluteCompare(x, y);
+    if (comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal)
+        return absoluteSub(vm, x, y, xSign);
+
+    return absoluteSub(vm, y, x, !xSign);
+}
 
 #if USE(JSVALUE32_64)
 #define HAVE_TWO_DIGIT 1
@@ -644,6 +678,85 @@ inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigIn
     return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
 }
 
+JSBigInt* JSBigInt::absoluteAdd(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSign)
+{
+    if (x->length() < y->length())
+        return absoluteAdd(vm, y, x, resultSign);
+
+    if (x->isZero()) {
+        ASSERT(y->isZero());
+        return x;
+    }
+
+    if (y->isZero())
+        return resultSign == x->sign() ? x : unaryMinus(vm, x);
+
+    JSBigInt* result = JSBigInt::createWithLength(vm, x->length() + 1);
+    ASSERT(result);
+    Digit carry = 0;
+    unsigned i = 0;
+    for (; i < y->length(); i++) {
+        Digit newCarry = 0;
+        Digit sum = digitAdd(x->digit(i), y->digit(i), newCarry);
+        sum = digitAdd(sum, carry, newCarry);
+        result->setDigit(i, sum);
+        carry = newCarry;
+    }
+
+    for (; i < x->length(); i++) {
+        Digit newCarry = 0;
+        Digit sum = digitAdd(x->digit(i), carry, newCarry);
+        result->setDigit(i, sum);
+        carry = newCarry;
+    }
+
+    result->setDigit(i, carry);
+    result->setSign(resultSign);
+
+    return result->rightTrim(vm);
+}
+
+JSBigInt* JSBigInt::absoluteSub(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSign)
+{
+    ComparisonResult comparisonResult = absoluteCompare(x, y);
+    ASSERT(x->length() >= y->length());
+    ASSERT(comparisonResult == ComparisonResult::GreaterThan || comparisonResult == ComparisonResult::Equal);
+
+    if (x->isZero()) {
+        ASSERT(y->isZero());
+        return x;
+    }
+
+    if (y->isZero())
+        return resultSign == x->sign() ? x : unaryMinus(vm, x);
+
+    if (comparisonResult == ComparisonResult::Equal)
+        return JSBigInt::createZero(vm);
+
+    JSBigInt* result = JSBigInt::createWithLength(vm, x->length());
+    Digit borrow = 0;
+    unsigned i = 0;
+    for (; i < y->length(); i++) {
+        Digit newBorrow = 0;
+        Digit difference = digitSub(x->digit(i), y->digit(i), newBorrow);
+        difference = digitSub(difference, borrow, newBorrow);
+        result->setDigit(i, difference);
+        borrow = newBorrow;
+    }
+
+    for (; i < x->length(); i++) {
+        Digit newBorrow = 0;
+        Digit difference = digitSub(x->digit(i), borrow, newBorrow);
+        result->setDigit(i, difference);
+        borrow = newBorrow;
+    }
+
+    ASSERT(!borrow);
+    result->setSign(resultSign);
+    result->rightTrim(vm);
+    return result;
+}
+
 // Divides {x} by {divisor}, returning the result in {quotient} and {remainder}.
 // Mathematically, the contract is:
 // quotient = (x - remainder) / divisor, with 0 <= remainder < divisor.
@@ -928,13 +1041,13 @@ uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned
     return maximumCharactersRequired;
 }
 
-String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix)
+String JSBigInt::toStringGeneric(ExecState* exec, JSBigInt* x, unsigned radix)
 {
     // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString
     // https://bugs.webkit.org/show_bug.cgi?id=18067
     Vector<LChar> resultString;
 
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
 
     ASSERT(radix >= 2 && radix <= 36);
     ASSERT(!x->isZero());
@@ -947,7 +1060,7 @@ String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix)
 
     if (maximumCharactersRequired > JSString::MaxLength) {
         auto scope = DECLARE_THROW_SCOPE(vm);
-        throwOutOfMemoryError(state, scope);
+        throwOutOfMemoryError(exec, scope);
         return String();
     }
 
@@ -1042,7 +1155,7 @@ JSBigInt* JSBigInt::rightTrim(VM& vm)
     return trimmedBigInt;
 }
 
-JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount)
+JSBigInt* JSBigInt::allocateFor(ExecState* exec, VM& vm, unsigned radix, unsigned charcount)
 {
     ASSERT(2 <= radix && radix <= 36);
 
@@ -1064,9 +1177,9 @@ JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsign
         }
     }
 
-    if (state) {
+    if (exec) {
         auto scope = DECLARE_THROW_SCOPE(vm);
-        throwOutOfMemoryError(state, scope);
+        throwOutOfMemoryError(exec, scope);
     }
     return nullptr;
 }
@@ -1076,18 +1189,18 @@ size_t JSBigInt::estimatedSize(JSCell* cell)
     return Base::estimatedSize(cell) + jsCast<JSBigInt*>(cell)->m_length * sizeof(Digit);
 }
 
-double JSBigInt::toNumber(ExecState* state) const
+double JSBigInt::toNumber(ExecState* exec) const
 {
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    throwTypeError(state, scope, ASCIILiteral("Conversion from 'BigInt' to 'number' is not allowed."));
+    throwTypeError(exec, scope, ASCIILiteral("Conversion from 'BigInt' to 'number' is not allowed."));
     return 0.0;
 }
 
-bool JSBigInt::getPrimitiveNumber(ExecState* state, double& number, JSValue& result) const
+bool JSBigInt::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
 {
     result = this;
-    number = toNumber(state);
+    number = toNumber(exec);
     return true;
 }
 
@@ -1097,9 +1210,9 @@ inline size_t JSBigInt::offsetOfData()
 }
 
 template <typename CharType>
-JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length, ErrorParseMode errorParseMode)
+JSBigInt* JSBigInt::parseInt(ExecState* exec, CharType*  data, unsigned length, ErrorParseMode errorParseMode)
 {
-    VM& vm = state->vm();
+    VM& vm = exec->vm();
 
     unsigned p = 0;
     while (p < length && isStrWhiteSpace(data[p]))
@@ -1108,13 +1221,13 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length,
     // Check Radix from frist characters
     if (static_cast<unsigned>(p) + 1 < static_cast<unsigned>(length) && data[p] == '0') {
         if (isASCIIAlphaCaselessEqual(data[p + 1], 'b'))
-            return parseInt(state, vm, data, length, p + 2, 2, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
+            return parseInt(exec, vm, data, length, p + 2, 2, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
         
         if (isASCIIAlphaCaselessEqual(data[p + 1], 'x'))
-            return parseInt(state, vm, data, length, p + 2, 16, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
+            return parseInt(exec, vm, data, length, p + 2, 16, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
         
         if (isASCIIAlphaCaselessEqual(data[p + 1], 'o'))
-            return parseInt(state, vm, data, length, p + 2, 8, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
+            return parseInt(exec, vm, data, length, p + 2, 8, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
     }
 
     ParseIntSign sign = ParseIntSign::Unsigned;
@@ -1127,7 +1240,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length,
         }
     }
 
-    JSBigInt* result = parseInt(state, vm, data, length, p, 10, errorParseMode, sign);
+    JSBigInt* result = parseInt(exec, vm, data, length, p, 10, errorParseMode, sign);
 
     if (result && !result->isZero())
         result->setSign(sign == ParseIntSign::Signed);
@@ -1136,7 +1249,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length,
 }
 
 template <typename CharType>
-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode)
+JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode)
 {
     ASSERT(length >= 0);
     unsigned p = startIndex;
@@ -1144,9 +1257,9 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned
     auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (parseMode != ParseIntMode::AllowEmptyString && startIndex == length) {
-        ASSERT(state);
+        ASSERT(exec);
         if (errorParseMode == ErrorParseMode::ThrowExceptions)
-            throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt"));
+            throwVMError(exec, scope, createSyntaxError(exec, "Failed to parse String to BigInt"));
         return nullptr;
     }
 
@@ -1168,7 +1281,7 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned
     unsigned limita = 'a' + (radix - 10);
     unsigned limitA = 'A' + (radix - 10);
 
-    JSBigInt* result = allocateFor(state, vm, radix, length - p);
+    JSBigInt* result = allocateFor(exec, vm, radix, length - p);
     RETURN_IF_EXCEPTION(scope, nullptr);
 
     result->initialize(InitializationType::WithZero);
@@ -1191,9 +1304,9 @@ JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned
     if (p == length)
         return result->rightTrim(vm);
 
-    ASSERT(state);
+    ASSERT(exec);
     if (errorParseMode == ErrorParseMode::ThrowExceptions)
-        throwVMError(state, scope, createSyntaxError(state, "Failed to parse String to BigInt"));
+        throwVMError(exec, scope, createSyntaxError(exec, "Failed to parse String to BigInt"));
 
     return nullptr;
 }
index fba5a6d..4af7a5f 100644 (file)
@@ -107,6 +107,8 @@ public:
     
     ComparisonResult static compareToDouble(JSBigInt* x, double y);
 
+    static JSBigInt* add(VM&, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* sub(VM&, JSBigInt* x, JSBigInt* y);
     static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* unaryMinus(VM&, JSBigInt* x);
@@ -169,6 +171,8 @@ private:
     JSBigInt* rightTrim(VM&);
 
     void inplaceMultiplyAdd(Digit multiplier, Digit part);
+    static JSBigInt* absoluteAdd(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
+    static JSBigInt* absoluteSub(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
     
     static size_t allocationSize(unsigned length);
     static size_t offsetOfData();
index f9dc308..4ba9d50 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "CatchScope.h"
 #include "Error.h"
 #include "ExceptionHelpers.h"
 #include "Identifier.h"
index c11d905..03856fa 100644 (file)
@@ -23,6 +23,7 @@
 #include "Operations.h"
 
 #include "Error.h"
+#include "JSBigInt.h"
 #include "JSCInlines.h"
 #include "JSObject.h"
 #include "JSString.h"
@@ -64,10 +65,19 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2)
         return jsString(callFrame, p1String, asString(p2));
     }
 
-    double p1Number = p1.toNumber(callFrame);
+    auto leftNumeric = p1.toNumeric(callFrame);
     RETURN_IF_EXCEPTION(scope, { });
-    scope.release();
-    return jsNumber(p1Number + p2.toNumber(callFrame));
+    auto rightNumeric = p2.toNumeric(callFrame);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
+            return JSBigInt::add(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+
+        return throwTypeError(callFrame, scope, ASCIILiteral("Invalid mix of BigInt and other type in addition."));
+    }
+
+    return jsNumber(WTF::get<double>(leftNumeric) + WTF::get<double>(rightNumeric));
 }
 
 JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v)
index f95b9d0..2647c97 100644 (file)
@@ -348,6 +348,26 @@ ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
     return jsAddSlowCase(callFrame, v1, v2);
 }
 
+ALWAYS_INLINE JSValue jsSub(ExecState* state, JSValue v1, JSValue v2)
+{
+    VM& vm = state->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto leftNumeric = v1.toNumeric(state);
+    RETURN_IF_EXCEPTION(scope, { });
+    auto rightNumeric = v2.toNumeric(state);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
+            return JSBigInt::sub(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+
+        return throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in subtraction."));
+    }
+
+    return jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric));
+}
+
 ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
 {
     VM& vm = state->vm();