Version 1.11.0-dev.5.6

Cherry-pick a192ef4acb95fad1aad1887f59eed071eb5e8201 into dev
Cherry-pick d9da805f07feb8b613832a5820c875f5b8703141 into dev
Cherry-pick d0d5185550d5b41af75ec6e514c484da4abbf2b5 into dev
Cherry-pick e91b99b66d7cce90ec0784e01128834d861b9d82 into dev
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index 04b85b7..adfb0db 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -47,6 +47,7 @@
 class _Bigint extends _IntegerImplementation implements int {
   // Bits per digit.
   static const int _DIGIT_BITS = 32;
+  static const int _LOG2_DIGIT_BITS = 5;
   static const int _DIGIT_BASE = 1 << _DIGIT_BITS;
   static const int _DIGIT_MASK = (1 << _DIGIT_BITS) - 1;
 
@@ -1538,27 +1539,52 @@
     return z._revert(r_digits, r_used)._toValidInt();
   }
 
-  // Returns 1/this % m, with m > 0.
-  int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
-    if (m == 1) return 0;
-    m = m._toBigint();
-    var t = this;
-    if (t._neg || (t._absCompare(m) >= 0)) {
-      t %= m;
-      t = t._toBigint();
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  static int _binaryGcd(_Bigint x, _Bigint y, bool inv) {
+    var x_digits = x._digits;
+    var y_digits = y._digits;
+    var x_used = x._used;
+    var y_used = y._used;
+    var m_used = x_used > y_used ? x_used : y_used;
+    final m_len = m_used + (m_used & 1);
+    x_digits = _cloneDigits(x_digits, 0, x_used, m_len);
+    y_digits = _cloneDigits(y_digits, 0, y_used, m_len);
+    int s = 0;
+    if (inv) {
+      if ((y_used == 1) && (y_digits[0] == 1)) return 1;
+      if ((y_used == 0) || (y_digits[0].isEven && x_digits[0].isEven)) {
+        throw new RangeError("Not coprime");
+      }
+    } else {
+      if ((x_used == 0) || (y_used == 0)) throw new RangeError(0);
+      if (((x_used == 1) && (x_digits[0] == 1)) ||
+          ((y_used == 1) && (y_digits[0] == 1))) return 1;
+      bool xy_cloned = false;
+      while (x.isEven && y.isEven) {
+        _rsh(x_digits, x_used, 1, x_digits);
+        _rsh(y_digits, y_used, 1, y_digits);
+        s++;
+      }
+      if (s >= _DIGIT_BITS) {
+        var sd = s >> _LOG2_DIGIT_BITS;
+        x_used -= sd;
+        y_used -= sd;
+        m_used -= sd;
+      }
+      if ((y_digits[0] & 1) == 1) {
+        var t_digits = x_digits;
+        var t_used = x_used;
+        x_digits = y_digits;
+        x_used = y_used;
+        y_digits = t_digits;
+        y_used = t_used;
+      }
     }
-    final bool ac = m.isEven;
-    final t_used = t._used;
-    if ((t_used == 1) && (t._digits[0] == 1)) return 1;
-    if ((t_used == 0) || (ac && t.isEven)) throw new RangeError("Not coprime");
-    final m_digits = m._digits;
-    final m_used = m._used;
-    final tuv_len = m_used + (m_used & 1);
-    final t_digits = _cloneDigits(t._digits, 0, t_used, tuv_len);
-    var u_digits = _cloneDigits(m_digits, 0, m_used, tuv_len);
-    var v_digits = _cloneDigits(t_digits, 0, t_used, tuv_len);
+    var u_digits = _cloneDigits(x_digits, 0, x_used, m_len);
+    var v_digits = _cloneDigits(y_digits, 0, y_used, m_len);
+    final bool ac = (x_digits[0] & 1) == 0;
 
     // Variables a, b, c, and d require one more digit.
     final abcd_used = m_used + 1;
@@ -1585,34 +1611,34 @@
           if (((a_digits[0] & 1) == 1) || ((b_digits[0] & 1) == 1)) {
             if (a_neg) {
               if ((a_digits[m_used] != 0) ||
-                  (_compareDigits(a_digits, m_used, t_digits, m_used)) > 0) {
-                _absSub(a_digits, abcd_used, t_digits, m_used, a_digits);
+                  (_compareDigits(a_digits, m_used, y_digits, m_used)) > 0) {
+                _absSub(a_digits, abcd_used, y_digits, m_used, a_digits);
               } else {
-                _absSub(t_digits, m_used, a_digits, m_used, a_digits);
+                _absSub(y_digits, m_used, a_digits, m_used, a_digits);
                 a_neg = false;
               }
             } else {
-              _absAdd(a_digits, abcd_used, t_digits, m_used, a_digits);
+              _absAdd(a_digits, abcd_used, y_digits, m_used, a_digits);
             }
             if (b_neg) {
-              _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits);
+              _absAdd(b_digits, abcd_used, x_digits, m_used, b_digits);
             } else if ((b_digits[m_used] != 0) ||
-                (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) {
-              _absSub(b_digits, abcd_used, m_digits, m_used, b_digits);
+                (_compareDigits(b_digits, m_used, x_digits, m_used) > 0)) {
+              _absSub(b_digits, abcd_used, x_digits, m_used, b_digits);
             } else {
-              _absSub(m_digits, m_used, b_digits, m_used, b_digits);
+              _absSub(x_digits, m_used, b_digits, m_used, b_digits);
               b_neg = true;
             }
           }
           _rsh(a_digits, abcd_used, 1, a_digits);
         } else if ((b_digits[0] & 1) == 1) {
           if (b_neg) {
-            _absAdd(b_digits, abcd_used, m_digits, m_used, b_digits);
+            _absAdd(b_digits, abcd_used, x_digits, m_used, b_digits);
           } else if ((b_digits[m_used] != 0) ||
-                     (_compareDigits(b_digits, m_used, m_digits, m_used) > 0)) {
-            _absSub(b_digits, abcd_used, m_digits, m_used, b_digits);
+                     (_compareDigits(b_digits, m_used, x_digits, m_used) > 0)) {
+            _absSub(b_digits, abcd_used, x_digits, m_used, b_digits);
           } else {
-            _absSub(m_digits, m_used, b_digits, m_used, b_digits);
+            _absSub(x_digits, m_used, b_digits, m_used, b_digits);
             b_neg = true;
           }
         }
@@ -1624,34 +1650,34 @@
           if (((c_digits[0] & 1) == 1) || ((d_digits[0] & 1) == 1)) {
             if (c_neg) {
               if ((c_digits[m_used] != 0) ||
-                  (_compareDigits(c_digits, m_used, t_digits, m_used) > 0)) {
-                _absSub(c_digits, abcd_used, t_digits, m_used, c_digits);
+                  (_compareDigits(c_digits, m_used, y_digits, m_used) > 0)) {
+                _absSub(c_digits, abcd_used, y_digits, m_used, c_digits);
               } else {
-                _absSub(t_digits, m_used, c_digits, m_used, c_digits);
+                _absSub(y_digits, m_used, c_digits, m_used, c_digits);
                 c_neg = false;
               }
             } else {
-              _absAdd(c_digits, abcd_used, t_digits, m_used, c_digits);
+              _absAdd(c_digits, abcd_used, y_digits, m_used, c_digits);
             }
             if (d_neg) {
-              _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits);
+              _absAdd(d_digits, abcd_used, x_digits, m_used, d_digits);
             } else if ((d_digits[m_used] != 0) ||
-                (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-              _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+                (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+              _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
             } else {
-              _absSub(m_digits, m_used, d_digits, m_used, d_digits);
+              _absSub(x_digits, m_used, d_digits, m_used, d_digits);
               d_neg = true;
             }
           }
           _rsh(c_digits, abcd_used, 1, c_digits);
         } else if ((d_digits[0] & 1) == 1) {
           if (d_neg) {
-            _absAdd(d_digits, abcd_used, m_digits, m_used, d_digits);
+            _absAdd(d_digits, abcd_used, x_digits, m_used, d_digits);
           } else if ((d_digits[m_used] != 0) ||
-                     (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-            _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+                     (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+            _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
           } else {
-            _absSub(m_digits, m_used, d_digits, m_used, d_digits);
+            _absSub(x_digits, m_used, d_digits, m_used, d_digits);
             d_neg = true;
           }
         }
@@ -1719,6 +1745,12 @@
       while ((i > 0) && (u_digits[i - 1] == 0)) --i;
       if (i == 0) break;
     }
+    if (!inv) {
+      if (s > 0) {
+        _lsh(v_digits, m_used, s, v_digits);
+      }
+      return new _Bigint(false, m_used, v_digits)._toValidInt();
+    }
     // No inverse if v != 1.
     var i = m_used - 1;
     while ((i > 0) && (v_digits[i] == 0)) --i;
@@ -1726,29 +1758,49 @@
 
     if (d_neg) {
       if ((d_digits[m_used] != 0) ||
-          (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-        _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+          (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+        _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
         if ((d_digits[m_used] != 0) ||
-            (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-          _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+            (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+          _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
         } else {
-          _absSub(m_digits, m_used, d_digits, m_used, d_digits);
+          _absSub(x_digits, m_used, d_digits, m_used, d_digits);
           d_neg = false;
         }
       } else {
-        _absSub(m_digits, m_used, d_digits, m_used, d_digits);
+        _absSub(x_digits, m_used, d_digits, m_used, d_digits);
         d_neg = false;
       }
     } else if ((d_digits[m_used] != 0) ||
-               (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-      _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+               (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+      _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
       if ((d_digits[m_used] != 0) ||
-          (_compareDigits(d_digits, m_used, m_digits, m_used) > 0)) {
-        _absSub(d_digits, abcd_used, m_digits, m_used, d_digits);
+          (_compareDigits(d_digits, m_used, x_digits, m_used) > 0)) {
+        _absSub(d_digits, abcd_used, x_digits, m_used, d_digits);
       }
     }
     return new _Bigint(false, m_used, d_digits)._toValidInt();
   }
+
+  // Returns 1/this % m, with m > 0.
+  int modInverse(int m) {
+    if (m is! int) throw new ArgumentError(m);
+    if (m <= 0) throw new RangeError(m);
+    if (m == 1) return 0;
+    m = m._toBigint();
+    var t = this;
+    if (t._neg || (t._absCompare(m) >= 0)) {
+      t %= m;
+      t = t._toBigint();
+    }
+    return _binaryGcd(m, t, true);
+  }
+
+  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  int gcd(int other) {
+    if (other is! int) throw new ArgumentError(other);
+    return _binaryGcd(this, other._toBigint(), false);
+  }
 }
 
 // Interface for modular reduction.
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index 1267d15..be0cb8f 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -290,21 +290,26 @@
     return r;
   }
 
-  // Returns 1/this % m, with m > 0.
-  int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
-    if (m == 1) return 0;
-    if (m is _Bigint) {
-      return _toBigint().modInverse(m);
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  static int _binaryGcd(int x, int y, bool inv) {
+    int s = 0;
+    if (!inv) {
+      while (x.isEven && y.isEven) {
+        x >>= 1;
+        y >>= 1;
+        s++;
+      }
+      if (y.isOdd) {
+        var t = x;
+        x = y;
+        y = t;
+      }
     }
-    int t = this;
-    if ((t < 0) || (t >= m)) t %= m;
-    if (t == 1) return 1;
-    final bool ac = m.isEven;
-    if ((t == 0) || (ac && t.isEven)) throw new RangeError("Not coprime");
-    int u = m;
-    int v = t;
+    final bool ac = x.isEven;
+    int u = x;
+    int v = y;
     int a = 1,
         b = 0,
         c = 0,
@@ -314,12 +319,12 @@
         u >>= 1;
         if (ac) {
           if (!a.isEven || !b.isEven) {
-            a += t;
-            b -= m;
+            a += y;
+            b -= x;
           }
           a >>= 1;
         } else if (!b.isEven) {
-          b -= m;
+          b -= x;
         }
         b >>= 1;
       }
@@ -327,12 +332,12 @@
         v >>= 1;
         if (ac) {
           if (!c.isEven || !d.isEven) {
-            c += t;
-            d -= m;
+            c += y;
+            d -= x;
           }
           c >>= 1;
         } else if (!d.isEven) {
-          d -= m;
+          d -= x;
         }
         d >>= 1;
       }
@@ -346,16 +351,45 @@
         d -= b;
       }
     } while (u != 0);
+    if (!inv) return v << s;
     if (v != 1) throw new RangeError("Not coprime");
     if (d < 0) {
-      d += m;
-      if (d < 0) d += m;
-    } else if (d > m) {
-      d -= m;
-      if (d > m) d -= m;
+      d += x;
+      if (d < 0) d += x;
+    } else if (d > x) {
+      d -= x;
+      if (d > x) d -= x;
     }
     return d;
   }
+
+  // Returns 1/this % m, with m > 0.
+  int modInverse(int m) {
+    if (m is! int) throw new ArgumentError(m);
+    if (m <= 0) throw new RangeError(m);
+    if (m == 1) return 0;
+    if (m is _Bigint) {
+      return _toBigint().modInverse(m);
+    }
+    int t = this;
+    if ((t < 0) || (t >= m)) t %= m;
+    if (t == 1) return 1;
+    if ((t == 0) || (t.isEven && m.isEven)) throw new RangeError("Not coprime");
+    return _binaryGcd(m, t, true);
+  }
+
+  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  int gcd(int other) {
+    if (other is! int) throw new ArgumentError(other);
+    if ((this == 0) || (other == 0)) throw new RangeError(0);
+    int x = this.abs();
+    int y = other.abs();
+    if ((x == 1) || (y == 1)) return 1;
+    if (other is _Bigint) {
+      return _toBigint().gcd(other);
+    }
+    return _binaryGcd(x, y, false);
+  }
 }
 
 class _Smi extends _IntegerImplementation implements int {
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index a1abaad..35bab84 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -508,13 +508,17 @@
 }
 
 
+// Comparison instruction that is equivalent to the (left & right) == 0
+// comparison pattern.
 void ConstantPropagator::VisitTestSmi(TestSmiInstr* instr) {
   const Object& left = instr->left()->definition()->constant_value();
   const Object& right = instr->right()->definition()->constant_value();
   if (IsNonConstant(left) || IsNonConstant(right)) {
     SetValue(instr, non_constant_);
   } else if (IsConstant(left) && IsConstant(right)) {
-    if (left.IsInteger() && right.IsInteger()) {
+    // BitOp does not work on Bigints.
+    if (left.IsInteger() && right.IsInteger() &&
+        !left.IsBigint() && !right.IsBigint()) {
       const bool result = CompareIntegers(
           instr->kind(),
           Integer::Handle(I, Integer::Cast(left).BitOp(Token::kBIT_AND,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index f78c295..1bdd070 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1656,7 +1656,7 @@
     case Token::kTRUNCDIV:
     case Token::kMOD:
       // Check right value for zero.
-      if (right.AsInt64Value() == 0) {
+      if (right.IsSmi() && right.AsInt64Value() == 0) {
         break;  // Will throw.
       }
       // Fall through.
diff --git a/sdk/lib/_internal/compiler/js_lib/js_number.dart b/sdk/lib/_internal/compiler/js_lib/js_number.dart
index 8822911..64df825 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_number.dart
@@ -411,18 +411,26 @@
     return r;
   }
 
-  // Returns 1/this % m, with m > 0.
-  int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
-    if (m == 1) return 0;
-    int t = this;
-    if ((t < 0) || (t >= m)) t %= m;
-    if (t == 1) return 1;
-    final bool ac = m.isEven;
-    if ((t == 0) || (ac && t.isEven)) throw new RangeError("Not coprime");
-    int u = m;
-    int v = t;
+  // If inv is false, returns gcd(x, y).
+  // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
+  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  static int _binaryGcd(int x, int y, bool inv) {
+    int s = 1;
+    if (!inv) {
+      while (x.isEven && y.isEven) {
+        x ~/= 2;
+        y ~/= 2;
+        s *= 2;
+      }
+      if (y.isOdd) {
+        var t = x;
+        x = y;
+        y = t;
+      }
+    }
+    final bool ac = x.isEven;
+    int u = x;
+    int v = y;
     int a = 1,
         b = 0,
         c = 0,
@@ -432,12 +440,12 @@
         u ~/= 2;
         if (ac) {
           if (!a.isEven || !b.isEven) {
-            a += t;
-            b -= m;
+            a += y;
+            b -= x;
           }
           a ~/= 2;
         } else if (!b.isEven) {
-          b -= m;
+          b -= x;
         }
         b ~/= 2;
       }
@@ -445,12 +453,12 @@
         v ~/= 2;
         if (ac) {
           if (!c.isEven || !d.isEven) {
-            c += t;
-            d -= m;
+            c += y;
+            d -= x;
           }
           c ~/= 2;
         } else if (!d.isEven) {
-          d -= m;
+          d -= x;
         }
         d ~/= 2;
       }
@@ -464,17 +472,40 @@
         d -= b;
       }
     } while (u != 0);
+    if (!inv) return s*v;
     if (v != 1) throw new RangeError("Not coprime");
     if (d < 0) {
-      d += m;
-      if (d < 0) d += m;
-    } else if (d > m) {
-      d -= m;
-      if (d > m) d -= m;
+      d += x;
+      if (d < 0) d += x;
+    } else if (d > x) {
+      d -= x;
+      if (d > x) d -= x;
     }
     return d;
   }
 
+  // Returns 1/this % m, with m > 0.
+  int modInverse(int m) {
+    if (m is! int) throw new ArgumentError(m);
+    if (m <= 0) throw new RangeError(m);
+    if (m == 1) return 0;
+    int t = this;
+    if ((t < 0) || (t >= m)) t %= m;
+    if (t == 1) return 1;
+    if ((t == 0) || (t.isEven && m.isEven)) throw new RangeError("Not coprime");
+    return _binaryGcd(m, t, true);
+  }
+
+  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  int gcd(int other) {
+    if (other is! int) throw new ArgumentError(other);
+    if ((this == 0) || (other == 0)) throw new RangeError(0);
+    int x = this.abs();
+    int y = other.abs();
+    if ((x == 1) || (y == 1)) return 1;
+    return _binaryGcd(x, y, false);
+  }
+
   // Assumes i is <= 32-bit and unsigned.
   static int _bitCount(int i) {
     // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 5aee609..58d80b8 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -120,6 +120,14 @@
    */
   int modInverse(int modulus);
 
+  /**
+   * Returns the greatest common divisor of the absolute value of
+   * this integer and the absolute value of [other].
+   *
+   * Both this and [other] must be non-zero.
+   */
+  int gcd(int other);
+
   /** Returns true if and only if this integer is even. */
   bool get isEven;
 
diff --git a/tests/corelib/big_integer_arith_vm_test.dart b/tests/corelib/big_integer_arith_vm_test.dart
index 3353756..8b76ba0 100644
--- a/tests/corelib/big_integer_arith_vm_test.dart
+++ b/tests/corelib/big_integer_arith_vm_test.dart
@@ -5,6 +5,7 @@
 // Testing Bigints with and without intrinsics.
 // VMOptions=
 // VMOptions=--no_intrinsify
+// VMOptions=--optimization_counter_threshold=10
 
 library big_integer_test;
 import "package:expect/expect.dart";
@@ -293,6 +294,88 @@
   Expect.equals(46296295879629629587962962962, x.modInverse(m));
 }
 
+testBigintGcd() {
+  var x, m;
+  x = 1;
+  m = 1;
+  Expect.equals(1, x.gcd(m));
+  x = 693;
+  m = 609;
+  Expect.equals(21, x.gcd(m));
+  x = 693 << 40;
+  m = 609 << 40;
+  Expect.equals(21 << 40, x.gcd(m));
+  x = 609 << 40;;
+  m = 693 << 40;;
+  Expect.equals(21 <<40, x.gcd(m));
+  x = 0;
+  m = 1000000001;
+  Expect.throws(() => x.gcd(m), (e) => e is RangeError);
+  x = 1000000001;
+  m = 0;
+  Expect.throws(() => x.gcd(m), (e) => e is RangeError);
+  x = 1234567890;
+  m = 19;
+  Expect.equals(1, x.gcd(m));
+  x = 1234567890;
+  m = 1000000001;
+  Expect.equals(1, x.gcd(m));
+  x = 19;
+  m = 1000000001;
+  Expect.equals(19, x.gcd(m));
+  x = 19;
+  m = 1234567890;
+  Expect.equals(1, x.gcd(m));
+  x = 1000000001;
+  m = 1234567890;
+  Expect.equals(1, x.gcd(m));
+  x = 1000000001;
+  m = 19;
+  Expect.equals(19, x.gcd(m));
+  x = 12345678901234567890;
+  m = 19;
+  Expect.equals(1, x.gcd(m));
+  x = 12345678901234567890;
+  m = 10000000000000000001;
+  Expect.equals(1, x.gcd(m));
+  x = 19;
+  m = 10000000000000000001;
+  Expect.equals(1, x.gcd(m));
+  x = 19;
+  m = 12345678901234567890;
+  Expect.equals(1, x.gcd(m));
+  x = 10000000000000000001;
+  m = 12345678901234567890;
+  Expect.equals(1, x.gcd(m));
+  x = 10000000000000000001;
+  m = 19;
+  Expect.equals(1, x.gcd(m));
+  x = 12345678901234567890;
+  m = 10000000000000000001;
+  Expect.equals(1, x.gcd(m));
+  x = 12345678901234567890;
+  m = 19;
+  Expect.equals(1, x.gcd(m));
+  x = 123456789012345678901234567890;
+  m = 123456789012345678901234567899;
+  Expect.equals(9, x.gcd(m));
+  x = 123456789012345678901234567890;
+  m = 123456789012345678901234567891;
+  Expect.equals(1, x.gcd(m));
+  x = 123456789012345678901234567899;
+  m = 123456789012345678901234567891;
+  Expect.equals(1, x.gcd(m));
+  x = 123456789012345678901234567899;
+  m = 123456789012345678901234567890;
+  Expect.equals(9, x.gcd(m));
+  x = 123456789012345678901234567891;
+  m = 123456789012345678901234567890;
+  Expect.equals(1, x.gcd(m));
+  x = 123456789012345678901234567891;
+  m = 123456789012345678901234567899;
+  Expect.equals(1, x.gcd(m));
+}
+
 testBigintNegate() {
   var a = 0xF000000000000000F;
   var b = ~a;  // negate.
@@ -314,23 +397,26 @@
 }
 
 main() {
-  Expect.equals(1234567890123456789, foo());
-  Expect.equals(12345678901234567890, bar());
-  testSmiOverflow();
-  testBigintAdd();
-  testBigintSub();
-  testBigintMul();
-  testBigintTruncDiv();
-  testBigintDiv();
-  testBigintModulo();
-  testBigintModPow();
-  testBigintModInverse();
-  testBigintNegate();
-  testShiftAmount();
-  Expect.equals(12345678901234567890, (12345678901234567890).abs());
-  Expect.equals(12345678901234567890, (-12345678901234567890).abs());
-  var a = 10000000000000000000;
-  var b = 10000000000000000001;
-  Expect.equals(false, a.hashCode == b.hashCode);
-  Expect.equals(true, a.hashCode == (b - 1).hashCode);
+  for (int i = 0; i < 10; i++) {
+    Expect.equals(1234567890123456789, foo());
+    Expect.equals(12345678901234567890, bar());
+    testSmiOverflow();  /// overflow: ok
+    testBigintAdd();  /// add: ok
+    testBigintSub();  /// sub: ok
+    testBigintMul();  /// mul: ok
+    testBigintTruncDiv();  /// trunDiv: ok
+    testBigintDiv();  /// div: ok
+    testBigintModulo();  /// mod: ok
+    testBigintModPow();  /// modPow: ok
+    testBigintModInverse();  /// modInv: ok
+    testBigintGcd();  /// gcd: ok
+    testBigintNegate();  /// negate: ok
+    testShiftAmount();  /// shift: ok
+    Expect.equals(12345678901234567890, (12345678901234567890).abs());
+    Expect.equals(12345678901234567890, (-12345678901234567890).abs());
+    var a = 10000000000000000000;
+    var b = 10000000000000000001;
+    Expect.equals(false, a.hashCode == b.hashCode);
+    Expect.equals(true, a.hashCode == (b - 1).hashCode);
+  }
 }
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 97080cb..f107d2c 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -205,6 +205,10 @@
 [ $mode == debug ]
 regexp/pcre_test: Pass, Slow # Timeout. Issue 22008
 
+[ $mode == debug && $runtime == vm]
+big_integer_arith_vm_test/gcd: Pass, Crash # Issue 23693
+big_integer_arith_vm_test/modInv: Pass, Crash # Issue 23693
+
 [ $runtime == vm && $arch == simarmv5te ]
 int_parse_radix_test/*: Pass, Slow
 big_integer_parsed_mul_div_vm_test: Pass, Slow
diff --git a/tools/VERSION b/tools/VERSION
index 1782662..7f622f5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
 MINOR 11
 PATCH 0
 PRERELEASE 5
-PRERELEASE_PATCH 5
+PRERELEASE_PATCH 6