[ESNext][BigInt] Implement support for "%" operation
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2018 16:40:17 +0000 (16:40 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2018 16:40:17 +0000 (16:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184327

Reviewed by Yusuke Suzuki.

JSTests:

* bigIntTests.yaml:
* stress/big-int-mod-memory-stress.js: Added.
* stress/big-int-mod-to-primitive-precedence.js: Added.
* stress/big-int-mod-to-primitive.js: Added.
* stress/big-int-mod-type-error.js: Added.
* stress/big-int-mod-wrapped-value.js: Added.
* stress/big-int-mod.js: Added.

Source/JavaScriptCore:

We are introducing the support of BigInt into remainder (a.k.a mod)
operation.

* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::remainder):
(JSC::JSBigInt::rightTrim):
* runtime/JSBigInt.h:

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

13 files changed:
JSTests/ChangeLog
JSTests/bigIntTests.yaml
JSTests/stress/big-int-mod-jit.js [new file with mode: 0644]
JSTests/stress/big-int-mod-memory-stress.js [new file with mode: 0644]
JSTests/stress/big-int-mod-to-primitive-precedence.js [new file with mode: 0644]
JSTests/stress/big-int-mod-to-primitive.js [new file with mode: 0644]
JSTests/stress/big-int-mod-type-error.js [new file with mode: 0644]
JSTests/stress/big-int-mod-wrapped-value.js [new file with mode: 0644]
JSTests/stress/big-int-mod.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/JSBigInt.cpp
Source/JavaScriptCore/runtime/JSBigInt.h

index a68fd29..56d63ef 100644 (file)
@@ -1,3 +1,18 @@
+2018-05-30  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "%" operation
+        https://bugs.webkit.org/show_bug.cgi?id=184327
+
+        Reviewed by Yusuke Suzuki.
+
+        * bigIntTests.yaml:
+        * stress/big-int-mod-memory-stress.js: Added.
+        * stress/big-int-mod-to-primitive-precedence.js: Added.
+        * stress/big-int-mod-to-primitive.js: Added.
+        * stress/big-int-mod-type-error.js: Added.
+        * stress/big-int-mod-wrapped-value.js: Added.
+        * stress/big-int-mod.js: Added.
+
 2018-05-29  Caitlin Potter  <caitp@igalia.com>
 
         [JSTests] update test262 expectations after r232261
index 1b05d69..cafa96a 100644 (file)
 
 - path: stress/big-int-no-conversion-to-number.js
   cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-memory-stress.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-to-primitive-precedence.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-to-primitive.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-type-error.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-wrapped-value.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-div-to-primitive-precedence.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mod-jit.js
+  cmd: runBigIntEnabled
+
diff --git a/JSTests/stress/big-int-mod-jit.js b/JSTests/stress/big-int-mod-jit.js
new file mode 100644 (file)
index 0000000..81c5da7
--- /dev/null
@@ -0,0 +1,33 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntMod(x, y) {
+    return x % y;
+}
+noInline(bigIntMod);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntMod(30n, 10n);
+    assert.sameValue(r, 0n, 30n + " % " + 10n + " = " + r);
+}
+
+function bigIntModFolding(x, y) {
+    let r = x % y;
+    return -r;
+}
+noInline(bigIntModFolding);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntModFolding(10, 30);
+    assert.sameValue(r, -10, "-(" + 10 + " % " + 30 + ") = " + r);
+}
+
+let r = bigIntModFolding(10n, 30n);
+assert.sameValue(r, -10n, "-(" + 10n + " % " + 30n + ") = " + r);
+
diff --git a/JSTests/stress/big-int-mod-memory-stress.js b/JSTests/stress/big-int-mod-memory-stress.js
new file mode 100644 (file)
index 0000000..9b67d71
--- /dev/null
@@ -0,0 +1,15 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+let a = 0n;
+let b = 30n;
+for (let i = 0; i < 1000000; i++) {
+    a = b % 2n;
+}
+
+assert(a === 0n);
+
diff --git a/JSTests/stress/big-int-mod-to-primitive-precedence.js b/JSTests/stress/big-int-mod-to-primitive-precedence.js
new file mode 100644 (file)
index 0000000..9a36a62
--- /dev/null
@@ -0,0 +1,38 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testMod(x, y, z, message) {
+    assert.sameValue(x % y, z, message);
+}
+
+testMod(Object(33n), 10n, 3n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 33n;
+    },
+    valueOf: function () {
+        throw new Error("Should never execute it");
+    },
+    toString: function () {
+        throw new Error("Should never execute it");
+    }
+};
+testMod(o, 10n, 3n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 33n;
+    },
+    toString: function () {
+        throw new Error("Should never execute it");
+    }
+};
+testMod(o, 10n, 3n, "ToPrimitive: valueOf");
+
diff --git a/JSTests/stress/big-int-mod-to-primitive.js b/JSTests/stress/big-int-mod-to-primitive.js
new file mode 100644 (file)
index 0000000..95d36f3
--- /dev/null
@@ -0,0 +1,34 @@
+//@ 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 testMod(x, y, z) {
+    assert.sameValue(x % y, z, x + " % " + y + " = " + z);
+}
+
+let o = {
+    [Symbol.toPrimitive]: function () { return 3000n; }
+}
+
+testMod(500000000000438n, o, 2438n);
+
+o.valueOf = function () {
+    throw new Error("Should never execute it");
+};
+
+testMod(700000000000438n, o, 1438n);
+
+o.toString = function () {
+    throw new Error("Should never execute it");
+};
+
+testMod(700000000000438n, o, 1438n);
+
diff --git a/JSTests/stress/big-int-mod-type-error.js b/JSTests/stress/big-int-mod-type-error.js
new file mode 100644 (file)
index 0000000..75079cc
--- /dev/null
@@ -0,0 +1,117 @@
+//@ 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, "foo", "BigInt % String");
+assertThrowTypeError("bar", 18757382984821n, "String % BigInt");
+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");
+
+o = {
+    [Symbol.toPrimitive]: function () { throw new Error("Bad"); }
+};
+
+assertThrowTypeError(Symbol("30"), o, "Symbol % object should result in TypeError");
+try {
+    o % Symbol("30");
+} catch (e) {
+    assert(e.message === "Bad", "Erro message expected is 'Bad'");
+}
+
diff --git a/JSTests/stress/big-int-mod-wrapped-value.js b/JSTests/stress/big-int-mod-wrapped-value.js
new file mode 100644 (file)
index 0000000..849194b
--- /dev/null
@@ -0,0 +1,36 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testDiv(x, y, z, message) {
+    assert.sameValue(x % y, z, message);
+}
+
+testDiv(Object(33n), 10n, 3n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 33n;
+    }
+};
+testDiv(o, 10n, 3n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 33n;
+    }
+};
+testDiv(o, 10n, 3n, "ToPrimitive: valueOf");
+
+o = {
+    toString: function() {
+        return 33n;
+    }
+}
+testDiv(o, 10n, 3n, "ToPrimitive: toString");
+
diff --git a/JSTests/stress/big-int-mod.js b/JSTests/stress/big-int-mod.js
new file mode 100644 (file)
index 0000000..fc9c724
--- /dev/null
@@ -0,0 +1,276 @@
+//@ runBigIntEnabled
+
+// Copyright (C) 2017 Robin Templeton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+assert.sameValue = function (input, expected, message) {
+    if (input !== expected)
+        throw new Error(message);
+}
+
+function testMod(x, y, z) {
+    assert.sameValue(x % y, z, x + " % " + y + " = " + z);
+}
+
+testMod(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0x0n);
+testMod(0xFEDCBA9876543210n, 0xFEDCBA987654320Fn, 0x1n);
+testMod(0xFEDCBA9876543210n, 0xFEDCBA98n, 0x76543210n);
+testMod(0xFEDCBA9876543210n, 0xFEDCBA97n, 0x77777779n);
+testMod(0xFEDCBA9876543210n, 0x1234n, 0x960n);
+testMod(0xFEDCBA9876543210n, 0x3n, 0x0n);
+testMod(0xFEDCBA9876543210n, 0x2n, 0x0n);
+testMod(0xFEDCBA9876543210n, 0x1n, 0x0n);
+testMod(0xFEDCBA9876543210n, BigInt("-1"), 0x0n);
+testMod(0xFEDCBA9876543210n, BigInt("-2"), 0x0n);
+testMod(0xFEDCBA9876543210n, BigInt("-3"), 0x0n);
+testMod(0xFEDCBA9876543210n, BigInt("-4660"), 0x960n);
+testMod(0xFEDCBA9876543210n, BigInt("-4275878551"), 0x77777779n);
+testMod(0xFEDCBA9876543210n, BigInt("-4275878552"), 0x76543210n);
+testMod(0xFEDCBA9876543210n, BigInt("-18364758544493064719"), 0x1n);
+testMod(0xFEDCBA987654320Fn, 0xFEDCBA9876543210n, 0xFEDCBA987654320Fn);
+testMod(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0x0n);
+testMod(0xFEDCBA987654320Fn, 0xFEDCBA98n, 0x7654320Fn);
+testMod(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0x77777778n);
+testMod(0xFEDCBA987654320Fn, 0x1234n, 0x95Fn);
+testMod(0xFEDCBA987654320Fn, 0x3n, 0x2n);
+testMod(0xFEDCBA987654320Fn, 0x2n, 0x1n);
+testMod(0xFEDCBA987654320Fn, 0x1n, 0x0n);
+testMod(0xFEDCBA987654320Fn, BigInt("-1"), 0x0n);
+testMod(0xFEDCBA987654320Fn, BigInt("-3"), 0x2n);
+testMod(0xFEDCBA987654320Fn, BigInt("-4660"), 0x95Fn);
+testMod(0xFEDCBA987654320Fn, BigInt("-4275878551"), 0x77777778n);
+testMod(0xFEDCBA987654320Fn, BigInt("-18364758544493064720"), 0xFEDCBA987654320Fn);
+testMod(0xFEDCBA98n, 0xFEDCBA9876543210n, 0xFEDCBA98n);
+testMod(0xFEDCBA98n, 0xFEDCBA987654320Fn, 0xFEDCBA98n);
+testMod(0xFEDCBA98n, 0xFEDCBA98n, 0x0n);
+testMod(0xFEDCBA98n, 0xFEDCBA97n, 0x1n);
+testMod(0xFEDCBA98n, 0x1234n, 0x930n);
+testMod(0xFEDCBA98n, 0x3n, 0x2n);
+testMod(0xFEDCBA98n, 0x2n, 0x0n);
+testMod(0xFEDCBA98n, 0x1n, 0x0n);
+testMod(0xFEDCBA98n, BigInt("-1"), 0x0n);
+testMod(0xFEDCBA98n, BigInt("-2"), 0x0n);
+testMod(0xFEDCBA98n, BigInt("-3"), 0x2n);
+testMod(0xFEDCBA98n, BigInt("-4660"), 0x930n);
+testMod(0xFEDCBA98n, BigInt("-4275878551"), 0x1n);
+testMod(0xFEDCBA98n, BigInt("-4275878552"), 0x0n);
+testMod(0xFEDCBA98n, BigInt("-18364758544493064719"), 0xFEDCBA98n);
+testMod(0xFEDCBA98n, BigInt("-18364758544493064720"), 0xFEDCBA98n);
+testMod(0xFEDCBA97n, 0xFEDCBA9876543210n, 0xFEDCBA97n);
+testMod(0xFEDCBA97n, 0xFEDCBA987654320Fn, 0xFEDCBA97n);
+testMod(0xFEDCBA97n, 0xFEDCBA98n, 0xFEDCBA97n);
+testMod(0xFEDCBA97n, 0xFEDCBA97n, 0x0n);
+testMod(0xFEDCBA97n, 0x1234n, 0x92Fn);
+testMod(0xFEDCBA97n, 0x3n, 0x1n);
+testMod(0xFEDCBA97n, 0x2n, 0x1n);
+testMod(0xFEDCBA97n, 0x1n, 0x0n);
+testMod(0xFEDCBA97n, BigInt("-1"), 0x0n);
+testMod(0xFEDCBA97n, BigInt("-2"), 0x1n);
+testMod(0xFEDCBA97n, BigInt("-3"), 0x1n);
+testMod(0xFEDCBA97n, BigInt("-4660"), 0x92Fn);
+testMod(0xFEDCBA97n, BigInt("-4275878551"), 0x0n);
+testMod(0xFEDCBA97n, BigInt("-4275878552"), 0xFEDCBA97n);
+testMod(0xFEDCBA97n, BigInt("-18364758544493064719"), 0xFEDCBA97n);
+testMod(0xFEDCBA97n, BigInt("-18364758544493064720"), 0xFEDCBA97n);
+testMod(0x1234n, 0xFEDCBA9876543210n, 0x1234n);
+testMod(0x1234n, 0xFEDCBA987654320Fn, 0x1234n);
+testMod(0x1234n, 0xFEDCBA98n, 0x1234n);
+testMod(0x1234n, 0xFEDCBA97n, 0x1234n);
+testMod(0x1234n, 0x1234n, 0x0n);
+testMod(0x1234n, 0x3n, 0x1n);
+testMod(0x1234n, 0x2n, 0x0n);
+testMod(0x1234n, 0x1n, 0x0n);
+testMod(0x1234n, BigInt("-1"), 0x0n);
+testMod(0x1234n, BigInt("-2"), 0x0n);
+testMod(0x1234n, BigInt("-3"), 0x1n);
+testMod(0x1234n, BigInt("-4660"), 0x0n);
+testMod(0x1234n, BigInt("-4275878551"), 0x1234n);
+testMod(0x1234n, BigInt("-4275878552"), 0x1234n);
+testMod(0x1234n, BigInt("-18364758544493064719"), 0x1234n);
+testMod(0x1234n, BigInt("-18364758544493064720"), 0x1234n);
+testMod(0x3n, 0xFEDCBA9876543210n, 0x3n);
+testMod(0x3n, 0xFEDCBA987654320Fn, 0x3n);
+testMod(0x3n, 0xFEDCBA98n, 0x3n);
+testMod(0x3n, 0xFEDCBA97n, 0x3n);
+testMod(0x3n, 0x1234n, 0x3n);
+testMod(0x3n, 0x3n, 0x0n);
+testMod(0x3n, 0x2n, 0x1n);
+testMod(0x3n, 0x1n, 0x0n);
+testMod(0x3n, BigInt("-1"), 0x0n);
+testMod(0x3n, BigInt("-2"), 0x1n);
+testMod(0x3n, BigInt("-3"), 0x0n);
+testMod(0x3n, BigInt("-4660"), 0x3n);
+testMod(0x3n, BigInt("-4275878551"), 0x3n);
+testMod(0x3n, BigInt("-4275878552"), 0x3n);
+testMod(0x3n, BigInt("-18364758544493064719"), 0x3n);
+testMod(0x3n, BigInt("-18364758544493064720"), 0x3n);
+testMod(0x2n, 0xFEDCBA9876543210n, 0x2n);
+testMod(0x2n, 0xFEDCBA987654320Fn, 0x2n);
+testMod(0x2n, 0xFEDCBA98n, 0x2n);
+testMod(0x2n, 0xFEDCBA97n, 0x2n);
+testMod(0x2n, 0x1234n, 0x2n);
+testMod(0x2n, 0x3n, 0x2n);
+testMod(0x2n, 0x2n, 0x0n);
+testMod(0x2n, 0x1n, 0x0n);
+testMod(0x2n, BigInt("-1"), 0x0n);
+testMod(0x2n, BigInt("-2"), 0x0n);
+testMod(0x2n, BigInt("-3"), 0x2n);
+testMod(0x2n, BigInt("-4660"), 0x2n);
+testMod(0x2n, BigInt("-4275878551"), 0x2n);
+testMod(0x2n, BigInt("-4275878552"), 0x2n);
+testMod(0x2n, BigInt("-18364758544493064719"), 0x2n);
+testMod(0x2n, BigInt("-18364758544493064720"), 0x2n);
+testMod(0x1n, 0xFEDCBA9876543210n, 0x1n);
+testMod(0x1n, 0xFEDCBA987654320Fn, 0x1n);
+testMod(0x1n, 0xFEDCBA98n, 0x1n);
+testMod(0x1n, 0xFEDCBA97n, 0x1n);
+testMod(0x1n, 0x1234n, 0x1n);
+testMod(0x1n, 0x3n, 0x1n);
+testMod(0x1n, 0x2n, 0x1n);
+testMod(0x1n, 0x1n, 0x0n);
+testMod(0x1n, BigInt("-1"), 0x0n);
+testMod(0x1n, BigInt("-2"), 0x1n);
+testMod(0x1n, BigInt("-3"), 0x1n);
+testMod(0x1n, BigInt("-4660"), 0x1n);
+testMod(0x1n, BigInt("-4275878551"), 0x1n);
+testMod(0x1n, BigInt("-4275878552"), 0x1n);
+testMod(0x1n, BigInt("-18364758544493064719"), 0x1n);
+testMod(0x1n, BigInt("-18364758544493064720"), 0x1n);
+testMod(BigInt("-1"), 0xFEDCBA9876543210n, BigInt("-1"));
+testMod(BigInt("-1"), 0xFEDCBA987654320Fn, BigInt("-1"));
+testMod(BigInt("-1"), 0xFEDCBA98n, BigInt("-1"));
+testMod(BigInt("-1"), 0xFEDCBA97n, BigInt("-1"));
+testMod(BigInt("-1"), 0x1234n, BigInt("-1"));
+testMod(BigInt("-1"), 0x3n, BigInt("-1"));
+testMod(BigInt("-1"), 0x2n, BigInt("-1"));
+testMod(BigInt("-1"), 0x1n, 0x0n);
+testMod(BigInt("-1"), BigInt("-1"), 0x0n);
+testMod(BigInt("-1"), BigInt("-2"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-3"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-4660"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-4275878551"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-4275878552"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-18364758544493064719"), BigInt("-1"));
+testMod(BigInt("-1"), BigInt("-18364758544493064720"), BigInt("-1"));
+testMod(BigInt("-2"), 0xFEDCBA9876543210n, BigInt("-2"));
+testMod(BigInt("-2"), 0xFEDCBA987654320Fn, BigInt("-2"));
+testMod(BigInt("-2"), 0xFEDCBA98n, BigInt("-2"));
+testMod(BigInt("-2"), 0xFEDCBA97n, BigInt("-2"));
+testMod(BigInt("-2"), 0x1234n, BigInt("-2"));
+testMod(BigInt("-2"), 0x3n, BigInt("-2"));
+testMod(BigInt("-2"), 0x2n, 0x0n);
+testMod(BigInt("-2"), 0x1n, 0x0n);
+testMod(BigInt("-2"), BigInt("-1"), 0x0n);
+testMod(BigInt("-2"), BigInt("-2"), 0x0n);
+testMod(BigInt("-2"), BigInt("-3"), BigInt("-2"));
+testMod(BigInt("-2"), BigInt("-4660"), BigInt("-2"));
+testMod(BigInt("-2"), BigInt("-4275878551"), BigInt("-2"));
+testMod(BigInt("-2"), BigInt("-4275878552"), BigInt("-2"));
+testMod(BigInt("-2"), BigInt("-18364758544493064719"), BigInt("-2"));
+testMod(BigInt("-2"), BigInt("-18364758544493064720"), BigInt("-2"));
+testMod(BigInt("-3"), 0xFEDCBA9876543210n, BigInt("-3"));
+testMod(BigInt("-3"), 0xFEDCBA987654320Fn, BigInt("-3"));
+testMod(BigInt("-3"), 0xFEDCBA98n, BigInt("-3"));
+testMod(BigInt("-3"), 0xFEDCBA97n, BigInt("-3"));
+testMod(BigInt("-3"), 0x1234n, BigInt("-3"));
+testMod(BigInt("-3"), 0x3n, 0x0n);
+testMod(BigInt("-3"), 0x2n, BigInt("-1"));
+testMod(BigInt("-3"), 0x1n, 0x0n);
+testMod(BigInt("-3"), BigInt("-1"), 0x0n);
+testMod(BigInt("-3"), BigInt("-2"), BigInt("-1"));
+testMod(BigInt("-3"), BigInt("-3"), 0x0n);
+testMod(BigInt("-3"), BigInt("-4660"), BigInt("-3"));
+testMod(BigInt("-3"), BigInt("-4275878551"), BigInt("-3"));
+testMod(BigInt("-3"), BigInt("-4275878552"), BigInt("-3"));
+testMod(BigInt("-3"), BigInt("-18364758544493064719"), BigInt("-3"));
+testMod(BigInt("-3"), BigInt("-18364758544493064720"), BigInt("-3"));
+testMod(BigInt("-4660"), 0xFEDCBA9876543210n, BigInt("-4660"));
+testMod(BigInt("-4660"), 0xFEDCBA987654320Fn, BigInt("-4660"));
+testMod(BigInt("-4660"), 0xFEDCBA98n, BigInt("-4660"));
+testMod(BigInt("-4660"), 0xFEDCBA97n, BigInt("-4660"));
+testMod(BigInt("-4660"), 0x1234n, 0x0n);
+testMod(BigInt("-4660"), 0x3n, BigInt("-1"));
+testMod(BigInt("-4660"), 0x2n, 0x0n);
+testMod(BigInt("-4660"), 0x1n, 0x0n);
+testMod(BigInt("-4660"), BigInt("-1"), 0x0n);
+testMod(BigInt("-4660"), BigInt("-2"), 0x0n);
+testMod(BigInt("-4660"), BigInt("-3"), BigInt("-1"));
+testMod(BigInt("-4660"), BigInt("-4660"), 0x0n);
+testMod(BigInt("-4660"), BigInt("-4275878551"), BigInt("-4660"));
+testMod(BigInt("-4660"), BigInt("-4275878552"), BigInt("-4660"));
+testMod(BigInt("-4660"), BigInt("-18364758544493064719"), BigInt("-4660"));
+testMod(BigInt("-4660"), BigInt("-18364758544493064720"), BigInt("-4660"));
+testMod(BigInt("-4275878551"), 0xFEDCBA9876543210n, BigInt("-4275878551"));
+testMod(BigInt("-4275878551"), 0xFEDCBA987654320Fn, BigInt("-4275878551"));
+testMod(BigInt("-4275878551"), 0xFEDCBA98n, BigInt("-4275878551"));
+testMod(BigInt("-4275878551"), 0xFEDCBA97n, 0x0n);
+testMod(BigInt("-4275878551"), 0x1234n, BigInt("-2351"));
+testMod(BigInt("-4275878551"), 0x3n, BigInt("-1"));
+testMod(BigInt("-4275878551"), 0x2n, BigInt("-1"));
+testMod(BigInt("-4275878551"), 0x1n, 0x0n);
+testMod(BigInt("-4275878551"), BigInt("-1"), 0x0n);
+testMod(BigInt("-4275878551"), BigInt("-2"), BigInt("-1"));
+testMod(BigInt("-4275878551"), BigInt("-3"), BigInt("-1"));
+testMod(BigInt("-4275878551"), BigInt("-4660"), BigInt("-2351"));
+testMod(BigInt("-4275878551"), BigInt("-4275878551"), 0x0n);
+testMod(BigInt("-4275878551"), BigInt("-4275878552"), BigInt("-4275878551"));
+testMod(BigInt("-4275878551"), BigInt("-18364758544493064719"), BigInt("-4275878551"));
+testMod(BigInt("-4275878551"), BigInt("-18364758544493064720"), BigInt("-4275878551"));
+testMod(BigInt("-4275878552"), 0xFEDCBA9876543210n, BigInt("-4275878552"));
+testMod(BigInt("-4275878552"), 0xFEDCBA987654320Fn, BigInt("-4275878552"));
+testMod(BigInt("-4275878552"), 0xFEDCBA98n, 0x0n);
+testMod(BigInt("-4275878552"), 0xFEDCBA97n, BigInt("-1"));
+testMod(BigInt("-4275878552"), 0x1234n, BigInt("-2352"));
+testMod(BigInt("-4275878552"), 0x3n, BigInt("-2"));
+testMod(BigInt("-4275878552"), 0x2n, 0x0n);
+testMod(BigInt("-4275878552"), 0x1n, 0x0n);
+testMod(BigInt("-4275878552"), BigInt("-1"), 0x0n);
+testMod(BigInt("-4275878552"), BigInt("-2"), 0x0n);
+testMod(BigInt("-4275878552"), BigInt("-3"), BigInt("-2"));
+testMod(BigInt("-4275878552"), BigInt("-4660"), BigInt("-2352"));
+testMod(BigInt("-4275878552"), BigInt("-4275878551"), BigInt("-1"));
+testMod(BigInt("-4275878552"), BigInt("-4275878552"), 0x0n);
+testMod(BigInt("-4275878552"), BigInt("-18364758544493064719"), BigInt("-4275878552"));
+testMod(BigInt("-4275878552"), BigInt("-18364758544493064720"), BigInt("-4275878552"));
+testMod(BigInt("-18364758544493064719"), 0xFEDCBA9876543210n, BigInt("-18364758544493064719"));
+testMod(BigInt("-18364758544493064719"), 0xFEDCBA987654320Fn, 0x0n);
+testMod(BigInt("-18364758544493064719"), 0xFEDCBA97n, BigInt("-2004318072"));
+testMod(BigInt("-18364758544493064719"), 0x1234n, BigInt("-2399"));
+testMod(BigInt("-18364758544493064719"), 0x3n, BigInt("-2"));
+testMod(BigInt("-18364758544493064719"), 0x2n, BigInt("-1"));
+testMod(BigInt("-18364758544493064719"), 0x1n, 0x0n);
+testMod(BigInt("-18364758544493064719"), BigInt("-1"), 0x0n);
+testMod(BigInt("-18364758544493064719"), BigInt("-2"), BigInt("-1"));
+testMod(BigInt("-18364758544493064719"), BigInt("-3"), BigInt("-2"));
+testMod(BigInt("-18364758544493064719"), BigInt("-4660"), BigInt("-2399"));
+testMod(BigInt("-18364758544493064719"), BigInt("-4275878551"), BigInt("-2004318072"));
+testMod(BigInt("-18364758544493064719"), BigInt("-4275878552"), BigInt("-1985229327"));
+testMod(BigInt("-18364758544493064719"), BigInt("-18364758544493064719"), 0x0n);
+testMod(BigInt("-18364758544493064719"), BigInt("-18364758544493064720"), BigInt("-18364758544493064719"));
+testMod(BigInt("-18364758544493064720"), 0xFEDCBA9876543210n, 0x0n);
+testMod(BigInt("-18364758544493064720"), 0xFEDCBA987654320Fn, BigInt("-1"));
+testMod(BigInt("-18364758544493064720"), 0xFEDCBA98n, BigInt("-1985229328"));
+testMod(BigInt("-18364758544493064720"), 0xFEDCBA97n, BigInt("-2004318073"));
+testMod(BigInt("-18364758544493064720"), 0x1234n, BigInt("-2400"));
+testMod(BigInt("-18364758544493064720"), 0x3n, 0x0n);
+testMod(BigInt("-18364758544493064720"), 0x2n, 0x0n);
+testMod(BigInt("-18364758544493064720"), 0x1n, 0x0n);
+testMod(BigInt("-18364758544493064720"), BigInt("-1"), 0x0n);
+testMod(BigInt("-18364758544493064720"), BigInt("-2"), 0x0n);
+testMod(BigInt("-18364758544493064720"), BigInt("-3"), 0x0n);
+testMod(BigInt("-18364758544493064720"), BigInt("-4660"), BigInt("-2400"));
+testMod(BigInt("-18364758544493064720"), BigInt("-4275878551"), BigInt("-2004318073"));
+testMod(BigInt("-18364758544493064720"), BigInt("-4275878552"), BigInt("-1985229328"));
+testMod(BigInt("-18364758544493064720"), BigInt("-18364758544493064719"), BigInt("-1"));
+testMod(BigInt("-18364758544493064720"), BigInt("-18364758544493064720"), 0x0n);
+
+// Test rightTrim when result is zero, but m_length and m_sign are not canonical
+testMod(340282366920938463463374607431768211456n, 340282366920938463463374607431768211456n, 0n);
+testMod(BigInt("-340282366920938463463374607431768211456"), 340282366920938463463374607431768211456n, 0n);
+testMod(340282366920938463463374607431768211456n, BigInt("-340282366920938463463374607431768211456"), 0n);
+
index b6552fe..98d605c 100644 (file)
@@ -1,3 +1,20 @@
+2018-05-30  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "%" operation
+        https://bugs.webkit.org/show_bug.cgi?id=184327
+
+        Reviewed by Yusuke Suzuki.
+
+        We are introducing the support of BigInt into remainder (a.k.a mod)
+        operation.
+
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::remainder):
+        (JSC::JSBigInt::rightTrim):
+        * runtime/JSBigInt.h:
+
 2018-05-30  Saam Barati  <sbarati@apple.com>
 
         AI for Atomics.load() is too conservative in always clobbering world
index cba4f5f..363ebdf 100644 (file)
@@ -560,10 +560,25 @@ SLOW_PATH_DECL(slow_path_div)
 SLOW_PATH_DECL(slow_path_mod)
 {
     BEGIN();
-    double a = OP_C(2).jsValue().toNumber(exec);
-    if (UNLIKELY(throwScope.exception()))
-        RETURN(JSValue());
-    double b = OP_C(3).jsValue().toNumber(exec);
+    JSValue left = OP_C(2).jsValue();
+    JSValue right = OP_C(3).jsValue();
+    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::remainder(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            CHECK_EXCEPTION();
+            RETURN(result);
+        }
+
+        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in remainder operation."));
+    }
+    
+    double a = WTF::get<double>(leftNumeric);
+    double b = WTF::get<double>(rightNumeric);
     RETURN(jsNumber(jsMod(a, b)));
 }
 
index daf3664..8545233 100644 (file)
@@ -323,6 +323,43 @@ JSBigInt* JSBigInt::unaryMinus(VM& vm, JSBigInt* x)
     return result;
 }
 
+JSBigInt* JSBigInt::remainder(ExecState* state, JSBigInt* x, JSBigInt* y)
+{
+    // 1. If y is 0n, throw a RangeError exception.
+    VM& vm = state->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    
+    if (y->isZero()) {
+        throwRangeError(state, scope, ASCIILiteral("0 is an invalid divisor value."));
+        return nullptr;
+    }
+
+    // 2. Return the JSBigInt representing x modulo y.
+    // See https://github.com/tc39/proposal-bigint/issues/84 though.
+    if (absoluteCompare(x, y) == ComparisonResult::LessThan)
+        return x;
+
+    JSBigInt* remainder;
+    if (y->length() == 1) {
+        Digit divisor = y->digit(0);
+        if (divisor == 1)
+            return createZero(vm);
+
+        Digit remainderDigit;
+        absoluteDivWithDigitDivisor(vm, x, divisor, nullptr, remainderDigit);
+        if (!remainderDigit)
+            return createZero(vm);
+
+        remainder = createWithLength(vm, 1);
+        remainder->setDigit(0, remainderDigit);
+    } else
+        absoluteDivWithBigIntDivisor(vm, x, y, nullptr, &remainder);
+
+    remainder->setSign(x->sign());
+    return remainder->rightTrim(vm);
+}
+
+
 #if USE(JSVALUE32_64)
 #define HAVE_TWO_DIGIT 1
 typedef uint64_t TwoDigit;
@@ -993,14 +1030,19 @@ String JSBigInt::toStringGeneric(ExecState* state, JSBigInt* x, unsigned radix)
 
 JSBigInt* JSBigInt::rightTrim(VM& vm)
 {
-    if (isZero())
+    if (isZero()) {
+        ASSERT(!sign());
         return this;
+    }
 
-    unsigned nonZeroIndex = m_length - 1;
-    while (!digit(nonZeroIndex))
+    int nonZeroIndex = m_length - 1;
+    while (nonZeroIndex >= 0 && !digit(nonZeroIndex))
         nonZeroIndex--;
 
-    if (nonZeroIndex == m_length - 1)
+    if (nonZeroIndex < 0)
+        return createZero(vm);
+
+    if (nonZeroIndex == static_cast<int>(m_length - 1))
         return this;
 
     unsigned newLength = nonZeroIndex + 1;
index ea3b1ac..28e24aa 100644 (file)
@@ -108,6 +108,7 @@ public:
     ComparisonResult static compareToDouble(JSBigInt* x, double y);
 
     static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* unaryMinus(VM&, JSBigInt* x);
     
 private: