[ESNext][BigInt] Implement support for "*" operation
https://bugs.webkit.org/show_bug.cgi?id=183721

Reviewed by Saam Barati.

JSTests:

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

Source/JavaScriptCore:

Added BigInt support into times binary operator into LLInt and on
JITOperations profiledMul and unprofiledMul. We are also replacing all
uses of int to unsigned when there is no negative values for
variables.

* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* jit/JITOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::JSBigInt):
(JSC::JSBigInt::allocationSize):
(JSC::JSBigInt::createWithLength):
(JSC::JSBigInt::toString):
(JSC::JSBigInt::multiply):
(JSC::JSBigInt::digitDiv):
(JSC::JSBigInt::internalMultiplyAdd):
(JSC::JSBigInt::multiplyAccumulate):
(JSC::JSBigInt::equals):
(JSC::JSBigInt::absoluteDivSmall):
(JSC::JSBigInt::calculateMaximumCharactersRequired):
(JSC::JSBigInt::toStringGeneric):
(JSC::JSBigInt::rightTrim):
(JSC::JSBigInt::allocateFor):
(JSC::JSBigInt::parseInt):
(JSC::JSBigInt::digit):
(JSC::JSBigInt::setDigit):
* runtime/JSBigInt.h:
* runtime/Operations.h:
(JSC::jsMul):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231137 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index 1392a0d..a126800 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,19 @@
+2018-04-28  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "*" operation
+        https://bugs.webkit.org/show_bug.cgi?id=183721
+
+        Reviewed by Saam Barati.
+
+        * bigIntTests.yaml:
+        * stress/big-int-mul-jit.js: Added.
+        * stress/big-int-mul-to-primitive-precedence.js: Added.
+        * stress/big-int-mul-to-primitive.js: Added.
+        * stress/big-int-mul-type-error.js: Added.
+        * stress/big-int-mul-wrapped-value.js: Added.
+        * stress/big-int-multiplication.js: Added.
+        * stress/big-int-multiply-memory-stress.js: Added.
+
 2018-04-28  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231131.
diff --git a/JSTests/bigIntTests.yaml b/JSTests/bigIntTests.yaml
index 7ae22cb..e947dc2 100644
--- a/JSTests/bigIntTests.yaml
+++ b/JSTests/bigIntTests.yaml
@@ -97,3 +97,24 @@
 - path: stress/big-int-to-string.js
   cmd: runBigIntEnabled
 
+- path: stress/big-int-mul-jit.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mul-to-primitive-precedence.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mul-to-primitive.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mul-type-error.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-mul-wrapped-value.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-multiplication.js
+  cmd: runBigIntEnabled
+
+- path: stress/big-int-multiply-memory-stress.js
+  cmd: runBigIntEnabled
+
diff --git a/JSTests/stress/big-int-mul-jit.js b/JSTests/stress/big-int-mul-jit.js
new file mode 100644
index 0000000..0cbede3
--- /dev/null
+++ b/JSTests/stress/big-int-mul-jit.js
@@ -0,0 +1,19 @@
+//@ runBigIntEnabled
+
+let assert = {
+    sameValue: function(i, e, m) {
+        if (i !== e)
+            throw new Error(m);
+    }
+}
+
+function bigIntMul(x, y) {
+    return x * y;
+}
+noInline(bigIntMul);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bigIntMul(3n, 10n);
+    assert.sameValue(r, 30n, 3n + " * " + 10n + " = " + r);
+}
+
diff --git a/JSTests/stress/big-int-mul-to-primitive-precedence.js b/JSTests/stress/big-int-mul-to-primitive-precedence.js
new file mode 100644
index 0000000..7149a19
--- /dev/null
+++ b/JSTests/stress/big-int-mul-to-primitive-precedence.js
@@ -0,0 +1,39 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testMul(x, y, z, message) {
+    assert.sameValue(x * y, z, message);
+    assert.sameValue(y * x, z, message);
+}
+
+testMul(Object(2n), 1n, 2n, "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");
+    }
+};
+testMul(o, 1n, 2n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    },
+    toString: function () {
+        throw new Error("Should never execute it");
+    }
+};
+testMul(o, 1n, 2n, "ToPrimitive: valueOf");
+
diff --git a/JSTests/stress/big-int-mul-to-primitive.js b/JSTests/stress/big-int-mul-to-primitive.js
new file mode 100644
index 0000000..642e2e8
--- /dev/null
+++ b/JSTests/stress/big-int-mul-to-primitive.js
@@ -0,0 +1,35 @@
+//@ 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 testMul(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; }
+}
+
+testMul(500000000000438n, o, 150000000000131400000000000000n);
+
+o.valueOf = function () {
+    throw new Error("Should never execute it");
+};
+
+testMul(700000000000438n, o, 210000000000131400000000000000n);
+
+o.toString = function () {
+    throw new Error("Should never execute it");
+};
+
+testMul(700000000000438n, o, 210000000000131400000000000000n);
+
diff --git a/JSTests/stress/big-int-mul-type-error.js b/JSTests/stress/big-int-mul-type-error.js
new file mode 100644
index 0000000..b517845
--- /dev/null
+++ b/JSTests/stress/big-int-mul-type-error.js
@@ -0,0 +1,106 @@
+//@ 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");
+
diff --git a/JSTests/stress/big-int-mul-wrapped-value.js b/JSTests/stress/big-int-mul-wrapped-value.js
new file mode 100644
index 0000000..b673d8a
--- /dev/null
+++ b/JSTests/stress/big-int-mul-wrapped-value.js
@@ -0,0 +1,37 @@
+//@ runBigIntEnabled
+
+assert = {
+    sameValue: function (input, expected, message) {
+        if (input !== expected)
+            throw new Error(message);
+    }
+};
+
+function testMul(x, y, z, message) {
+    assert.sameValue(x * y, z, message);
+    assert.sameValue(y * x, z, message);
+}
+
+testMul(Object(2n), 1n, 2n, "ToPrimitive: unbox object with internal slot");
+
+let o = {
+    [Symbol.toPrimitive]: function() {
+        return 2n;
+    }
+};
+testMul(o, 1n, 2n, "ToPrimitive: @@toPrimitive");
+
+o = {
+    valueOf: function() {
+        return 2n;
+    }
+};
+testMul(o, 1n, 2n, "ToPrimitive: valueOf");
+
+o = {
+    toString: function() {
+        return 2n;
+    }
+}
+testMul(o, 1n, 2n, "ToPrimitive: toString");
+
diff --git a/JSTests/stress/big-int-multiplication.js b/JSTests/stress/big-int-multiplication.js
new file mode 100644
index 0000000..3ecd636
--- /dev/null
+++ b/JSTests/stress/big-int-multiplication.js
@@ -0,0 +1,83 @@
+//@ runBigIntEnabled
+
+// Copyright (C) 2017 Robin Templeton. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+assert = {
+    sameValue: function (input, expected, message) {
+    if (input !== expected)
+        throw new Error(message);
+    }
+};
+
+function testMul(x, y, z) {
+    assert.sameValue(x * y, z, x + " * " + y + " = " + z);
+    assert.sameValue(y * x, z, y + " * " + x + " = " + z);
+}
+
+testMul(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0xFDBAC097C8DC5ACCDEEC6CD7A44A4100n);
+testMul(0xFEDCBA9876543210n, 0xFEDCBA98n, 0xFDBAC097530ECA86541D5980n);
+testMul(0xFEDCBA9876543210n, 0x1234n, 0x121F49F49F49F49F4B40n);
+testMul(0xFEDCBA9876543210n, 0x3n, 0x2FC962FC962FC9630n);
+testMul(0xFEDCBA9876543210n, 0x2n, 0x1FDB97530ECA86420n);
+testMul(0xFEDCBA9876543210n, 0x1n, 0xFEDCBA9876543210n);
+testMul(0xFEDCBA9876543210n, 0x0n, 0x0n);
+testMul(0xFEDCBA9876543210n, BigInt("-1"), BigInt("-18364758544493064720"));
+testMul(0xFEDCBA9876543210n, BigInt("-2"), BigInt("-36729517088986129440"));
+testMul(0xFEDCBA9876543210n, BigInt("-3"), BigInt("-55094275633479194160"));
+testMul(0xFEDCBA9876543210n, BigInt("-4660"), BigInt("-85579774817337681595200"));
+testMul(0xFEDCBA9876543210n, BigInt("-4275878551"), BigInt("-78525477154691874604502820720"));
+testMul(0xFEDCBA987654320Fn, 0xFEDCBA987654320Fn, 0xFDBAC097C8DC5ACAE132F7A6B7A1DCE1n);
+testMul(0xFEDCBA987654320Fn, 0xFEDCBA97n, 0xFDBAC09654320FECDEEC6CD9n);
+testMul(0xFEDCBA987654320Fn, 0x3n, 0x2FC962FC962FC962Dn);
+testMul(0xFEDCBA987654320Fn, 0x2n, 0x1FDB97530ECA8641En);
+testMul(0xFEDCBA987654320Fn, 0x1n, 0xFEDCBA987654320Fn);
+testMul(0xFEDCBA987654320Fn, 0x0n, 0x0n);
+testMul(0xFEDCBA987654320Fn, BigInt("-1"), BigInt("-18364758544493064719"));
+testMul(0xFEDCBA987654320Fn, BigInt("-2"), BigInt("-36729517088986129438"));
+testMul(0xFEDCBA987654320Fn, BigInt("-3"), BigInt("-55094275633479194157"));
+testMul(0xFEDCBA987654320Fn, BigInt("-4275878551"), BigInt("-78525477154691874600226942169"));
+testMul(0xFEDCBA987654320Fn, BigInt("-18364758544493064720"), BigInt("-337264356397531028976608289633615613680"));
+testMul(0xFEDCBA98n, 0xFEDCBA98n, 0xFDBAC096DD413A40n);
+testMul(0xFEDCBA98n, 0x1234n, 0x121F49F496E0n);
+testMul(0xFEDCBA98n, 0x3n, 0x2FC962FC8n);
+testMul(0xFEDCBA98n, 0x2n, 0x1FDB97530n);
+testMul(0xFEDCBA98n, 0x1n, 0xFEDCBA98n);
+testMul(0xFEDCBA98n, 0x0n, 0x0n);
+testMul(0xFEDCBA98n, BigInt("-1"), BigInt("-4275878552"));
+testMul(0xFEDCBA98n, BigInt("-2"), BigInt("-8551757104"));
+testMul(0xFEDCBA98n, BigInt("-3"), BigInt("-12827635656"));
+testMul(0xFEDCBA98n, BigInt("-4275878551"), BigInt("-18283137387177738152"));
+testMul(0xFEDCBA98n, BigInt("-18364758544493064720"), BigInt("-78525477173056633148995885440"));
+testMul(0x3n, 0x3n, 0x9n);
+testMul(0x3n, 0x2n, 0x6n);
+testMul(0x3n, 0x1n, 0x3n);
+testMul(0x3n, 0x0n, 0x0n);
+testMul(0x3n, BigInt("-1"), BigInt("-3"));
+testMul(0x3n, BigInt("-2"), BigInt("-6"));
+testMul(0x3n, BigInt("-3"), BigInt("-9"));
+testMul(0x3n, BigInt("-4660"), BigInt("-13980"));
+testMul(0x3n, BigInt("-4275878552"), BigInt("-12827635656"));
+testMul(0x3n, BigInt("-18364758544493064720"), BigInt("-55094275633479194160"));
+testMul(0x0n, 0x0n, 0x0n);
+testMul(0x0n, BigInt("-1"), 0x0n);
+testMul(0x0n, BigInt("-2"), 0x0n);
+testMul(0x0n, BigInt("-3"), 0x0n);
+testMul(0x0n, BigInt("-4275878551"), 0x0n);
+testMul(0x0n, BigInt("-18364758544493064719"), 0x0n);
+testMul(BigInt("-1"), BigInt("-1"), 0x1n);
+testMul(BigInt("-1"), BigInt("-2"), 0x2n);
+testMul(BigInt("-1"), BigInt("-3"), 0x3n);
+testMul(BigInt("-1"), BigInt("-4660"), 0x1234n);
+testMul(BigInt("-1"), BigInt("-4275878551"), 0xFEDCBA97n);
+testMul(BigInt("-1"), BigInt("-4275878552"), 0xFEDCBA98n);
+testMul(BigInt("-1"), BigInt("-18364758544493064719"), 0xFEDCBA987654320Fn);
+testMul(BigInt("-1"), BigInt("-18364758544493064720"), 0xFEDCBA9876543210n);
+testMul(BigInt("-3"), BigInt("-3"), 0x9n);
+testMul(BigInt("-3"), BigInt("-4660"), 0x369Cn);
+testMul(BigInt("-3"), BigInt("-4275878551"), 0x2FC962FC5n);
+testMul(BigInt("-3"), BigInt("-4275878552"), 0x2FC962FC8n);
+testMul(BigInt("-3"), BigInt("-18364758544493064719"), 0x2FC962FC962FC962Dn);
+testMul(BigInt("-3"), BigInt("-18364758544493064720"), 0x2FC962FC962FC9630n);
+testMul(BigInt("-18364758544493064720"), BigInt("-18364758544493064720"), 0xFDBAC097C8DC5ACCDEEC6CD7A44A4100n);
+
diff --git a/JSTests/stress/big-int-multiply-memory-stress.js b/JSTests/stress/big-int-multiply-memory-stress.js
new file mode 100644
index 0000000..1abaa7e
--- /dev/null
+++ b/JSTests/stress/big-int-multiply-memory-stress.js
@@ -0,0 +1,15 @@
+//@ runBigIntEnabled
+
+function assert(a) {
+    if (!a)
+        throw new Error("Bad assertion");
+}
+
+let a = 0n;
+let b = 1n;
+for (let i = 0; i < 1000000; i++) {
+    a = b * 30n;
+}
+
+assert(a === 30n);
+
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 6a1191d..14b34c1 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,42 @@
+2018-04-28  Caio Lima  <ticaiolima@gmail.com>
+
+        [ESNext][BigInt] Implement support for "*" operation
+        https://bugs.webkit.org/show_bug.cgi?id=183721
+
+        Reviewed by Saam Barati.
+
+        Added BigInt support into times binary operator into LLInt and on
+        JITOperations profiledMul and unprofiledMul. We are also replacing all
+        uses of int to unsigned when there is no negative values for
+        variables.
+
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * jit/JITOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::JSBigInt):
+        (JSC::JSBigInt::allocationSize):
+        (JSC::JSBigInt::createWithLength):
+        (JSC::JSBigInt::toString):
+        (JSC::JSBigInt::multiply):
+        (JSC::JSBigInt::digitDiv):
+        (JSC::JSBigInt::internalMultiplyAdd):
+        (JSC::JSBigInt::multiplyAccumulate):
+        (JSC::JSBigInt::equals):
+        (JSC::JSBigInt::absoluteDivSmall):
+        (JSC::JSBigInt::calculateMaximumCharactersRequired):
+        (JSC::JSBigInt::toStringGeneric):
+        (JSC::JSBigInt::rightTrim):
+        (JSC::JSBigInt::allocateFor):
+        (JSC::JSBigInt::parseInt):
+        (JSC::JSBigInt::digit):
+        (JSC::JSBigInt::setDigit):
+        * runtime/JSBigInt.h:
+        * runtime/Operations.h:
+        (JSC::jsMul):
+
 2018-04-28  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r231131.
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index cee6562..e4650ac 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -146,14 +146,14 @@
                     JSValue child2Constant = m_state.forNode(node->child2().node()).value();
 
                     // FIXME: Revisit this condition when introducing BigInt to JSC.
-                    auto isNonStringCellConstant = [] (JSValue value) {
-                        return value && value.isCell() && !value.isString();
+                    auto isNonStringOrBigIntCellConstant = [] (JSValue value) {
+                        return value && value.isCell() && !value.isString() && !value.isBigInt();
                     };
 
-                    if (isNonStringCellConstant(child1Constant)) {
+                    if (isNonStringOrBigIntCellConstant(child1Constant)) {
                         node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2());
                         changed = true;
-                    } else if (isNonStringCellConstant(child2Constant)) {
+                    } else if (isNonStringOrBigIntCellConstant(child2Constant)) {
                         node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1());
                         changed = true;
                     }
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 365bb73..62fc1b0 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -2554,34 +2554,23 @@
     return JSValue::encode(result);
 }
 
-ALWAYS_INLINE static EncodedJSValue unprofiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
+ALWAYS_INLINE static EncodedJSValue unprofiledMul(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(jsMul(exec, op1, op2));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledMul(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
+ALWAYS_INLINE static EncodedJSValue profiledMul(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 = jsMul(exec, op1, op2);
     arithProfile.observeResult(result);
     return JSValue::encode(result);
 }
@@ -2591,7 +2580,7 @@
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledMul(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueMulNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*)
@@ -2599,7 +2588,7 @@
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledMul(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueMulOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
@@ -2616,7 +2605,7 @@
     exec->codeBlock()->dumpMathICStats();
 #endif
 
-    return unprofiledMul(*vm, exec, encodedOp1, encodedOp2);
+    return unprofiledMul(exec, encodedOp1, encodedOp2);
 }
 
 EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
@@ -2625,7 +2614,7 @@
     NativeCallFrameTracer tracer(vm, exec);
 
     ASSERT(arithProfile);
-    return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
+    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
 }
 
 EncodedJSValue JIT_OPERATION operationValueMulProfiledOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
@@ -2643,7 +2632,7 @@
     exec->codeBlock()->dumpMathICStats();
 #endif
 
-    return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile, false);
+    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile, false);
 }
 
 EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC* mulIC)
@@ -2653,7 +2642,7 @@
 
     ArithProfile* arithProfile = mulIC->arithProfile();
     ASSERT(arithProfile);
-    return profiledMul(*vm, exec, encodedOp1, encodedOp2, *arithProfile);
+    return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
 }
 
 ALWAYS_INLINE static EncodedJSValue unprofiledNegate(ExecState* exec, EncodedJSValue encodedOperand)
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index e6c1a44..1c0391b 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -486,10 +486,26 @@
     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);
+    JSValue leftPrimitive = left.toPrimitive(exec, PreferNumber); 
+    CHECK_EXCEPTION();
+    JSValue rightPrimitive = right.toPrimitive(exec, PreferNumber);
+    CHECK_EXCEPTION();
+    
+    if (leftPrimitive.isBigInt() || rightPrimitive.isBigInt()) {
+        if (leftPrimitive.isBigInt() && rightPrimitive.isBigInt()) {
+            JSValue result(JSBigInt::multiply(exec, asBigInt(leftPrimitive), asBigInt(rightPrimitive)));
+            RETURN_WITH_PROFILING(result, {
+                updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
+            });
+        }
+
+        THROW(createTypeError(exec, "Invalid mix of BigInt and other type in multiplication."));
+    }
+
+    double a = leftPrimitive.toNumber(exec);
+    CHECK_EXCEPTION();
+    double b = rightPrimitive.toNumber(exec);
+    CHECK_EXCEPTION();
     JSValue result = jsNumber(a * b);
     RETURN_WITH_PROFILING(result, {
         updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp
index c51c8b2..9197b9a 100644
--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp
+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp
@@ -69,7 +69,7 @@
     Base::visitChildren(thisObject, visitor);
 }
 
-JSBigInt::JSBigInt(VM& vm, Structure* structure, int length)
+JSBigInt::JSBigInt(VM& vm, Structure* structure, unsigned length)
     : Base(vm, structure)
     , m_length(length)
 { }
@@ -93,13 +93,13 @@
     return zeroBigInt;
 }
 
-size_t JSBigInt::allocationSize(int length)
+size_t JSBigInt::allocationSize(unsigned length)
 {
     size_t sizeWithPadding = WTF::roundUpToMultipleOf<sizeof(size_t)>(sizeof(JSBigInt));
     return sizeWithPadding + length * sizeof(Digit);
 }
 
-JSBigInt* JSBigInt::createWithLength(VM& vm, int length)
+JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length)
 {
     JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
     bigInt->finishCreation(vm);
@@ -223,7 +223,7 @@
     return parseInt(state, vm, s.characters16(), s.length(), 0, radix, false);
 }
 
-String JSBigInt::toString(ExecState& state, int radix)
+String JSBigInt::toString(ExecState& state, unsigned radix)
 {
     if (this->isZero())
         return state.vm().smallStrings.singleCharacterStringRep('0');
@@ -246,6 +246,26 @@
     internalMultiplyAdd(this, factor, summand, length(), this);
 }
 
+JSBigInt* JSBigInt::multiply(ExecState* state, JSBigInt* x, JSBigInt* y)
+{
+    VM& vm = state->vm();
+
+    if (x->isZero())
+        return x;
+    if (y->isZero())
+        return y;
+
+    unsigned resultLength = x->length() + y->length();
+    JSBigInt* result = JSBigInt::createWithLength(vm, resultLength);
+    result->initialize(InitializationType::WithZero);
+
+    for (unsigned i = 0; i < x->length(); i++)
+        multiplyAccumulate(y, x->digit(i), result, i);
+
+    result->setSign(x->sign() != y->sign());
+    return result->rightTrim(vm);
+}
+
 #if USE(JSVALUE32_64)
 #define HAVE_TWO_DIGIT 1
 typedef uint64_t TwoDigit;
@@ -378,9 +398,9 @@
     static const Digit kHalfDigitBase = 1ull << halfDigitBits;
     // Adapted from Warren, Hacker's Delight, p. 152.
 #if USE(JSVALUE64)
-    int s = clz64(divisor);
+    unsigned s = clz64(divisor);
 #else
-    int s = clz32(divisor);
+    unsigned s = clz32(divisor);
 #endif
     divisor <<= s;
     
@@ -423,14 +443,14 @@
 
 // Multiplies {source} with {factor} and adds {summand} to the result.
 // {result} and {source} may be the same BigInt for inplace modification.
-void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int n, JSBigInt* result)
+void JSBigInt::internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned n, JSBigInt* result)
 {
     ASSERT(source->length() >= n);
     ASSERT(result->length() >= n);
 
     Digit carry = summand;
     Digit high = 0;
-    for (int i = 0; i < n; i++) {
+    for (unsigned i = 0; i < n; i++) {
         Digit current = source->digit(i);
         Digit newCarry = 0;
 
@@ -458,6 +478,49 @@
         ASSERT(!(carry + high));
 }
 
+// Multiplies {multiplicand} with {multiplier} and adds the result to
+// {accumulator}, starting at {accumulatorIndex} for the least-significant
+// digit.
+// Callers must ensure that {accumulator} is big enough to hold the result.
+void JSBigInt::multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex)
+{
+    ASSERT(accumulator->length() > multiplicand->length() + accumulatorIndex);
+    if (!multiplier)
+        return;
+    
+    Digit carry = 0;
+    Digit high = 0;
+    for (unsigned i = 0; i < multiplicand->length(); i++, accumulatorIndex++) {
+        Digit acc = accumulator->digit(accumulatorIndex);
+        Digit newCarry = 0;
+        
+        // Add last round's carryovers.
+        acc = digitAdd(acc, high, newCarry);
+        acc = digitAdd(acc, carry, newCarry);
+        
+        // Compute this round's multiplication.
+        Digit multiplicandDigit = multiplicand->digit(i);
+        Digit low = digitMul(multiplier, multiplicandDigit, high);
+        acc = digitAdd(acc, low, newCarry);
+        
+        // Store result and prepare for next round.
+        accumulator->setDigit(accumulatorIndex, acc);
+        carry = newCarry;
+    }
+    
+    while (carry || high) {
+        ASSERT(accumulatorIndex < accumulator->length());
+        Digit acc = accumulator->digit(accumulatorIndex);
+        Digit newCarry = 0;
+        acc = digitAdd(acc, high, newCarry);
+        high = 0;
+        acc = digitAdd(acc, carry, newCarry);
+        accumulator->setDigit(accumulatorIndex, acc);
+        carry = newCarry;
+        accumulatorIndex++;
+    }
+}
+
 bool JSBigInt::equals(JSBigInt* x, JSBigInt* y)
 {
     if (x->sign() != y->sign())
@@ -466,7 +529,7 @@
     if (x->length() != y->length())
         return false;
 
-    for (int i = 0; i < x->length(); i++) {
+    for (unsigned i = 0; i < x->length(); i++) {
         if (x->digit(i) != y->digit(i))
             return false;
     }
@@ -494,7 +557,7 @@
         return;
     }
 
-    int length = x->length();
+    unsigned length = x->length();
     if (quotient != nullptr) {
         if (*quotient == nullptr)
             *quotient = JSBigInt::createWithLength(vm, length);
@@ -521,14 +584,14 @@
     162, 163, 165, 166,                         // 33..36
 };
 
-static const int bitsPerCharTableShift = 5;
+static const unsigned bitsPerCharTableShift = 5;
 static const size_t bitsPerCharTableMultiplier = 1u << bitsPerCharTableShift;
 
 // Compute (an overapproximation of) the length of the resulting string:
 // Divide bit length of the BigInt by bits representable per character.
-uint64_t JSBigInt::calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign)
+uint64_t JSBigInt::calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign)
 {
-    int leadingZeros;
+    unsigned leadingZeros;
     if (sizeof(lastDigit) == 8)
         leadingZeros = clz64(lastDigit);
     else
@@ -556,7 +619,7 @@
     return maximumCharactersRequired;
 }
 
-String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, int radix)
+String JSBigInt::toStringGeneric(ExecState& state, JSBigInt* x, unsigned radix)
 {
     // FIXME: [JSC] Revisit usage of StringVector into JSBigInt::toString
     // https://bugs.webkit.org/show_bug.cgi?id=18067
@@ -565,7 +628,7 @@
     ASSERT(radix >= 2 && radix <= 36);
     ASSERT(!x->isZero());
 
-    int length = x->length();
+    unsigned length = x->length();
     bool sign = x->sign();
 
     uint8_t maxBitsPerChar = maxBitsPerCharTable[radix];
@@ -581,12 +644,12 @@
     if (length == 1)
         lastDigit = x->digit(0);
     else {
-        int chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
+        unsigned chunkChars = digitBits * bitsPerCharTableMultiplier / maxBitsPerChar;
         Digit chunkDivisor = digitPow(radix, chunkChars);
 
         // By construction of chunkChars, there can't have been overflow.
         ASSERT(chunkDivisor);
-        int nonZeroDigit = length - 1;
+        unsigned nonZeroDigit = length - 1;
         ASSERT(x->digit(nonZeroDigit));
 
         // {rest} holds the part of the BigInt that we haven't looked at yet.
@@ -602,7 +665,7 @@
             ASSERT(rest);
 
             dividend = &rest;
-            for (int i = 0; i < chunkChars; i++) {
+            for (unsigned i = 0; i < chunkChars; i++) {
                 resultString.append(radixDigits[chunk % radix]);
                 chunk /= radix;
             }
@@ -627,7 +690,7 @@
     ASSERT(resultString.size() <= static_cast<size_t>(maximumCharactersRequired));
 
     // Remove leading zeroes.
-    int newSizeNoLeadingZeroes = resultString.size();
+    unsigned newSizeNoLeadingZeroes = resultString.size();
     while (newSizeNoLeadingZeroes  > 1 && resultString[newSizeNoLeadingZeroes - 1] == '0')
         newSizeNoLeadingZeroes--;
 
@@ -646,14 +709,16 @@
     if (isZero())
         return this;
 
+    ASSERT(m_length);
+
     int nonZeroIndex = m_length - 1;
     while (nonZeroIndex >= 0 && !digit(nonZeroIndex))
         nonZeroIndex--;
 
-    if (nonZeroIndex == m_length - 1)
+    if (nonZeroIndex == static_cast<int>(m_length - 1))
         return this;
 
-    int newLength = nonZeroIndex + 1;
+    unsigned newLength = nonZeroIndex + 1;
     JSBigInt* trimmedBigInt = createWithLength(vm, newLength);
     RELEASE_ASSERT(trimmedBigInt);
     std::copy(dataStorage(), dataStorage() + newLength, trimmedBigInt->dataStorage()); 
@@ -663,14 +728,14 @@
     return trimmedBigInt;
 }
 
-JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, int radix, int charcount)
+JSBigInt* JSBigInt::allocateFor(ExecState* state, VM& vm, unsigned radix, unsigned charcount)
 {
     ASSERT(2 <= radix && radix <= 36);
     ASSERT(charcount >= 0);
 
     size_t bitsPerChar = maxBitsPerCharTable[radix];
     size_t chars = charcount;
-    const int roundup = bitsPerCharTableMultiplier - 1;
+    const unsigned roundup = bitsPerCharTableMultiplier - 1;
     if (chars <= (std::numeric_limits<size_t>::max() - roundup) / bitsPerChar) {
         size_t bitsMin = bitsPerChar * chars;
 
@@ -678,7 +743,7 @@
         bitsMin = (bitsMin + roundup) >> bitsPerCharTableShift;
         if (bitsMin <= static_cast<size_t>(maxInt)) {
             // Divide by kDigitsBits, rounding up.
-            int length = (static_cast<int>(bitsMin) + digitBits - 1) / digitBits;
+            unsigned length = (bitsMin + digitBits - 1) / digitBits;
             if (length <= maxLength) {
                 JSBigInt* result = JSBigInt::createWithLength(vm, length);
                 return result;
@@ -719,11 +784,11 @@
 }
 
 template <typename CharType>
-JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, int length)
+JSBigInt* JSBigInt::parseInt(ExecState* state, CharType*  data, unsigned length)
 {
     VM& vm = state->vm();
 
-    int p = 0;
+    unsigned p = 0;
     while (p < length && isStrWhiteSpace(data[p]))
         ++p;
 
@@ -758,10 +823,10 @@
 }
 
 template <typename CharType>
-JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, int length, int startIndex, int radix, bool allowEmptyString)
+JSBigInt* JSBigInt::parseInt(ExecState* state, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, bool allowEmptyString)
 {
     ASSERT(length >= 0);
-    int p = startIndex;
+    unsigned p = startIndex;
 
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -777,7 +842,7 @@
 
     int endIndex = length - 1;
     // Removing trailing spaces
-    while (endIndex >= p && isStrWhiteSpace(data[endIndex]))
+    while (endIndex >= static_cast<int>(p) && isStrWhiteSpace(data[endIndex]))
         --endIndex;
 
     length = endIndex + 1;
@@ -785,16 +850,16 @@
     if (p == length)
         return createZero(vm);
 
-    int limit0 = '0' + (radix < 10 ? radix : 10);
-    int limita = 'a' + (radix - 10);
-    int limitA = 'A' + (radix - 10);
+    unsigned limit0 = '0' + (radix < 10 ? radix : 10);
+    unsigned limita = 'a' + (radix - 10);
+    unsigned limitA = 'A' + (radix - 10);
 
     JSBigInt* result = allocateFor(state, vm, radix, length - p);
     RETURN_IF_EXCEPTION(scope, nullptr);
 
     result->initialize(InitializationType::WithZero);
 
-    for (int i = p; i < length; i++, p++) {
+    for (unsigned i = p; i < length; i++, p++) {
         uint32_t digit;
         if (data[i] >= '0' && data[i] < limit0)
             digit = data[i] - '0';
@@ -822,13 +887,13 @@
     return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData());
 }
 
-JSBigInt::Digit JSBigInt::digit(int n)
+JSBigInt::Digit JSBigInt::digit(unsigned n)
 {
     ASSERT(n >= 0 && n < length());
     return dataStorage()[n];
 }
 
-void JSBigInt::setDigit(int n, Digit value)
+void JSBigInt::setDigit(unsigned n, Digit value)
 {
     ASSERT(n >= 0 && n < length());
     dataStorage()[n] = value;
diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h
index 298c348..eb12c00 100644
--- a/Source/JavaScriptCore/runtime/JSBigInt.h
+++ b/Source/JavaScriptCore/runtime/JSBigInt.h
@@ -41,7 +41,7 @@
 
 public:
 
-    JSBigInt(VM&, Structure*, int length);
+    JSBigInt(VM&, Structure*, unsigned length);
 
     enum class InitializationType { None, WithZero };
     void initialize(InitializationType);
@@ -49,12 +49,11 @@
     static void visitChildren(JSCell*, SlotVisitor&);
 
     static size_t estimatedSize(JSCell*);
-    static size_t allocationSize(int length);
+    static size_t allocationSize(unsigned length);
 
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
-
     static JSBigInt* createZero(VM&);
-    static JSBigInt* createWithLength(VM&, int length);
+    static JSBigInt* createWithLength(VM&, unsigned length);
 
     static JSBigInt* createFrom(VM&, int32_t value);
     static JSBigInt* createFrom(VM&, uint32_t value);
@@ -70,14 +69,14 @@
     void setSign(bool sign) { m_sign = sign; }
     bool sign() const { return m_sign; }
 
-    void setLength(int length) { m_length = length; }
-    int length() const { return m_length; }
+    void setLength(unsigned length) { m_length = length; }
+    unsigned length() const { return m_length; }
 
     static JSBigInt* parseInt(ExecState*, VM&, StringView, uint8_t radix);
     static JSBigInt* parseInt(ExecState*, StringView);
 
     std::optional<uint8_t> singleDigitValueForString();
-    String toString(ExecState&, int radix);
+    String toString(ExecState&, unsigned radix);
     
     JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*);
 
@@ -85,12 +84,14 @@
     double toNumber(ExecState*) const;
 
     JSObject* toObject(ExecState*, JSGlobalObject*) const;
+
+    static JSBigInt* multiply(ExecState*, JSBigInt* x, JSBigInt* y);
     
 private:
     using Digit = uintptr_t;
-    static constexpr const int bitsPerByte = 8;
-    static constexpr const int digitBits = sizeof(Digit) * bitsPerByte;
-    static constexpr const int halfDigitBits = digitBits / 2;
+    static constexpr const unsigned bitsPerByte = 8;
+    static constexpr const unsigned digitBits = sizeof(Digit) * bitsPerByte;
+    static constexpr const unsigned halfDigitBits = digitBits / 2;
     static constexpr const Digit halfDigitMask = (1ull << halfDigitBits) - 1;
     static constexpr const int maxInt = 0x7FFFFFFF;
     
@@ -98,12 +99,13 @@
     // maxInt / digitBits. However, we use a lower limit for now, because
     // raising it later is easier than lowering it.
     // Support up to 1 million bits.
-    static const int maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
+    static const unsigned maxLength = 1024 * 1024 / (sizeof(void*) * bitsPerByte);
     
-    static uint64_t calculateMaximumCharactersRequired(int length, int radix, Digit lastDigit, bool sign);
+    static uint64_t calculateMaximumCharactersRequired(unsigned length, unsigned radix, Digit lastDigit, bool sign);
     
     static void absoluteDivSmall(ExecState&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
-    static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, int, JSBigInt* result);
+    static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
+    static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
 
     // Digit arithmetic helpers.
     static Digit digitAdd(Digit a, Digit b, Digit& carry);
@@ -112,17 +114,17 @@
     static Digit digitDiv(Digit high, Digit low, Digit divisor, Digit& remainder);
     static Digit digitPow(Digit base, Digit exponent);
 
-    static String toStringGeneric(ExecState&, JSBigInt*, int radix);
+    static String toStringGeneric(ExecState&, JSBigInt*, unsigned radix);
 
     bool isZero();
 
     template <typename CharType>
-    static JSBigInt* parseInt(ExecState*, CharType*  data, int length);
+    static JSBigInt* parseInt(ExecState*, CharType*  data, unsigned length);
 
     template <typename CharType>
-    static JSBigInt* parseInt(ExecState*, VM&, CharType* data, int length, int startIndex, int radix, bool allowEmptyString = true);
+    static JSBigInt* parseInt(ExecState*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, bool allowEmptyString = true);
 
-    static JSBigInt* allocateFor(ExecState*, VM&, int radix, int charcount);
+    static JSBigInt* allocateFor(ExecState*, VM&, unsigned radix, unsigned charcount);
 
     JSBigInt* rightTrim(VM&);
 
@@ -131,10 +133,10 @@
     static size_t offsetOfData();
     Digit* dataStorage();
 
-    Digit digit(int);
-    void setDigit(int, Digit);
+    Digit digit(unsigned);
+    void setDigit(unsigned, Digit);
         
-    int m_length;
+    unsigned m_length;
     bool m_sign;
 };
 
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index 1349aec..e265815 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -23,6 +23,7 @@
 
 #include "CallFrame.h"
 #include "ExceptionHelpers.h"
+#include "JSBigInt.h"
 #include "JSCJSValue.h"
 
 namespace JSC {
@@ -256,6 +257,31 @@
     return jsAddSlowCase(callFrame, v1, v2);
 }
 
+ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
+{
+    VM& vm = state->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue leftNumber = v1.toPrimitive(state, PreferNumber);
+    RETURN_IF_EXCEPTION(scope, { });
+    JSValue rightNumber = v2.toPrimitive(state, PreferNumber);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    if (leftNumber.isBigInt() || rightNumber.isBigInt()) {
+        if (leftNumber.isBigInt() && rightNumber.isBigInt())
+            return JSBigInt::multiply(state, asBigInt(leftNumber), asBigInt(rightNumber));
+
+        throwTypeError(state, scope, ASCIILiteral("Invalid mix of BigInt and other type in multiplication."));
+        return { };
+    }
+
+    double leftValue =  leftNumber.toNumber(state);
+    RETURN_IF_EXCEPTION(scope, { });
+    double rightValue =  rightNumber.toNumber(state);
+    RETURN_IF_EXCEPTION(scope, { });
+    return jsNumber(leftValue * rightValue);
+}
+
 inline bool scribbleFreeCells()
 {
     return !ASSERT_DISABLED || Options::scribbleFreeCells();