[ESNext][BigInt] Implement support for "=<" and ">=" relational operation
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Jun 2018 03:30:22 +0000 (03:30 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Jun 2018 03:30:22 +0000 (03:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185929

Reviewed by Yusuke Suzuki.

JSTests:

* bigIntTests.yaml:
* stress/big-int-greater-than-or-equal-jit.js: Added.
* stress/big-int-greater-than-or-equal-order-of-evaluation.js: Added.
* stress/big-int-greater-than-or-equal-wrapped-values.js: Added.
* stress/big-int-greater-than-or-equal.js: Added.
* stress/big-int-less-than-or-equal-general.js: Added.
* stress/big-int-less-than-or-equal-jit.js: Added.
* stress/big-int-less-than-or-equal-order-of-evaluation.js: Added.
* stress/big-int-less-than-or-equal-wrapped-values.js: Added.

Source/JavaScriptCore:

This patch is introducing support to BigInt operands into ">=" and
"<=" operators.
Here we introduce ```bigIntCompareResult``` that is a helper function
to reuse code between "less than" and "less than or equal" operators.

* runtime/JSBigInt.h:
* runtime/Operations.h:
(JSC::bigIntCompareResult):
(JSC::bigIntCompare):
(JSC::jsLess):
(JSC::jsLessEq):
(JSC::bigIntCompareLess): Deleted.

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

13 files changed:
JSTests/ChangeLog
JSTests/bigIntTests.yaml
JSTests/stress/big-int-greater-than-or-equal-jit.js [new file with mode: 0644]
JSTests/stress/big-int-greater-than-or-equal-order-of-evaluation.js [new file with mode: 0644]
JSTests/stress/big-int-greater-than-or-equal-wrapped-values.js [new file with mode: 0644]
JSTests/stress/big-int-greater-than-or-equal.js [new file with mode: 0644]
JSTests/stress/big-int-less-than-or-equal-general.js [new file with mode: 0644]
JSTests/stress/big-int-less-than-or-equal-jit.js [new file with mode: 0644]
JSTests/stress/big-int-less-than-or-equal-order-of-evaluation.js [new file with mode: 0644]
JSTests/stress/big-int-less-than-or-equal-wrapped-values.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSBigInt.h
Source/JavaScriptCore/runtime/Operations.h

index 4e8d8eb905829050d2d05764b5532ae41dbb11d2..c6f6f12687bb2ecdf6995f63fb48c8b7403540d1 100644 (file)
@@ -1,3 +1,20 @@
+2018-05-31  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "=<" and ">=" relational operation
+        https://bugs.webkit.org/show_bug.cgi?id=185929
+
+        Reviewed by Yusuke Suzuki.
+
+        * bigIntTests.yaml:
+        * stress/big-int-greater-than-or-equal-jit.js: Added.
+        * stress/big-int-greater-than-or-equal-order-of-evaluation.js: Added.
+        * stress/big-int-greater-than-or-equal-wrapped-values.js: Added.
+        * stress/big-int-greater-than-or-equal.js: Added.
+        * stress/big-int-less-than-or-equal-general.js: Added.
+        * stress/big-int-less-than-or-equal-jit.js: Added.
+        * stress/big-int-less-than-or-equal-order-of-evaluation.js: Added.
+        * stress/big-int-less-than-or-equal-wrapped-values.js: Added.
+
 2018-05-31  Saam Barati  <sbarati@apple.com>
 
         Cache toString results for CoW arrays
 2018-05-31  Saam Barati  <sbarati@apple.com>
 
         Cache toString results for CoW arrays
index cafa96ae565e3ba17eed59d43b5a904aac08952a..756e49b5c8abdc1320dfdb2bd6863c583084b17b 100644 (file)
 - path: stress/big-int-no-conversion-to-number.js
   cmd: runBigIntEnabled
 
 - path: stress/big-int-no-conversion-to-number.js
   cmd: runBigIntEnabled
 
+- path: stress/big-int-greater-than-or-equal-general.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-greater-than-or-equal-jit.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-greater-than-or-equal-order-of-evaluation.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-greater-than-or-equal-wrapped-values.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-less-than-or-equal-jit.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-less-than-or-equal-order-of-evaluation.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-less-than-or-equal-wrapped-values.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-less-than-or-equal-general.js
+  cmd: runBigIntEnabled
+
 - path: stress/big-int-mod-memory-stress.js
   cmd: runBigIntEnabled
 
 - path: stress/big-int-mod-memory-stress.js
   cmd: runBigIntEnabled
 
diff --git a/JSTests/stress/big-int-greater-than-or-equal-jit.js b/JSTests/stress/big-int-greater-than-or-equal-jit.js
new file mode 100644 (file)
index 0000000..d37fe51
--- /dev/null
@@ -0,0 +1,24 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+function greaterThanOrEqualTest(a, b) {
+    return a >= b;
+}
+noInline(greaterThanOrEqualTest);
+
+for (let i = 0; i < 100000; i++) {
+    assert(greaterThanOrEqualTest(3n, 4) === false);
+}
+
+for (let i = 0; i < 100000; i++) {
+    assert(greaterThanOrEqualTest(3n, 4n) === false);
+}
+
+for (let i = 0; i < 100000; i++) {
+    assert(greaterThanOrEqualTest(3n, "4") === false);
+}
+
diff --git a/JSTests/stress/big-int-greater-than-or-equal-order-of-evaluation.js b/JSTests/stress/big-int-greater-than-or-equal-order-of-evaluation.js
new file mode 100644 (file)
index 0000000..0e8ac85
--- /dev/null
@@ -0,0 +1,55 @@
+//@ runBigIntEnabled
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        throw new Error("Calling @toPrimitive");
+    }
+}
+
+try {
+    o >= Symbol(2);
+    assert(true, false, "")
+} catch(e) {
+    assert(e.message, "Calling @toPrimitive", "Bad Exception when object is left operand");
+}
+
+try {
+    Symbol(2) >= o;
+    assert(true, false, "")
+} catch(e) {
+    assert(e instanceof TypeError, true, "Bad Exception when Symbol is left operand");
+}
+
+o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    },
+
+    toString: function() {
+        throw new Error("Should never call toString");
+    },
+
+    valueOf: function() {
+        throw new Error("Should never call valueOf");
+    }
+}
+
+assert(o >= 3n, false, "ToPrimitive(2n) > 3n");
+
+o = {
+    toString: function() {
+        throw new Error("Should never call toString");
+    },
+
+    valueOf: function() {
+        return 2n;
+    }
+}
+
+assert(o >= 3n, false, "valueOf(2n) > 3n");
+
diff --git a/JSTests/stress/big-int-greater-than-or-equal-wrapped-values.js b/JSTests/stress/big-int-greater-than-or-equal-wrapped-values.js
new file mode 100644 (file)
index 0000000..597b2cf
--- /dev/null
@@ -0,0 +1,63 @@
+//@ runBigIntEnabled
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+assert(Object(2n) >= 1n, true, "Object(2n) >= 1n");
+assert(1n >= Object(2n), false, "1n >= Object(2n)");
+assert(Object(2n) >= Object(1n), true, "Object(2n) >= Object(1n)");
+assert(Object(1n) >= Object(2n), false, "Object(1n) >= Object(2n)");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    }
+}
+
+let o2 = {
+    [Symbol.toPrimitive]: function() {
+        return 1n;
+    }
+}
+
+assert(o >= 1n, true, "ToPrimitive(2n) >= 1n");
+assert(1n >= o, false, "1n >= ToPrimitive(2n)");
+assert(o >= o2, true, "ToPrimitive(2n) >= ToPrimitive(1n)");
+assert(o2 >= o, false, "ToPrimitive(1n) >= ToPrimitive(2n)");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    }
+}
+
+o2 = {
+    valueOf: function() {
+        return 1n;
+    }
+}
+
+assert(o >= 1n, true, "valueOf(2n) >= 1n");
+assert(1n >= o, false, "1n >= valueOf(2n)");
+assert(o >= o2, true, "valueOf(2n) >= valueOf(1n)");
+assert(o2 >= o, false, "valueOf(1n) >= valueOf(2n)");
+
+o = {
+    toString: function() {
+        return 2n;
+    }
+}
+
+o2 = {
+    toString: function() {
+        return 1n;
+    }
+}
+
+assert(o >= 1n, true, "toString(2n) >= 1n");
+assert(1n >= o, false, "1n >= ToPrimitive(2n)");
+assert(o >= o2, true, "toString(2n) < toString(1n)");
+assert(o2 >= o, false, "toString(1n) < toString(2n)");
+
diff --git a/JSTests/stress/big-int-greater-than-or-equal.js b/JSTests/stress/big-int-greater-than-or-equal.js
new file mode 100644 (file)
index 0000000..7fb523a
--- /dev/null
@@ -0,0 +1,140 @@
+//@ runBigIntEnabled
+
+// Copyright (C) 2017 Josh Wolfe. All rights reserved.
+// Copyright (C) 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+assert(0n >= 0n, true, "0n >= 0n");
+assert(1n >= 1n, true, "1n >= 1n");
+assert(BigInt("-1") >= BigInt("-1"), true, "-1n >= -1n");
+assert(0n >= BigInt("-0"), true, "0n >= -0n");
+assert(BigInt("-0") >= 0n, true, "-0n >= 0n");
+assert(0n >= 1n, false, "0n >= 1n");
+assert(1n >= 0n, true, "1n >= 0n");
+assert(0n >= BigInt("-1"), true, "0n >= -1n");
+assert(BigInt("-1") >= 0n, false, "-1n >= 0n");
+assert(1n >= BigInt("-1"), true, "1n >= -1n");
+assert(BigInt("-1") >= 1n, false, "-1n >= 1n");
+assert(0x1fffffffffffff01n >= 0x1fffffffffffff02n, false, "0x1fffffffffffff01n >= 0x1fffffffffffff02n");
+assert(0x1fffffffffffff02n >= 0x1fffffffffffff01n, true, "0x1fffffffffffff02n >= 0x1fffffffffffff01n");
+assert(BigInt("-2305843009213693697") >= BigInt("-2305843009213693698"), true, "-2305843009213693697n >= -2305843009213693698n");
+assert(BigInt("-2305843009213693698") >= BigInt("-2305843009213693697"), false, "-2305843009213693698n >= -2305843009213693697n");
+assert(0x10000000000000000n >= 0n, true, "0x10000000000000000n >= 0n");
+assert(0n >= 0x10000000000000000n, false, "0n >= 0x10000000000000000n");
+assert(0x10000000000000000n >= 1n, true, "0x10000000000000000n >= 1n");
+assert(1n >= 0x10000000000000000n, false, "1n >= 0x10000000000000000n");
+assert(0x10000000000000000n >= BigInt("-1"), true, "0x10000000000000000n >= -1n");
+assert(BigInt("-1") >= 0x10000000000000000n, false, "-1n >= 0x10000000000000000n");
+assert(0x10000000000000001n >= 0n, true, "0x10000000000000001n >= 0n");
+assert(0n >= 0x10000000000000001n, false, "0n >= 0x10000000000000001n");
+assert(BigInt("-18446744073709551616") >= 0n, false, "-18446744073709551616n >= 0n");
+assert(0n >= BigInt("-18446744073709551616"), true, "0n >= -18446744073709551616n");
+assert(BigInt("-18446744073709551616") >= 1n, false, "-18446744073709551616n >= 1n");
+assert(1n >= BigInt("-18446744073709551616"), true, "1n >= -18446744073709551616n");
+assert(BigInt("-18446744073709551616") >= BigInt("-1"), false, "-18446744073709551616n >= -1n");
+assert(BigInt("-1") >= BigInt("-18446744073709551616"), true, "-1n >= -18446744073709551616n");
+assert(BigInt("-18446744073709551617") >= 0n, false, "-18446744073709551617n >= 0n");
+assert(0n >= BigInt("-18446744073709551617"), true, "0n >= -18446744073709551617n");
+assert(0x10000000000000000n >= 0x100000000n, true, "0x10000000000000000n >= 0x100000000n");
+assert(0x100000000n >= 0x10000000000000000n, false, "0x100000000n >= 0x10000000000000000n");
+
+// BigInt - String
+
+assert(0n >= "0", true, "0n >= '0'");
+assert("0" >= 0n, true, "'0' >= 0n");
+assert(0n >= "1", false, "0n >= '1'");
+assert("0" >= 1n, false, "'0' >= 1n");
+assert(1n >= "0", true, "1n >= '0'");
+assert("1" >= 0n, true, "'1' >= 0n");
+assert(0n >= "", true, "0n >= ''");
+assert("" >= 0n, true, "'' >= 0n");
+assert(0n >= "1", false, "0n >= '1'");
+assert("" >= 1n, false, "'' >= 1n");
+assert(1n >= "", true, "1n >= ''");
+assert(1n >= "1", true, "1n >= '1'");
+assert("1" >= 1n, true, "'1' >= 1n");
+assert(1n >= "-1", true, "1n >= '-1'");
+assert("1" >= BigInt("-1"), true, "'1' >= -1n");
+assert(BigInt("-1") >= "1", false, "-1n >= '1'");
+assert("-1" >= 1n, false, "'-1' >= 1n");
+assert(BigInt("-1") >= "-1", true, "-1n >= '-1'");
+assert("-1" >= BigInt("-1"), true, "'-1' >= -1n");
+assert(9007199254740993n >= "9007199254740992", true, "9007199254740993n >= '9007199254740992'");
+assert("9007199254740993" >= 9007199254740992n, true, "'9007199254740993' >= 9007199254740992n");
+assert(BigInt("-9007199254740992") >= "-9007199254740993", true, "-9007199254740992n >= '-9007199254740993'");
+assert("-9007199254740992" >= BigInt("-9007199254740993"), true, "'-9007199254740992' >= -9007199254740993n");
+assert("0x10" >= 14n, true, "'0x10' >= 3n");
+assert("0b10" >= 2n, true, "'0b10' >= 2n");
+assert("0b10" >= 1n, true, "'0b10' >= 1n");
+
+// Invalid String
+
+assert("b10" >= 2n, false, "'b10' >= 2n");
+assert("bbb10" >= 2n, false, "'bbb10' >= 2n");
+
+// BigInt - Number
+
+assert(0n >= 0, true, "0n >= 0");
+assert(0 >= 0n, true, "0 >= 0n");
+assert(0n >= -0, true, "0n >= -0");
+assert(-0 >= 0n, true, "-0 >= 0n");
+assert(0n >= 0.000000000001, false, "0n >= 0.000000000001");
+assert(0.000000000001 >= 0n, true, "0.000000000001 >= 0n");
+assert(0n >= 1, false, "0n >= 1");
+assert(1 >= 0n, true, "1 >= 0n");
+assert(1n >= 0, true, "1n >= 0");
+assert(0 >= 1n, false, "0 >= 1n");
+assert(1n >= 0.999999999999, true, "1n >= 0.999999999999");
+assert(0.999999999999 >= 1n, false, "0.999999999999 >= 1n");
+assert(1n >= 1, true, "1n >= 1");
+assert(1 >= 1n, true, "1 >= 1n");
+assert(0n >= Number.MIN_VALUE, false, "0n >= Number.MIN_VALUE");
+assert(Number.MIN_VALUE >= 0n, true, "Number.MIN_VALUE >= 0n");
+assert(0n >= -Number.MIN_VALUE, true, "0n >= -Number.MIN_VALUE");
+assert(-Number.MIN_VALUE >= 0n, false, "-Number.MIN_VALUE >= 0n");
+assert(BigInt("-10") >= Number.MIN_VALUE, false, "-10n >= Number.MIN_VALUE");
+assert(Number.MIN_VALUE >= BigInt("-10"), true, "Number.MIN_VALUE >= -10n");
+assert(1n >= Number.MAX_VALUE, false, "1n >= Number.MAX_VALUE");
+assert(Number.MAX_VALUE >= 1n, true, "Number.MAX_VALUE >= 1n");
+assert(1n >= -Number.MAX_VALUE, true, "1n >= -Number.MAX_VALUE");
+assert(-Number.MAX_VALUE >= 1n, false, "-Number.MAX_VALUE >= 1n");
+assert(0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn >= Number.MAX_VALUE, false, "0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn >= Number.MAX_VALUE");
+assert(Number.MAX_VALUE >= 0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn, true, "Number.MAX_VALUE >= 0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn");
+assert(0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n >= Number.MAX_VALUE, true, "0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n >= Number.MAX_VALUE");
+assert(Number.MAX_VALUE >= 0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n, false, "Number.MAX_VALUE >= 0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n");
+assert(1n >= Infinity, false, "1n >= Infinity");
+assert(Infinity >= 1n, true, "Infinity >= 1n");
+assert(BigInt("-1") >= Infinity, false, "-1n >= Infinity");
+assert(Infinity >= BigInt("-1"), true, "Infinity >= -1n");
+assert(1n >= -Infinity, true, "1n >= -Infinity");
+assert(-Infinity >= 1n, false, "-Infinity >= 1n");
+assert(BigInt("-1") >= -Infinity, true, "-1n >= -Infinity");
+assert(-Infinity >= BigInt("-1"), false, "-Infinity >= -1n");
+assert(0n >= NaN, false, "0n >= NaN");
+assert(NaN >= 0n, false, "NaN >= 0n");
+
+// BigInt - Boolean
+
+assert(false >= 1n, false, "false >= 1n");
+assert(1n >= false, true, "1n >= false");
+assert(false >= 0n, true, "false >= 0n");
+assert(0n >= false, true, "0n >= false");
+assert(true >= 1n, true, "true >= 1n");
+assert(1n >= true, true, "1n >= true");
+assert(true >= 2n, false, "true >= 2n");
+assert(2n >= true, true, "2n >= true");
+
+// BigInt - Symbol
+
+try {
+    1n >= Symbol("1");
+    assert(false, true, "Comparison with Symbol shoud throw TypeError, but executed without exception");
+} catch(e) {
+    assert(e instanceof TypeError, true, "Comparison with Symbol shoud throw TypeError, but throwed something else");
+}
+
diff --git a/JSTests/stress/big-int-less-than-or-equal-general.js b/JSTests/stress/big-int-less-than-or-equal-general.js
new file mode 100644 (file)
index 0000000..44ffa57
--- /dev/null
@@ -0,0 +1,148 @@
+//@ runBigIntEnabled
+
+// Copyright (C) 2017 Josh Wolfe. All rights reserved.
+// Copyright (C) 2017 Robin Templeton. All rights reserved.
+// Copyright (C) 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+assert(0n <= 0n, true, "0n <= 0n");
+assert(1n <= 1n, true, "1n <= 1n");
+assert(BigInt("-1") <= BigInt("-1"), true, "-1n <= -1n");
+assert(0n <= BigInt("-0"), true, "0n <= -0n");
+assert(BigInt("-0") <= 0n, true, "-0n <= 0n");
+assert(0n <= 1n, true, "0n <= 1n");
+assert(1n <= 0n, false, "1n <= 0n");
+assert(0n <= BigInt("-1"), false, "0n <= -1n");
+assert(BigInt("-1") <= 0n, true, "-1n <= 0n");
+assert(1n <= BigInt("-1"), false, "1n <= -1n");
+assert(BigInt("-1") <= 1n, true, "-1n <= 1n");
+assert(0x1fffffffffffff01n <= 0x1fffffffffffff02n, true, "0x1fffffffffffff01n <= 0x1fffffffffffff02n");
+assert(0x1fffffffffffff02n <= 0x1fffffffffffff01n, false, "0x1fffffffffffff02n <= 0x1fffffffffffff01n");
+assert(BigInt("-2305843009213693697") <= BigInt("-2305843009213693698"), false, "-2305843009213693697n <= -2305843009213693698n");
+assert(BigInt("-2305843009213693698") <= BigInt("-2305843009213693697"), true, "-2305843009213693698n <= -2305843009213693697n");
+assert(0x10000000000000000n <= 0n, false, "0x10000000000000000n <= 0n");
+assert(0n <= 0x10000000000000000n, true, "0n <= 0x10000000000000000n");
+assert(0x10000000000000000n <= 1n, false, "0x10000000000000000n <= 1n");
+assert(1n <= 0x10000000000000000n, true, "1n <= 0x10000000000000000n");
+assert(0x10000000000000000n <= BigInt("-1"), false, "0x10000000000000000n <= -1n");
+assert(BigInt("-1") <= 0x10000000000000000n, true, "-1n <= 0x10000000000000000n");
+assert(0x10000000000000001n <= 0n, false, "0x10000000000000001n <= 0n");
+assert(0n <= 0x10000000000000001n, true, "0n <= 0x10000000000000001n");
+assert(BigInt("-18446744073709551616") <= 0n, true, "-18446744073709551616n <= 0n");
+assert(0n <= BigInt("-18446744073709551616"), false, "0n <= -18446744073709551616n");
+assert(BigInt("-18446744073709551616") <= 1n, true, "-18446744073709551616n <= 1n");
+assert(1n <= BigInt("-18446744073709551616"), false, "1n <= -18446744073709551616n");
+assert(BigInt("-18446744073709551616") <= BigInt("-1"), true, "-18446744073709551616n <= -1n");
+assert(BigInt("-1") <= BigInt("-18446744073709551616"), false, "-1n <= -18446744073709551616n");
+assert(BigInt("-18446744073709551617") <= 0n, true, "-18446744073709551617n <= 0n");
+assert(0n <= BigInt("-18446744073709551617"), false, "0n <= -18446744073709551617n");
+assert(0x10000000000000000n <= 0x100000000n, false, "0x10000000000000000n <= 0x100000000n");
+assert(0x100000000n <= 0x10000000000000000n, true, "0x100000000n <= 0x10000000000000000n");
+
+// BigInt - String
+
+assert(0n <= "0", true, "0n <= '0'");
+assert("0" <= 0n, true, "'0' <= 0n");
+assert(0n <= "1", true, "0n <= '1'");
+assert("0" <= 1n, true, "'0' <= 1n");
+assert(1n <= "0", false, "1n <= '0'");
+assert("1" <= 0n, false, "'1' <= 0n");
+assert(0n <= "", true, "0n <= ''");
+assert("" <= 0n, true, "'' <= 0n");
+assert(0n <= "1", true, "0n <= '1'");
+assert("" <= 1n, true, "'' <= 1n");
+assert(1n <= "", false, "1n <= ''");
+assert("1" <= 0n, false, "'1' <= 0n");
+assert(1n <= "1", true, "1n <= '1'");
+assert("1" <= 1n, true, "'1' <= 1n");
+assert(1n <= "-1", false, "1n <= '-1'");
+assert("1" <= BigInt("-1"), false, "'1' <= -1n");
+assert(BigInt("-1") <= "1", true, "-1n <= '1'");
+assert("-1" <= 1n, true, "'-1' <= 1n");
+assert(BigInt("-1") <= "-1", true, "-1n <= '-1'");
+assert("-1" <= BigInt("-1"), true, "'-1' <= -1n");
+assert(9007199254740993n <= "9007199254740992", false, "9007199254740993n <= '9007199254740992'");
+assert("9007199254740993" <= 9007199254740992n, false, "'9007199254740993' <= 9007199254740992n");
+assert(BigInt("-9007199254740992") <= "-9007199254740993", false, "-9007199254740992n <= '-9007199254740993'");
+assert("-9007199254740992" <= BigInt("-9007199254740993"), false, "'-9007199254740992' <= -9007199254740993n");
+assert("0x10" <= 3n, false, "'0x10' <= 3n");
+assert("0x10" <= 2n, false, "'0x10' <= 2n");
+assert("0x10" <= 1n, false, "'0x10' <= 1n");
+assert("0o10" <= 7n, false, "'0o10' <= 7n");
+assert("0o10" <= 8n, true, "'0o10' <= 8n");
+assert("0o10" <= 9n, true, "'0o10' <= 9n");
+assert("0b10" <= 3n, true, "'0b10' <= 3n");
+assert("0b10" <= 2n, true, "'0b10' <= 2n");
+assert("0b10" <= 1n, false, "'0b10' <= 1n");
+
+// Invalid String
+
+assert("b10" <= 2n, false, "'b10' > 2n");
+assert("bbb10" <= 2n, false, "'bbb10' > 2n");
+
+// BigInt - Number
+
+assert(0n <= 0, true, "0n <= 0");
+assert(0 <= 0n, true, "0 <= 0n");
+assert(0n <= -0, true, "0n <= -0");
+assert(-0 <= 0n, true, "-0 <= 0n");
+assert(0n <= 0.000000000001, true, "0n <= 0.000000000001");
+assert(0.000000000001 <= 0n, false, "0.000000000001 <= 0n");
+assert(0n <= 1, true, "0n <= 1");
+assert(1 <= 0n, false, "1 <= 0n");
+assert(1n <= 0, false, "1n <= 0");
+assert(0 <= 1n, true, "0 <= 1n");
+assert(1n <= 0.999999999999, false, "1n <= 0.999999999999");
+assert(0.999999999999 <= 1n, true, "0.999999999999 <= 1n");
+assert(1n <= 1, true, "1n <= 1");
+assert(1 <= 1n, true, "1 <= 1n");
+assert(0n <= Number.MIN_VALUE, true, "0n <= Number.MIN_VALUE");
+assert(Number.MIN_VALUE <= 0n, false, "Number.MIN_VALUE <= 0n");
+assert(0n <= -Number.MIN_VALUE, false, "0n <= -Number.MIN_VALUE");
+assert(-Number.MIN_VALUE <= 0n, true, "-Number.MIN_VALUE <= 0n");
+assert(BigInt("-10") <= Number.MIN_VALUE, true, "-10n <= Number.MIN_VALUE");
+assert(Number.MIN_VALUE <= BigInt("-10"), false, "Number.MIN_VALUE <= -10n");
+assert(1n <= Number.MAX_VALUE, true, "1n <= Number.MAX_VALUE");
+assert(Number.MAX_VALUE <= 1n, false, "Number.MAX_VALUE <= 1n");
+assert(1n <= -Number.MAX_VALUE, false, "1n <= -Number.MAX_VALUE");
+assert(-Number.MAX_VALUE <= 1n, true, "-Number.MAX_VALUE <= 1n");
+assert(0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn <= Number.MAX_VALUE, true, "0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn <= Number.MAX_VALUE");
+assert(Number.MAX_VALUE <= 0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn, false, "Number.MAX_VALUE <= 0xfffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn");
+assert(0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n <= Number.MAX_VALUE, false, "0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n <= Number.MAX_VALUE");
+assert(Number.MAX_VALUE <= 0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n, true, "Number.MAX_VALUE <= 0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001n");
+assert(1n <= Infinity, true, "1n <= Infinity");
+assert(Infinity <= 1n, false, "Infinity <= 1n");
+assert(BigInt("-1") <= Infinity, true, "-1n <= Infinity");
+assert(Infinity <= BigInt("-1"), false, "Infinity <= -1n");
+assert(1n <= -Infinity, false, "1n <= -Infinity");
+assert(-Infinity <= 1n, true, "-Infinity <= 1n");
+assert(BigInt("-1") <= -Infinity, false, "-1n <= -Infinity");
+assert(-Infinity <= BigInt("-1"), true, "-Infinity <= -1n");
+assert(0n <= NaN, false, "0n <= NaN");
+assert(NaN <= 0n, false, "NaN <= 0n");
+
+// BigInt - Boolean
+
+assert(false <= 1n, true, "false <= 1n");
+assert(1n <= false, false, "1n <= false");
+assert(false <= 0n, true, "false <= 0n");
+assert(0n <= false, true, "0n <= false");
+assert(true <= 1n, true, "true <= 1n");
+assert(1n <= true, true, "1n <= true");
+assert(true <= 2n, true, "true <= 2n");
+assert(2n <= true, false, "2n <= true");
+
+// BigInt - Symbol
+
+try {
+    1n <= Symbol("1");
+    assert(false, true, "Comparison with Symbol shoud throw TypeError, but executed without exception");
+} catch(e) {
+    assert(e instanceof TypeError, true, "Comparison with Symbol shoud throw TypeError, but throwed something else");
+}
+
diff --git a/JSTests/stress/big-int-less-than-or-equal-jit.js b/JSTests/stress/big-int-less-than-or-equal-jit.js
new file mode 100644 (file)
index 0000000..f356844
--- /dev/null
@@ -0,0 +1,24 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+function lessThanOrEqualTest(a, b) {
+    return a <= b;
+}
+noInline(lessThanOrEqualTest);
+
+for (let i = 0; i < 100000; i++) {
+    assert(lessThanOrEqualTest(3n, 4) === true);
+}
+
+for (let i = 0; i < 100000; i++) {
+    assert(lessThanOrEqualTest(3n, 4n) === true);
+}
+
+for (let i = 0; i < 100000; i++) {
+    assert(lessThanOrEqualTest(3n, "4") === true);
+}
+
diff --git a/JSTests/stress/big-int-less-than-or-equal-order-of-evaluation.js b/JSTests/stress/big-int-less-than-or-equal-order-of-evaluation.js
new file mode 100644 (file)
index 0000000..64ea754
--- /dev/null
@@ -0,0 +1,55 @@
+//@ runBigIntEnabled
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        throw new Error("Calling @toPrimitive");
+    }
+}
+
+try {
+    o <= Symbol(2);
+    assert(true, false, "")
+} catch(e) {
+    assert(e.message, "Calling @toPrimitive", "Bad Exception when object is left operand");
+}
+
+try {
+    Symbol(2) <= o;
+    assert(true, false, "")
+} catch(e) {
+    assert(e instanceof TypeError, true, "Bad Exception when Symbol is left operand");
+}
+
+o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    },
+
+    toString: function() {
+        throw new Error("Should never call toString");
+    },
+
+    valueOf: function() {
+        throw new Error("Should never call valueOf");
+    }
+}
+
+assert(o <= 3n, true, "ToPrimitive(2n) <= 3n");
+
+o = {
+    toString: function() {
+        throw new Error("Should never call toString");
+    },
+
+    valueOf: function() {
+        return 2n;
+    }
+}
+
+assert(o <= 3n, true, "valueOf(2n) <= 3n");
+
diff --git a/JSTests/stress/big-int-less-than-or-equal-wrapped-values.js b/JSTests/stress/big-int-less-than-or-equal-wrapped-values.js
new file mode 100644 (file)
index 0000000..237c56a
--- /dev/null
@@ -0,0 +1,63 @@
+//@ runBigIntEnabled
+
+function assert(v, e, m) {
+    if (v !== e)
+        throw new Error(m);
+}
+
+assert(Object(2n) <= 1n, false, "Object(2n) <= 1n");
+assert(1n <= Object(2n), true, "1n <= Object(2n)");
+assert(Object(2n) <= Object(1n), false, "Object(2n) <= Object(1n)");
+assert(Object(1n) <= Object(2n), true, "Object(1n) <= Object(2n)");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    }
+}
+
+let o2 = {
+    [Symbol.toPrimitive]: function() {
+        return 1n;
+    }
+}
+
+assert(o <= 1n, false, "ToPrimitive(2n) <= 1n");
+assert(1n <= o, true, "1n <= ToPrimitive(2n)");
+assert(o <= o2, false, "ToPrimitive(2n) <= ToPrimitive(1n)");
+assert(o2 <= o, true, "ToPrimitive(1n) <= ToPrimitive(2n)");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    }
+}
+
+o2 = {
+    valueOf: function() {
+        return 1n;
+    }
+}
+
+assert(o <= 1n, false, "ToPrimitive(2n) <= 1n");
+assert(1n <= o, true, "1n <= ToPrimitive(2n)");
+assert(o <= o2, false, "ToPrimitive(2n) <= ToPrimitive(1n)");
+assert(o2 <= o, true, "ToPrimitive(1n) <= ToPrimitive(2n)");
+
+o = {
+    toString: function() {
+        return 2n;
+    }
+}
+
+o2 = {
+    toString: function() {
+        return 1n;
+    }
+}
+
+assert(o <= 1n, false, "ToPrimitive(2n) <= 1n");
+assert(1n <= o, true, "1n <= ToPrimitive(2n)");
+assert(o <= o2, false, "ToPrimitive(2n) <= ToPrimitive(1n)");
+assert(o2 <= o, true, "ToPrimitive(1n) <= ToPrimitive(2n)");
+
index 7c092b5fa0cf7221378293b836a6189952c52478..fb19a5a407985bf346319db1b79d5742746fb102 100644 (file)
@@ -1,3 +1,23 @@
+2018-05-31  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "=<" and ">=" relational operation
+        https://bugs.webkit.org/show_bug.cgi?id=185929
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch is introducing support to BigInt operands into ">=" and
+        "<=" operators.
+        Here we introduce ```bigIntCompareResult``` that is a helper function
+        to reuse code between "less than" and "less than or equal" operators.
+
+        * runtime/JSBigInt.h:
+        * runtime/Operations.h:
+        (JSC::bigIntCompareResult):
+        (JSC::bigIntCompare):
+        (JSC::jsLess):
+        (JSC::jsLessEq):
+        (JSC::bigIntCompareLess): Deleted.
+
 2018-05-31  Saam Barati  <sbarati@apple.com>
 
         Cache toString results for CoW arrays
 2018-05-31  Saam Barati  <sbarati@apple.com>
 
         Cache toString results for CoW arrays
index 28e24aa35e24b4c447cbf52b5c8411b2a5e32646..28e4da6cccd712694a3d9b1b03f57c2ff30518c1 100644 (file)
@@ -87,6 +87,11 @@ public:
     std::optional<uint8_t> singleDigitValueForString();
     String toString(ExecState*, unsigned radix);
     
     std::optional<uint8_t> singleDigitValueForString();
     String toString(ExecState*, unsigned radix);
     
+    enum class ComparisonMode {
+        LessThan,
+        LessThanOrEqual
+    };
+
     enum class ComparisonResult {
         Equal,
         Undefined,
     enum class ComparisonResult {
         Equal,
         Undefined,
index f8aa9f7eaf95656d375366e0eb928f55b44a431c..f95b9d0d24edfe284db962d150f1a6c782e39f37 100644 (file)
@@ -156,7 +156,16 @@ ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
     return ropeBuilder.release();
 }
 
     return ropeBuilder.release();
 }
 
-ALWAYS_INLINE bool bigIntCompareLess(CallFrame* callFrame, JSValue v1, JSValue v2)
+ALWAYS_INLINE bool bigIntCompareResult(JSBigInt::ComparisonResult comparisonResult, JSBigInt::ComparisonMode comparisonMode)
+{
+    if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
+        return comparisonResult == JSBigInt::ComparisonResult::LessThan;
+
+    ASSERT(comparisonMode == JSBigInt::ComparisonMode::LessThanOrEqual);
+    return comparisonResult == JSBigInt::ComparisonResult::LessThan || comparisonResult == JSBigInt::ComparisonResult::Equal;
+}
+
+ALWAYS_INLINE bool bigIntCompare(CallFrame* callFrame, JSValue v1, JSValue v2, JSBigInt::ComparisonMode comparisonMode)
 {
     ASSERT(v1.isBigInt() || v2.isBigInt());
     ASSERT(v1.isPrimitive() && v2.isPrimitive());
 {
     ASSERT(v1.isBigInt() || v2.isBigInt());
     ASSERT(v1.isPrimitive() && v2.isPrimitive());
@@ -165,7 +174,7 @@ ALWAYS_INLINE bool bigIntCompareLess(CallFrame* callFrame, JSValue v1, JSValue v
     auto scope = DECLARE_THROW_SCOPE(vm);
     
     if (v1.isBigInt() && v2.isBigInt())
     auto scope = DECLARE_THROW_SCOPE(vm);
     
     if (v1.isBigInt() && v2.isBigInt())
-        return JSBigInt::compare(asBigInt(v1), asBigInt(v2)) == JSBigInt::ComparisonResult::LessThan;
+        return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(v2)), comparisonMode);
     
     if (v1.isBigInt()) {
         JSValue primValue = v2;
     
     if (v1.isBigInt()) {
         JSValue primValue = v2;
@@ -175,15 +184,15 @@ ALWAYS_INLINE bool bigIntCompareLess(CallFrame* callFrame, JSValue v1, JSValue v
             if (!bigIntValue)
                 return false;
 
             if (!bigIntValue)
                 return false;
 
-            return JSBigInt::compare(asBigInt(v1), bigIntValue) == JSBigInt::ComparisonResult::LessThan;
+            return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), bigIntValue), comparisonMode);
         }
 
         if (primValue.isBigInt())
         }
 
         if (primValue.isBigInt())
-            return JSBigInt::compare(asBigInt(v1), asBigInt(primValue)) == JSBigInt::ComparisonResult::LessThan;
+            return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(primValue)), comparisonMode);
 
         double numberValue = primValue.toNumber(callFrame);
         RETURN_IF_EXCEPTION(scope, false);
 
         double numberValue = primValue.toNumber(callFrame);
         RETURN_IF_EXCEPTION(scope, false);
-        return JSBigInt::compareToDouble(asBigInt(v1), numberValue) == JSBigInt::ComparisonResult::LessThan;
+        return bigIntCompareResult(JSBigInt::compareToDouble(asBigInt(v1), numberValue), comparisonMode);
     }
     
     JSValue primValue = v1;
     }
     
     JSValue primValue = v1;
@@ -193,15 +202,21 @@ ALWAYS_INLINE bool bigIntCompareLess(CallFrame* callFrame, JSValue v1, JSValue v
         if (!bigIntValue)
             return false;
 
         if (!bigIntValue)
             return false;
 
-        return JSBigInt::compare(bigIntValue, asBigInt(v2)) == JSBigInt::ComparisonResult::LessThan;
+        return bigIntCompareResult(JSBigInt::compare(bigIntValue, asBigInt(v2)), comparisonMode);
     }
     
     if (primValue.isBigInt())
     }
     
     if (primValue.isBigInt())
-        return JSBigInt::compare(asBigInt(primValue), asBigInt(v2)) == JSBigInt::ComparisonResult::LessThan;
+        return bigIntCompareResult(JSBigInt::compare(asBigInt(primValue), asBigInt(v2)), comparisonMode);
     
     double numberValue = primValue.toNumber(callFrame);
     RETURN_IF_EXCEPTION(scope, false);
     
     double numberValue = primValue.toNumber(callFrame);
     RETURN_IF_EXCEPTION(scope, false);
-    return JSBigInt::compareToDouble(asBigInt(v2), numberValue) == JSBigInt::ComparisonResult::GreaterThan;
+
+    // Here we check inverted because BigInt is the v2
+    JSBigInt::ComparisonResult comparisonResult = JSBigInt::compareToDouble(asBigInt(v2), numberValue);
+    if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
+        return comparisonResult == JSBigInt::ComparisonResult::GreaterThan;
+
+    return comparisonResult == JSBigInt::ComparisonResult::GreaterThan || comparisonResult == JSBigInt::ComparisonResult::Equal;
 }
 
 ALWAYS_INLINE bool toPrimitiveNumeric(CallFrame* callFrame, JSValue v, JSValue& p, double& n)
 }
 
 ALWAYS_INLINE bool toPrimitiveNumeric(CallFrame* callFrame, JSValue v, JSValue& p, double& n)
@@ -257,11 +272,12 @@ ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
     if (wasNotString1 | wasNotString2) {
         if (p1.isBigInt() || p2.isBigInt()) {
             scope.release();
     if (wasNotString1 | wasNotString2) {
         if (p1.isBigInt() || p2.isBigInt()) {
             scope.release();
-            return bigIntCompareLess(callFrame, p1, p2);
+            return bigIntCompare(callFrame, p1, p2, JSBigInt::ComparisonMode::LessThan);
         }
 
         return n1 < n2;
     }
         }
 
         return n1 < n2;
     }
+
     return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame));
 }
 
     return codePointCompareLessThan(asString(p1)->value(callFrame), asString(p2)->value(callFrame));
 }
 
@@ -290,18 +306,24 @@ ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
     bool wasNotString1;
     bool wasNotString2;
     if (leftFirst) {
     bool wasNotString1;
     bool wasNotString2;
     if (leftFirst) {
-        wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+        wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
         RETURN_IF_EXCEPTION(scope, false);
         RETURN_IF_EXCEPTION(scope, false);
-        wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+        wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
     } else {
     } else {
-        wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+        wasNotString2 = toPrimitiveNumeric(callFrame, v2, p2, n2);
         RETURN_IF_EXCEPTION(scope, false);
         RETURN_IF_EXCEPTION(scope, false);
-        wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+        wasNotString1 = toPrimitiveNumeric(callFrame, v1, p1, n1);
     }
     RETURN_IF_EXCEPTION(scope, false);
 
     }
     RETURN_IF_EXCEPTION(scope, false);
 
-    if (wasNotString1 | wasNotString2)
+    if (wasNotString1 | wasNotString2) {
+        if (p1.isBigInt() || p2.isBigInt()) {
+            scope.release();
+            return bigIntCompare(callFrame, p1, p2, JSBigInt::ComparisonMode::LessThanOrEqual);
+        }
+
         return n1 <= n2;
         return n1 <= n2;
+    }
     return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame));
 }
 
     return !codePointCompareLessThan(asString(p2)->value(callFrame), asString(p1)->value(callFrame));
 }