[BigInt] JSBigInt::createWithLength should throw when length is greater than JSBigInt...
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2018 15:46:34 +0000 (15:46 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2018 15:46:34 +0000 (15:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190836

Reviewed by Saam Barati.

JSTests:

* stress/big-int-out-of-memory-tests.js: Added.

Source/JavaScriptCore:

In this patch we are creating a new method called `JSBigInt::createWithLengthUnchecked`
where we allocate a BigInt trusting the length received as argument.
With this additional method, we now check if length passed to
`JSBigInt::createWithLength` is not greater than JSBigInt::maxLength.
When the length is greater than maxLength, we then throw OOM
exception.
This required change the interface of some JSBigInt operations to
receive `ExecState*` instead of `VM&`. We changed only operations that
can throw because of OOM.
We beleive that this approach of throwing instead of finishing the
execution abruptly is better because JS programs can catch such
exception and handle this issue properly.

* dfg/DFGOperations.cpp:
* jit/JITOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::createZero):
(JSC::JSBigInt::tryCreateWithLength):
(JSC::JSBigInt::createWithLengthUnchecked):
(JSC::JSBigInt::createFrom):
(JSC::JSBigInt::multiply):
(JSC::JSBigInt::divide):
(JSC::JSBigInt::copy):
(JSC::JSBigInt::unaryMinus):
(JSC::JSBigInt::remainder):
(JSC::JSBigInt::add):
(JSC::JSBigInt::sub):
(JSC::JSBigInt::bitwiseAnd):
(JSC::JSBigInt::bitwiseOr):
(JSC::JSBigInt::bitwiseXor):
(JSC::JSBigInt::absoluteAdd):
(JSC::JSBigInt::absoluteSub):
(JSC::JSBigInt::absoluteDivWithDigitDivisor):
(JSC::JSBigInt::absoluteDivWithBigIntDivisor):
(JSC::JSBigInt::absoluteLeftShiftAlwaysCopy):
(JSC::JSBigInt::absoluteBitwiseOp):
(JSC::JSBigInt::absoluteAddOne):
(JSC::JSBigInt::absoluteSubOne):
(JSC::JSBigInt::toStringGeneric):
(JSC::JSBigInt::rightTrim):
(JSC::JSBigInt::allocateFor):
(JSC::JSBigInt::createWithLength): Deleted.
* runtime/JSBigInt.h:
* runtime/Operations.cpp:
(JSC::jsAddSlowCase):
* runtime/Operations.h:
(JSC::jsSub):
(JSC::jsMul):

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

JSTests/ChangeLog
JSTests/stress/big-int-out-of-memory-tests.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/JSBigInt.cpp
Source/JavaScriptCore/runtime/JSBigInt.h
Source/JavaScriptCore/runtime/Operations.cpp
Source/JavaScriptCore/runtime/Operations.h

index 77dc666..436683e 100644 (file)
@@ -1,3 +1,12 @@
+2018-11-13  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] JSBigInt::createWithLength should throw when length is greater than JSBigInt::maxLength
+        https://bugs.webkit.org/show_bug.cgi?id=190836
+
+        Reviewed by Saam Barati.
+
+        * stress/big-int-out-of-memory-tests.js: Added.
+
 2018-11-08  Ross Kirsling  <ross.kirsling@sony.com>
 
         U+180E is no longer a whitespace character
 2018-11-08  Ross Kirsling  <ross.kirsling@sony.com>
 
         U+180E is no longer a whitespace character
diff --git a/JSTests/stress/big-int-out-of-memory-tests.js b/JSTests/stress/big-int-out-of-memory-tests.js
new file mode 100644 (file)
index 0000000..ac39387
--- /dev/null
@@ -0,0 +1,63 @@
+//@ runDefault("--useBigInt=true", "--useDFGJIT=false")
+
+function assert(a, message) {
+    if (!a)
+        throw new Error(message);
+}
+
+function lshift(y) {
+    let out = 1n;
+    for (let i = 0; i < y; i++) {
+        out *= 2n;
+    }
+
+    return out;
+}
+
+let a = lshift(16384 * 63);
+for (let i = 0; i < 256; i++) {
+    a *= 18446744073709551615n;
+}
+
+try {
+    let b = a + 1n;
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
+try {
+    let b = a - (-1n);
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
+try {
+    let b = a * (-1n);
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
+try {
+    let b = a / a;
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
+try {
+    let b = -a & -1n;
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
+try {
+    let b = a ^ -1n;
+    assert(false, "Should throw OutOfMemoryError, but executed without exception");
+} catch(e) {
+    assert(e.message == "Out of memory", "Expected OutOfMemoryError, but got: " + e);
+}
+
index 10158d4..f8e59b6 100644 (file)
@@ -1,3 +1,61 @@
+2018-11-13  Caio Lima  <ticaiolima@gmail.com>
+
+        [BigInt] JSBigInt::createWithLength should throw when length is greater than JSBigInt::maxLength
+        https://bugs.webkit.org/show_bug.cgi?id=190836
+
+        Reviewed by Saam Barati.
+
+        In this patch we are creating a new method called `JSBigInt::createWithLengthUnchecked`
+        where we allocate a BigInt trusting the length received as argument.
+        With this additional method, we now check if length passed to
+        `JSBigInt::createWithLength` is not greater than JSBigInt::maxLength.
+        When the length is greater than maxLength, we then throw OOM
+        exception.
+        This required change the interface of some JSBigInt operations to
+        receive `ExecState*` instead of `VM&`. We changed only operations that
+        can throw because of OOM.
+        We beleive that this approach of throwing instead of finishing the
+        execution abruptly is better because JS programs can catch such
+        exception and handle this issue properly.
+
+        * dfg/DFGOperations.cpp:
+        * jit/JITOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::createZero):
+        (JSC::JSBigInt::tryCreateWithLength):
+        (JSC::JSBigInt::createWithLengthUnchecked):
+        (JSC::JSBigInt::createFrom):
+        (JSC::JSBigInt::multiply):
+        (JSC::JSBigInt::divide):
+        (JSC::JSBigInt::copy):
+        (JSC::JSBigInt::unaryMinus):
+        (JSC::JSBigInt::remainder):
+        (JSC::JSBigInt::add):
+        (JSC::JSBigInt::sub):
+        (JSC::JSBigInt::bitwiseAnd):
+        (JSC::JSBigInt::bitwiseOr):
+        (JSC::JSBigInt::bitwiseXor):
+        (JSC::JSBigInt::absoluteAdd):
+        (JSC::JSBigInt::absoluteSub):
+        (JSC::JSBigInt::absoluteDivWithDigitDivisor):
+        (JSC::JSBigInt::absoluteDivWithBigIntDivisor):
+        (JSC::JSBigInt::absoluteLeftShiftAlwaysCopy):
+        (JSC::JSBigInt::absoluteBitwiseOp):
+        (JSC::JSBigInt::absoluteAddOne):
+        (JSC::JSBigInt::absoluteSubOne):
+        (JSC::JSBigInt::toStringGeneric):
+        (JSC::JSBigInt::rightTrim):
+        (JSC::JSBigInt::allocateFor):
+        (JSC::JSBigInt::createWithLength): Deleted.
+        * runtime/JSBigInt.h:
+        * runtime/Operations.cpp:
+        (JSC::jsAddSlowCase):
+        * runtime/Operations.h:
+        (JSC::jsSub):
+        (JSC::jsMul):
+
 2018-11-12  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Network: show secure certificate details per-request
 2018-11-12  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Network: show secure certificate details per-request
index df3fd1e..5417fb0 100644 (file)
@@ -349,7 +349,7 @@ EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValu
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
 
     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::bitwiseAnd(*vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             RETURN_IF_EXCEPTION(scope, encodedJSValue());
             return JSValue::encode(result);
         }
             RETURN_IF_EXCEPTION(scope, encodedJSValue());
             return JSValue::encode(result);
         }
@@ -376,7 +376,7 @@ EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
 
     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::bitwiseOr(*vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             RETURN_IF_EXCEPTION(scope, encodedJSValue());
             return JSValue::encode(result);
         }
             RETURN_IF_EXCEPTION(scope, encodedJSValue());
             return JSValue::encode(result);
         }
@@ -1294,7 +1294,7 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState* exec, JSCell* op1, JSCell* o
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
-    return JSBigInt::sub(*vm, leftOperand, rightOperand);
+    return JSBigInt::sub(exec, leftOperand, rightOperand);
 }
 
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 }
 
 JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
@@ -1305,7 +1305,7 @@ JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
 
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
 
-    return JSBigInt::bitwiseAnd(*vm, leftOperand, rightOperand);
+    return JSBigInt::bitwiseAnd(exec, leftOperand, rightOperand);
 }
 
 JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 }
 
 JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
@@ -1316,7 +1316,7 @@ JSCell* JIT_OPERATION operationAddBigInt(ExecState* exec, JSCell* op1, JSCell* o
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
-    return JSBigInt::add(*vm, leftOperand, rightOperand);
+    return JSBigInt::add(exec, leftOperand, rightOperand);
 }
 
 JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
 }
 
 JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell* op2)
@@ -1327,7 +1327,7 @@ JSCell* JIT_OPERATION operationBitOrBigInt(ExecState* exec, JSCell* op1, JSCell*
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
     JSBigInt* leftOperand = jsCast<JSBigInt*>(op1);
     JSBigInt* rightOperand = jsCast<JSBigInt*>(op2);
     
-    return JSBigInt::bitwiseOr(*vm, leftOperand, rightOperand);
+    return JSBigInt::bitwiseOr(exec, leftOperand, rightOperand);
 }
 
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2)
 }
 
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, JSCell* op1, JSCell* op2)
index 1e8fe00..511c42f 100644 (file)
@@ -2766,10 +2766,8 @@ EncodedJSValue JIT_OPERATION operationArithNegateOptimize(ExecState* exec, Encod
     JSValue primValue = operand.toPrimitive(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     
     JSValue primValue = operand.toPrimitive(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     
-    if (primValue.isBigInt()) {
-        JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
-        return JSValue::encode(result);
-    }
+    if (primValue.isBigInt())
+        return JSValue::encode(JSBigInt::unaryMinus(vm, asBigInt(primValue)));
 
     double number = primValue.toNumber(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
     double number = primValue.toNumber(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
index 5163c33..ee5ada2 100644 (file)
@@ -563,7 +563,8 @@ SLOW_PATH_DECL(slow_path_sub)
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::sub(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::sub(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            CHECK_EXCEPTION();
             RETURN_WITH_PROFILING(result, {
                 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
             });
             RETURN_WITH_PROFILING(result, {
                 updateArithProfileForBinaryArithOp(exec, pc, result, left, right);
             });
@@ -699,7 +700,7 @@ SLOW_PATH_DECL(slow_path_bitand)
     CHECK_EXCEPTION();
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     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::bitwiseAnd(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
             RETURN_PROFILED(result);
         }
             CHECK_EXCEPTION();
             RETURN_PROFILED(result);
         }
@@ -720,7 +721,7 @@ SLOW_PATH_DECL(slow_path_bitor)
     CHECK_EXCEPTION();
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     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::bitwiseOr(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
             RETURN_PROFILED(result);
         }
             CHECK_EXCEPTION();
             RETURN_PROFILED(result);
         }
@@ -741,7 +742,7 @@ SLOW_PATH_DECL(slow_path_bitxor)
     CHECK_EXCEPTION();
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
         if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     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::bitwiseXor(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+            JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             CHECK_EXCEPTION();
             RETURN(result);
         }
             CHECK_EXCEPTION();
             RETURN(result);
         }
index 4ab5a52..0c6f40d 100644 (file)
@@ -81,7 +81,7 @@ Structure* JSBigInt::createStructure(VM& vm, JSGlobalObject* globalObject, JSVal
 
 JSBigInt* JSBigInt::createZero(VM& vm)
 {
 
 JSBigInt* JSBigInt::createZero(VM& vm)
 {
-    JSBigInt* zeroBigInt = createWithLength(vm, 0);
+    JSBigInt* zeroBigInt = createWithLengthUnchecked(vm, 0);
     return zeroBigInt;
 }
 
     return zeroBigInt;
 }
 
@@ -91,7 +91,22 @@ inline size_t JSBigInt::allocationSize(unsigned length)
     return sizeWithPadding + length * sizeof(Digit);
 }
 
     return sizeWithPadding + length * sizeof(Digit);
 }
 
-JSBigInt* JSBigInt::createWithLength(VM& vm, unsigned length)
+JSBigInt* JSBigInt::tryCreateWithLength(ExecState* exec, unsigned length)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (UNLIKELY(length > maxLength)) {
+        throwOutOfMemoryError(exec, scope);
+        return nullptr;
+    }
+
+    scope.release();
+
+    return createWithLengthUnchecked(vm, length);
+}
+
+JSBigInt* JSBigInt::createWithLengthUnchecked(VM& vm, unsigned length)
 {
     JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
     bigInt->finishCreation(vm);
 {
     JSBigInt* bigInt = new (NotNull, allocateCell<JSBigInt>(vm.heap, allocationSize(length))) JSBigInt(vm, vm.bigIntStructure.get(), length);
     bigInt->finishCreation(vm);
@@ -103,8 +118,7 @@ JSBigInt* JSBigInt::createFrom(VM& vm, int32_t value)
     if (!value)
         return createZero(vm);
     
     if (!value)
         return createZero(vm);
     
-    JSBigInt* bigInt = createWithLength(vm, 1);
-    
+    JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
     if (value < 0) {
         bigInt->setDigit(0, static_cast<Digit>(-1 * static_cast<int64_t>(value)));
         bigInt->setSign(true);
     if (value < 0) {
         bigInt->setDigit(0, static_cast<Digit>(-1 * static_cast<int64_t>(value)));
         bigInt->setSign(true);
@@ -119,7 +133,7 @@ JSBigInt* JSBigInt::createFrom(VM& vm, uint32_t value)
     if (!value)
         return createZero(vm);
     
     if (!value)
         return createZero(vm);
     
-    JSBigInt* bigInt = createWithLength(vm, 1);
+    JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
     bigInt->setDigit(0, static_cast<Digit>(value));
     return bigInt;
 }
     bigInt->setDigit(0, static_cast<Digit>(value));
     return bigInt;
 }
@@ -130,8 +144,7 @@ JSBigInt* JSBigInt::createFrom(VM& vm, int64_t value)
         return createZero(vm);
     
     if (sizeof(Digit) == 8) {
         return createZero(vm);
     
     if (sizeof(Digit) == 8) {
-        JSBigInt* bigInt = createWithLength(vm, 1);
-        
+        JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
         if (value < 0) {
             bigInt->setDigit(0, static_cast<Digit>(static_cast<uint64_t>(-(value + 1)) + 1));
             bigInt->setSign(true);
         if (value < 0) {
             bigInt->setDigit(0, static_cast<Digit>(static_cast<uint64_t>(-(value + 1)) + 1));
             bigInt->setSign(true);
@@ -141,8 +154,7 @@ JSBigInt* JSBigInt::createFrom(VM& vm, int64_t value)
         return bigInt;
     }
     
         return bigInt;
     }
     
-    JSBigInt* bigInt = createWithLength(vm, 2);
-    
+    JSBigInt* bigInt = createWithLengthUnchecked(vm, 2);
     uint64_t tempValue;
     bool sign = false;
     if (value < 0) {
     uint64_t tempValue;
     bool sign = false;
     if (value < 0) {
@@ -166,7 +178,7 @@ JSBigInt* JSBigInt::createFrom(VM& vm, bool value)
     if (!value)
         return createZero(vm);
     
     if (!value)
         return createZero(vm);
     
-    JSBigInt* bigInt = createWithLength(vm, 1);
+    JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
     bigInt->setDigit(0, static_cast<Digit>(value));
     return bigInt;
 }
     bigInt->setDigit(0, static_cast<Digit>(value));
     return bigInt;
 }
@@ -234,6 +246,7 @@ void JSBigInt::inplaceMultiplyAdd(Digit factor, Digit summand)
 JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
     VM& vm = exec->vm();
 JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
     VM& vm = exec->vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
 
     if (x->isZero())
         return x;
 
     if (x->isZero())
         return x;
@@ -241,7 +254,8 @@ JSBigInt* JSBigInt::multiply(ExecState* exec, JSBigInt* x, JSBigInt* y)
         return y;
 
     unsigned resultLength = x->length() + y->length();
         return y;
 
     unsigned resultLength = x->length() + y->length();
-    JSBigInt* result = JSBigInt::createWithLength(vm, resultLength);
+    JSBigInt* result = JSBigInt::tryCreateWithLength(exec, resultLength);
+    RETURN_IF_EXCEPTION(scope, nullptr);
     result->initialize(InitializationType::WithZero);
 
     for (unsigned i = 0; i < x->length(); i++)
     result->initialize(InitializationType::WithZero);
 
     for (unsigned i = 0; i < x->length(); i++)
@@ -277,8 +291,10 @@ JSBigInt* JSBigInt::divide(ExecState* exec, JSBigInt* x, JSBigInt* y)
 
         Digit remainder;
         absoluteDivWithDigitDivisor(vm, x, divisor, &quotient, remainder);
 
         Digit remainder;
         absoluteDivWithDigitDivisor(vm, x, divisor, &quotient, remainder);
-    } else
-        absoluteDivWithBigIntDivisor(vm, x, y, &quotient, nullptr);
+    } else {
+        absoluteDivWithBigIntDivisor(exec, x, y, &quotient, nullptr);
+        RETURN_IF_EXCEPTION(scope, nullptr);
+    }
 
     quotient->setSign(resultSign);
     return quotient->rightTrim(vm);
 
     quotient->setSign(resultSign);
     return quotient->rightTrim(vm);
@@ -288,7 +304,7 @@ JSBigInt* JSBigInt::copy(VM& vm, JSBigInt* x)
 {
     ASSERT(!x->isZero());
 
 {
     ASSERT(!x->isZero());
 
-    JSBigInt* result = JSBigInt::createWithLength(vm, x->length());
+    JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, x->length());
     std::copy(x->dataStorage(), x->dataStorage() + x->length(), result->dataStorage());
     result->setSign(x->sign());
     return result;
     std::copy(x->dataStorage(), x->dataStorage() + x->length(), result->dataStorage());
     result->setSign(x->sign());
     return result;
@@ -331,23 +347,26 @@ JSBigInt* JSBigInt::remainder(ExecState* exec, JSBigInt* x, JSBigInt* y)
         if (!remainderDigit)
             return createZero(vm);
 
         if (!remainderDigit)
             return createZero(vm);
 
-        remainder = createWithLength(vm, 1);
+        remainder = createWithLengthUnchecked(vm, 1);
         remainder->setDigit(0, remainderDigit);
         remainder->setDigit(0, remainderDigit);
-    } else
-        absoluteDivWithBigIntDivisor(vm, x, y, nullptr, &remainder);
+    } else {
+        absoluteDivWithBigIntDivisor(exec, x, y, nullptr, &remainder);
+        RETURN_IF_EXCEPTION(scope, nullptr);
+    }
 
     remainder->setSign(x->sign());
     return remainder->rightTrim(vm);
 }
 
 
     remainder->setSign(x->sign());
     return remainder->rightTrim(vm);
 }
 
-JSBigInt* JSBigInt::add(VM& vm, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::add(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
 {
+    VM& vm = exec->vm();
     bool xSign = x->sign();
 
     // x + y == x + y
     // -x + -y == -(x + y)
     if (xSign == y->sign())
     bool xSign = x->sign();
 
     // x + y == x + y
     // -x + -y == -(x + y)
     if (xSign == y->sign())
-        return absoluteAdd(vm, x, y, xSign);
+        return absoluteAdd(exec, x, y, xSign);
 
     // x + -y == x - y == -(y - x)
     // -x + y == y - x == -(x - y)
 
     // x + -y == x - y == -(y - x)
     // -x + y == y - x == -(x - y)
@@ -358,13 +377,14 @@ JSBigInt* JSBigInt::add(VM& vm, JSBigInt* x, JSBigInt* y)
     return absoluteSub(vm, y, x, !xSign);
 }
 
     return absoluteSub(vm, y, x, !xSign);
 }
 
-JSBigInt* JSBigInt::sub(VM& vm, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::sub(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
 {
+    VM& vm = exec->vm();
     bool xSign = x->sign();
     if (xSign != y->sign()) {
         // x - (-y) == x + y
         // (-x) - y == -(x + y)
     bool xSign = x->sign();
     if (xSign != y->sign()) {
         // x - (-y) == x + y
         // (-x) - y == -(x + y)
-        return absoluteAdd(vm, x, y, xSign);
+        return absoluteAdd(exec, x, y, xSign);
     }
     // x - y == -(y - x)
     // (-x) - (-y) == y - x == -(x - y)
     }
     // x - y == -(y - x)
     // (-x) - (-y) == y - x == -(x - y)
@@ -375,8 +395,11 @@ JSBigInt* JSBigInt::sub(VM& vm, JSBigInt* x, JSBigInt* y)
     return absoluteSub(vm, y, x, !xSign);
 }
 
     return absoluteSub(vm, y, x, !xSign);
 }
 
-JSBigInt* JSBigInt::bitwiseAnd(VM& vm, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::bitwiseAnd(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
 {
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
     if (!x->sign() && !y->sign())
         return absoluteAnd(vm, x, y);
     
     if (!x->sign() && !y->sign())
         return absoluteAnd(vm, x, y);
     
@@ -384,11 +407,14 @@ JSBigInt* JSBigInt::bitwiseAnd(VM& vm, JSBigInt* x, JSBigInt* y)
         int resultLength = std::max(x->length(), y->length()) + 1;
         // (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
         // == -(((x-1) | (y-1)) + 1)
         int resultLength = std::max(x->length(), y->length()) + 1;
         // (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1))
         // == -(((x-1) | (y-1)) + 1)
-        JSBigInt* result = absoluteSubOne(vm, x, resultLength);
-        JSBigInt* y1 = absoluteSubOne(vm, y, y->length());
-        result = absoluteOr(vm, result, y1);
+        JSBigInt* result = absoluteSubOne(exec, x, resultLength);
+        RETURN_IF_EXCEPTION(scope, nullptr);
 
 
-        return absoluteAddOne(vm, result, SignOption::Signed);
+        JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
+        ASSERT(y1);
+        result = absoluteOr(vm, result, y1);
+        scope.release();
+        return absoluteAddOne(exec, result, SignOption::Signed);
     }
 
     ASSERT(x->sign() != y->sign());
     }
 
     ASSERT(x->sign() != y->sign());
@@ -397,11 +423,15 @@ JSBigInt* JSBigInt::bitwiseAnd(VM& vm, JSBigInt* x, JSBigInt* y)
         std::swap(x, y);
     
     // x & (-y) == x & ~(y-1) == x & ~(y-1)
         std::swap(x, y);
     
     // x & (-y) == x & ~(y-1) == x & ~(y-1)
-    return absoluteAndNot(vm, x, absoluteSubOne(vm, y, y->length()));
+    JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
+    ASSERT(y1);
+    return absoluteAndNot(vm, x, y1);
 }
 
 }
 
-JSBigInt* JSBigInt::bitwiseOr(VM& vm, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::bitwiseOr(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
 {
+    VM& vm = exec->vm();
+
     unsigned resultLength = std::max(x->length(), y->length());
 
     if (!x->sign() && !y->sign())
     unsigned resultLength = std::max(x->length(), y->length());
 
     if (!x->sign() && !y->sign())
@@ -410,10 +440,12 @@ JSBigInt* JSBigInt::bitwiseOr(VM& vm, JSBigInt* x, JSBigInt* y)
     if (x->sign() && y->sign()) {
         // (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
         // == -(((x-1) & (y-1)) + 1)
     if (x->sign() && y->sign()) {
         // (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1))
         // == -(((x-1) & (y-1)) + 1)
-        JSBigInt* result = absoluteSubOne(vm, x, resultLength);
-        JSBigInt* y1 = absoluteSubOne(vm, y, y->length());
+        JSBigInt* result = absoluteSubOne(exec, x, resultLength);
+        ASSERT(result);
+        JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
+        ASSERT(y1);
         result = absoluteAnd(vm, result, y1);
         result = absoluteAnd(vm, result, y1);
-        return absoluteAddOne(vm, result, SignOption::Signed);
+        return absoluteAddOne(exec, result, SignOption::Signed);
     }
     
     ASSERT(x->sign() != y->sign());
     }
     
     ASSERT(x->sign() != y->sign());
@@ -423,13 +455,17 @@ JSBigInt* JSBigInt::bitwiseOr(VM& vm, JSBigInt* x, JSBigInt* y)
         std::swap(x, y);
     
     // x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
         std::swap(x, y);
     
     // x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1)
-    JSBigInt* result = absoluteSubOne(vm, y, resultLength);
+    JSBigInt* result = absoluteSubOne(exec, y, resultLength);
+    ASSERT(result);
     result = absoluteAndNot(vm, result, x);
     result = absoluteAndNot(vm, result, x);
-    return absoluteAddOne(vm, result, SignOption::Signed);
+    return absoluteAddOne(exec, result, SignOption::Signed);
 }
 
 }
 
-JSBigInt* JSBigInt::bitwiseXor(VM& vm, JSBigInt* x, JSBigInt* y)
+JSBigInt* JSBigInt::bitwiseXor(ExecState* exec, JSBigInt* x, JSBigInt* y)
 {
 {
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
     if (!x->sign() && !y->sign())
         return absoluteXor(vm, x, y);
     
     if (!x->sign() && !y->sign())
         return absoluteXor(vm, x, y);
     
@@ -437,8 +473,10 @@ JSBigInt* JSBigInt::bitwiseXor(VM& vm, JSBigInt* x, JSBigInt* y)
         int resultLength = std::max(x->length(), y->length());
         
         // (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
         int resultLength = std::max(x->length(), y->length());
         
         // (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1)
-        JSBigInt* result = absoluteSubOne(vm, x, resultLength);
-        JSBigInt* y1 = absoluteSubOne(vm, y, y->length());
+        JSBigInt* result = absoluteSubOne(exec, x, resultLength);
+        ASSERT(result);
+        JSBigInt* y1 = absoluteSubOne(exec, y, y->length());
+        ASSERT(y1);
         return absoluteXor(vm, result, y1);
     }
     ASSERT(x->sign() != y->sign());
         return absoluteXor(vm, result, y1);
     }
     ASSERT(x->sign() != y->sign());
@@ -449,9 +487,12 @@ JSBigInt* JSBigInt::bitwiseXor(VM& vm, JSBigInt* x, JSBigInt* y)
         std::swap(x, y);
     
     // x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
         std::swap(x, y);
     
     // x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1)
-    JSBigInt* result = absoluteSubOne(vm, y, resultLength);
+    JSBigInt* result = absoluteSubOne(exec, y, resultLength);
+    RETURN_IF_EXCEPTION(scope, nullptr);
+
     result = absoluteXor(vm, result, x);
     result = absoluteXor(vm, result, x);
-    return absoluteAddOne(vm, result, SignOption::Signed);
+    scope.release();
+    return absoluteAddOne(exec, result, SignOption::Signed);
 }
 
 #if USE(JSVALUE32_64)
 }
 
 #if USE(JSVALUE32_64)
@@ -751,10 +792,12 @@ inline JSBigInt::ComparisonResult JSBigInt::absoluteCompare(JSBigInt* x, JSBigIn
     return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
 }
 
     return x->digit(i) > y->digit(i) ? ComparisonResult::GreaterThan : ComparisonResult::LessThan;
 }
 
-JSBigInt* JSBigInt::absoluteAdd(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSign)
+JSBigInt* JSBigInt::absoluteAdd(ExecState* exec, JSBigInt* x, JSBigInt* y, bool resultSign)
 {
 {
+    VM& vm = exec->vm();
+
     if (x->length() < y->length())
     if (x->length() < y->length())
-        return absoluteAdd(vm, y, x, resultSign);
+        return absoluteAdd(exec, y, x, resultSign);
 
     if (x->isZero()) {
         ASSERT(y->isZero());
 
     if (x->isZero()) {
         ASSERT(y->isZero());
@@ -764,8 +807,9 @@ JSBigInt* JSBigInt::absoluteAdd(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSig
     if (y->isZero())
         return resultSign == x->sign() ? x : unaryMinus(vm, x);
 
     if (y->isZero())
         return resultSign == x->sign() ? x : unaryMinus(vm, x);
 
-    JSBigInt* result = JSBigInt::createWithLength(vm, x->length() + 1);
-    ASSERT(result);
+    JSBigInt* result = JSBigInt::tryCreateWithLength(exec, x->length() + 1);
+    if (!result)
+        return nullptr;
     Digit carry = 0;
     unsigned i = 0;
     for (; i < y->length(); i++) {
     Digit carry = 0;
     unsigned i = 0;
     for (; i < y->length(); i++) {
@@ -806,7 +850,8 @@ JSBigInt* JSBigInt::absoluteSub(VM& vm, JSBigInt* x, JSBigInt* y, bool resultSig
     if (comparisonResult == ComparisonResult::Equal)
         return JSBigInt::createZero(vm);
 
     if (comparisonResult == ComparisonResult::Equal)
         return JSBigInt::createZero(vm);
 
-    JSBigInt* result = JSBigInt::createWithLength(vm, x->length());
+    JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, x->length());
+
     Digit borrow = 0;
     unsigned i = 0;
     for (; i < y->length(); i++) {
     Digit borrow = 0;
     unsigned i = 0;
     for (; i < y->length(); i++) {
@@ -851,7 +896,7 @@ void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, J
     unsigned length = x->length();
     if (quotient != nullptr) {
         if (*quotient == nullptr)
     unsigned length = x->length();
     if (quotient != nullptr) {
         if (*quotient == nullptr)
-            *quotient = JSBigInt::createWithLength(vm, length);
+            *quotient = JSBigInt::createWithLengthUnchecked(vm, length);
 
         for (int i = length - 1; i >= 0; i--) {
             Digit q = digitDiv(remainder, x->digit(i), divisor, remainder);
 
         for (int i = length - 1; i >= 0; i--) {
             Digit q = digitDiv(remainder, x->digit(i), divisor, remainder);
@@ -869,10 +914,12 @@ void JSBigInt::absoluteDivWithDigitDivisor(VM& vm, JSBigInt* x, Digit divisor, J
 // Both {quotient} and {remainder} are optional, for callers that are only
 // interested in one of them.
 // See Knuth, Volume 2, section 4.3.1, Algorithm D.
 // Both {quotient} and {remainder} are optional, for callers that are only
 // interested in one of them.
 // See Knuth, Volume 2, section 4.3.1, Algorithm D.
-void JSBigInt::absoluteDivWithBigIntDivisor(VM& vm, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder)
+void JSBigInt::absoluteDivWithBigIntDivisor(ExecState* exec, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder)
 {
     ASSERT(divisor->length() >= 2);
     ASSERT(dividend->length() >= divisor->length());
 {
     ASSERT(divisor->length() >= 2);
     ASSERT(dividend->length() >= divisor->length());
+    VM& vm = exec->vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
 
     // The unusual variable names inside this function are consistent with
     // Knuth's book, as well as with Go's implementation of this algorithm.
 
     // The unusual variable names inside this function are consistent with
     // Knuth's book, as well as with Go's implementation of this algorithm.
@@ -884,11 +931,12 @@ void JSBigInt::absoluteDivWithBigIntDivisor(VM& vm, JSBigInt* dividend, JSBigInt
     // The quotient to be computed.
     JSBigInt* q = nullptr;
     if (quotient != nullptr)
     // The quotient to be computed.
     JSBigInt* q = nullptr;
     if (quotient != nullptr)
-        q = createWithLength(vm, m + 1);
+        q = createWithLengthUnchecked(exec->vm(), m + 1);
     
     // In each iteration, {qhatv} holds {divisor} * {current quotient digit}.
     // "v" is the book's name for {divisor}, "qhat" the current quotient digit.
     
     // In each iteration, {qhatv} holds {divisor} * {current quotient digit}.
     // "v" is the book's name for {divisor}, "qhat" the current quotient digit.
-    JSBigInt* qhatv = createWithLength(vm, n + 1);
+    JSBigInt* qhatv = tryCreateWithLength(exec, n + 1);
+    RETURN_IF_EXCEPTION(scope, void());
     
     // D1.
     // Left-shift inputs so that the divisor's MSB is set. This is necessary
     
     // D1.
     // Left-shift inputs so that the divisor's MSB is set. This is necessary
@@ -898,12 +946,15 @@ void JSBigInt::absoluteDivWithBigIntDivisor(VM& vm, JSBigInt* dividend, JSBigInt
     Digit lastDigit = divisor->digit(n - 1);
     unsigned shift = sizeof(lastDigit) == 8 ? clz64(lastDigit) : clz32(lastDigit);
 
     Digit lastDigit = divisor->digit(n - 1);
     unsigned shift = sizeof(lastDigit) == 8 ? clz64(lastDigit) : clz32(lastDigit);
 
-    if (shift > 0)
-        divisor = absoluteLeftShiftAlwaysCopy(vm, divisor, shift, LeftShiftMode::SameSizeResult);
+    if (shift > 0) {
+        divisor = absoluteLeftShiftAlwaysCopy(exec, divisor, shift, LeftShiftMode::SameSizeResult);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
 
     // Holds the (continuously updated) remaining part of the dividend, which
     // eventually becomes the remainder.
 
     // Holds the (continuously updated) remaining part of the dividend, which
     // eventually becomes the remainder.
-    JSBigInt* u = absoluteLeftShiftAlwaysCopy(vm, dividend, shift, LeftShiftMode::AlwaysAddOneDigit);
+    JSBigInt* u = absoluteLeftShiftAlwaysCopy(exec, dividend, shift, LeftShiftMode::AlwaysAddOneDigit);
+    RETURN_IF_EXCEPTION(scope, void());
 
     // D2.
     // Iterate over the dividend's digit (like the "grad school" algorithm).
 
     // D2.
     // Iterate over the dividend's digit (like the "grad school" algorithm).
@@ -1031,14 +1082,16 @@ void JSBigInt::inplaceRightShift(unsigned shift)
 }
 
 // Always copies the input, even when {shift} == 0.
 }
 
 // Always copies the input, even when {shift} == 0.
-JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(VM& vm, JSBigInt* x, unsigned shift, LeftShiftMode mode)
+JSBigInt* JSBigInt::absoluteLeftShiftAlwaysCopy(ExecState* exec, JSBigInt* x, unsigned shift, LeftShiftMode mode)
 {
     ASSERT(shift < digitBits);
     ASSERT(!x->isZero());
 
     unsigned n = x->length();
     unsigned resultLength = mode == LeftShiftMode::AlwaysAddOneDigit ? n + 1 : n;
 {
     ASSERT(shift < digitBits);
     ASSERT(!x->isZero());
 
     unsigned n = x->length();
     unsigned resultLength = mode == LeftShiftMode::AlwaysAddOneDigit ? n + 1 : n;
-    JSBigInt* result = createWithLength(vm, resultLength);
+    JSBigInt* result = tryCreateWithLength(exec, resultLength);
+    if (!result)
+        return nullptr;
 
     if (!shift) {
         for (unsigned i = 0; i < n; i++)
 
     if (!shift) {
         for (unsigned i = 0; i < n; i++)
@@ -1095,8 +1148,7 @@ inline JSBigInt* JSBigInt::absoluteBitwiseOp(VM& vm, JSBigInt* x, JSBigInt* y, E
 
     ASSERT(numPairs == std::min(xLength, yLength));
     unsigned resultLength = extraDigits == ExtraDigitsHandling::Copy ? xLength : numPairs;
 
     ASSERT(numPairs == std::min(xLength, yLength));
     unsigned resultLength = extraDigits == ExtraDigitsHandling::Copy ? xLength : numPairs;
-    JSBigInt* result = createWithLength(vm, resultLength);
-
+    JSBigInt* result = createWithLengthUnchecked(vm, resultLength);
     unsigned i = 0;
     for (; i < numPairs; i++)
         result->setDigit(i, op(x->digit(i), y->digit(i)));
     unsigned i = 0;
     for (; i < numPairs; i++)
         result->setDigit(i, op(x->digit(i), y->digit(i)));
@@ -1144,7 +1196,7 @@ JSBigInt* JSBigInt::absoluteXor(VM& vm, JSBigInt* x, JSBigInt* y)
     return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Copy, SymmetricOp::Symmetric, digitOperation);
 }
     
     return absoluteBitwiseOp(vm, x, y, ExtraDigitsHandling::Copy, SymmetricOp::Symmetric, digitOperation);
 }
     
-JSBigInt* JSBigInt::absoluteAddOne(VM& vm, JSBigInt* x, SignOption signOption)
+JSBigInt* JSBigInt::absoluteAddOne(ExecState* exec, JSBigInt* x, SignOption signOption)
 {
     unsigned inputLength = x->length();
     // The addition will overflow into a new digit if all existing digits are
 {
     unsigned inputLength = x->length();
     // The addition will overflow into a new digit if all existing digits are
@@ -1158,7 +1210,9 @@ JSBigInt* JSBigInt::absoluteAddOne(VM& vm, JSBigInt* x, SignOption signOption)
     }
 
     unsigned resultLength = inputLength + willOverflow;
     }
 
     unsigned resultLength = inputLength + willOverflow;
-    JSBigInt* result = createWithLength(vm, resultLength);
+    JSBigInt* result = tryCreateWithLength(exec, resultLength);
+    if (!result)
+        return nullptr;
 
     Digit carry = 1;
     for (unsigned i = 0; i < inputLength; i++) {
 
     Digit carry = 1;
     for (unsigned i = 0; i < inputLength; i++) {
@@ -1172,16 +1226,18 @@ JSBigInt* JSBigInt::absoluteAddOne(VM& vm, JSBigInt* x, SignOption signOption)
         ASSERT(!carry);
 
     result->setSign(signOption == SignOption::Signed);
         ASSERT(!carry);
 
     result->setSign(signOption == SignOption::Signed);
-    return result->rightTrim(vm);
+    return result->rightTrim(exec->vm());
 }
 
 }
 
-// Like the above, but you can specify that the allocated result should have
-// length {resultLength}, which must be at least as large as {x->length()}.
-JSBigInt* JSBigInt::absoluteSubOne(VM& vm, JSBigInt* x, unsigned resultLength)
+JSBigInt* JSBigInt::absoluteSubOne(ExecState* exec, JSBigInt* x, unsigned resultLength)
 {
     ASSERT(!x->isZero());
     ASSERT(resultLength >= x->length());
 {
     ASSERT(!x->isZero());
     ASSERT(resultLength >= x->length());
-    JSBigInt* result = createWithLength(vm, resultLength);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSBigInt* result = tryCreateWithLength(exec, resultLength);
+    RETURN_IF_EXCEPTION(scope, nullptr);
 
     unsigned length = x->length();
     Digit borrow = 1;
 
     unsigned length = x->length();
     Digit borrow = 1;
@@ -1354,8 +1410,6 @@ String JSBigInt::toStringGeneric(ExecState* exec, JSBigInt* x, unsigned radix)
         do {
             Digit chunk;
             absoluteDivWithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk);
         do {
             Digit chunk;
             absoluteDivWithDigitDivisor(vm, *dividend, chunkDivisor, &rest, chunk);
-            ASSERT(rest);
-
             dividend = &rest;
             for (unsigned i = 0; i < chunkChars; i++) {
                 resultString.append(radixDigits[chunk % radix]);
             dividend = &rest;
             for (unsigned i = 0; i < chunkChars; i++) {
                 resultString.append(radixDigits[chunk % radix]);
@@ -1414,8 +1468,7 @@ JSBigInt* JSBigInt::rightTrim(VM& vm)
         return this;
 
     unsigned newLength = nonZeroIndex + 1;
         return this;
 
     unsigned newLength = nonZeroIndex + 1;
-    JSBigInt* trimmedBigInt = createWithLength(vm, newLength);
-    RELEASE_ASSERT(trimmedBigInt);
+    JSBigInt* trimmedBigInt = createWithLengthUnchecked(vm, newLength);
     std::copy(dataStorage(), dataStorage() + newLength, trimmedBigInt->dataStorage()); 
 
     trimmedBigInt->setSign(this->sign());
     std::copy(dataStorage(), dataStorage() + newLength, trimmedBigInt->dataStorage()); 
 
     trimmedBigInt->setSign(this->sign());
@@ -1439,7 +1492,7 @@ JSBigInt* JSBigInt::allocateFor(ExecState* exec, VM& vm, unsigned radix, unsigne
             // Divide by kDigitsBits, rounding up.
             unsigned length = (bitsMin + digitBits - 1) / digitBits;
             if (length <= maxLength) {
             // Divide by kDigitsBits, rounding up.
             unsigned length = (bitsMin + digitBits - 1) / digitBits;
             if (length <= maxLength) {
-                JSBigInt* result = JSBigInt::createWithLength(vm, length);
+                JSBigInt* result = JSBigInt::createWithLengthUnchecked(vm, length);
                 return result;
             }
         }
                 return result;
             }
         }
index a62e138..ab8ff5a 100644 (file)
@@ -51,7 +51,8 @@ public:
 
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
     static JSBigInt* createZero(VM&);
 
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
     static JSBigInt* createZero(VM&);
-    static JSBigInt* createWithLength(VM&, unsigned length);
+    static JSBigInt* tryCreateWithLength(ExecState*, unsigned length);
+    static JSBigInt* createWithLengthUnchecked(VM&, unsigned length);
 
     static JSBigInt* createFrom(VM&, int32_t value);
     static JSBigInt* createFrom(VM&, uint32_t value);
 
     static JSBigInt* createFrom(VM&, int32_t value);
     static JSBigInt* createFrom(VM&, uint32_t value);
@@ -108,15 +109,15 @@ public:
     
     ComparisonResult static compareToDouble(JSBigInt* x, double y);
 
     
     ComparisonResult static compareToDouble(JSBigInt* x, double y);
 
-    static JSBigInt* add(VM&, JSBigInt* x, JSBigInt* y);
-    static JSBigInt* sub(VM&, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* add(ExecState*, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* sub(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* unaryMinus(VM&, JSBigInt* x);
 
     static JSBigInt* divide(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* remainder(ExecState*, JSBigInt* x, JSBigInt* y);
     static JSBigInt* unaryMinus(VM&, JSBigInt* x);
 
-    static JSBigInt* bitwiseAnd(VM&, JSBigInt* x, JSBigInt* y);
-    static JSBigInt* bitwiseOr(VM&, JSBigInt* x, JSBigInt* y);
-    static JSBigInt* bitwiseXor(VM&, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* bitwiseAnd(ExecState*, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* bitwiseOr(ExecState*, JSBigInt* x, JSBigInt* y);
+    static JSBigInt* bitwiseXor(ExecState*, JSBigInt* x, JSBigInt* y);
 
 private:
 
 
 private:
 
@@ -139,14 +140,14 @@ private:
     static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
     static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
     static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
     static void absoluteDivWithDigitDivisor(VM&, JSBigInt* x, Digit divisor, JSBigInt** quotient, Digit& remainder);
     static void internalMultiplyAdd(JSBigInt* source, Digit factor, Digit summand, unsigned, JSBigInt* result);
     static void multiplyAccumulate(JSBigInt* multiplicand, Digit multiplier, JSBigInt* accumulator, unsigned accumulatorIndex);
-    static void absoluteDivWithBigIntDivisor(VM&, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder);
+    static void absoluteDivWithBigIntDivisor(ExecState*, JSBigInt* dividend, JSBigInt* divisor, JSBigInt** quotient, JSBigInt** remainder);
     
     enum class LeftShiftMode {
         SameSizeResult,
         AlwaysAddOneDigit
     };
     
     
     enum class LeftShiftMode {
         SameSizeResult,
         AlwaysAddOneDigit
     };
     
-    static JSBigInt* absoluteLeftShiftAlwaysCopy(VM&, JSBigInt* x, unsigned shift, LeftShiftMode);
+    static JSBigInt* absoluteLeftShiftAlwaysCopy(ExecState*, JSBigInt* x, unsigned shift, LeftShiftMode);
     static bool productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low);
 
     Digit absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex);
     static bool productGreaterThan(Digit factor1, Digit factor2, Digit high, Digit low);
 
     Digit absoluteInplaceAdd(JSBigInt* summand, unsigned startIndex);
@@ -176,8 +177,8 @@ private:
         Unsigned
     };
 
         Unsigned
     };
 
-    static JSBigInt* absoluteAddOne(VM&, JSBigInt* x, SignOption);
-    static JSBigInt* absoluteSubOne(VM&, JSBigInt* x, unsigned resultLength);
+    static JSBigInt* absoluteAddOne(ExecState*, JSBigInt* x, SignOption);
+    static JSBigInt* absoluteSubOne(ExecState*, JSBigInt* x, unsigned resultLength);
 
     // Digit arithmetic helpers.
     static Digit digitAdd(Digit a, Digit b, Digit& carry);
 
     // Digit arithmetic helpers.
     static Digit digitAdd(Digit a, Digit b, Digit& carry);
@@ -203,7 +204,7 @@ private:
     JSBigInt* rightTrim(VM&);
 
     void inplaceMultiplyAdd(Digit multiplier, Digit part);
     JSBigInt* rightTrim(VM&);
 
     void inplaceMultiplyAdd(Digit multiplier, Digit part);
-    static JSBigInt* absoluteAdd(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
+    static JSBigInt* absoluteAdd(ExecState*, JSBigInt* x, JSBigInt* y, bool resultSign);
     static JSBigInt* absoluteSub(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
     
     static size_t allocationSize(unsigned length);
     static JSBigInt* absoluteSub(VM&, JSBigInt* x, JSBigInt* y, bool resultSign);
     
     static size_t allocationSize(unsigned length);
index a088ad1..836f953 100644 (file)
@@ -69,8 +69,10 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2)
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
-            return JSBigInt::add(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+            scope.release();
+            return JSBigInt::add(callFrame, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+        }
 
         return throwTypeError(callFrame, scope, "Invalid mix of BigInt and other type in addition."_s);
     }
 
         return throwTypeError(callFrame, scope, "Invalid mix of BigInt and other type in addition."_s);
     }
index 61d533c..0ea9829 100644 (file)
@@ -348,8 +348,10 @@ ALWAYS_INLINE JSValue jsSub(ExecState* exec, JSValue v1, JSValue v2)
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
-            return JSBigInt::sub(vm, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+            scope.release();
+            return JSBigInt::sub(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+        }
 
         return throwTypeError(exec, scope, "Invalid mix of BigInt and other type in subtraction."_s);
     }
 
         return throwTypeError(exec, scope, "Invalid mix of BigInt and other type in subtraction."_s);
     }
@@ -368,8 +370,10 @@ ALWAYS_INLINE JSValue jsMul(ExecState* state, JSValue v1, JSValue v2)
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
     RETURN_IF_EXCEPTION(scope, { });
 
     if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
+        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
+            scope.release();
             return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
             return JSBigInt::multiply(state, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
+        }
 
         throwTypeError(state, scope, "Invalid mix of BigInt and other type in multiplication."_s);
         return { };
 
         throwTypeError(state, scope, "Invalid mix of BigInt and other type in multiplication."_s);
         return { };