changeset 2274:99255f8dcacd

Backport BigDecimal/Integer performance improvements. 2010-11-10 Andrew John Hughes <ahughes@redhat.com> * Makefile.am: Add BigDecimal/Integer performance improvement patches. * patches/openjdk/6622432-bigdecimal_performance.patch, * patches/openjdk/6850606-bigdecimal_regression.patch, * patches/openjdk/6876282-bigdecimal_divide.patch: Added.
author Andrew John Hughes <ahughes@redhat.com>
date Wed, 10 Nov 2010 19:17:09 +0000
parents 621a87c458c5
children aa23fe60637f
files ChangeLog Makefile.am patches/openjdk/6622432-bigdecimal_performance.patch patches/openjdk/6850606-bigdecimal_regression.patch patches/openjdk/6876282-bigdecimal_divide.patch
diffstat 5 files changed, 4457 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Nov 09 14:51:54 2010 +0000
+++ b/ChangeLog	Wed Nov 10 19:17:09 2010 +0000
@@ -1,3 +1,12 @@
+2010-11-10  Andrew John Hughes  <ahughes@redhat.com>
+
+	* Makefile.am: Add BigDecimal/Integer performance
+	improvement patches.
+	* patches/openjdk/6622432-bigdecimal_performance.patch,
+	* patches/openjdk/6850606-bigdecimal_regression.patch,
+	* patches/openjdk/6876282-bigdecimal_divide.patch:
+	Added.
+
 2010-11-09  Andrew John Hughes  <ahughes@redhat.com>
 
 	* Makefile.am:
--- a/Makefile.am	Tue Nov 09 14:51:54 2010 +0000
+++ b/Makefile.am	Wed Nov 10 19:17:09 2010 +0000
@@ -312,8 +312,10 @@
 	patches/openjdk/6650759-missing_inference.patch \
 	patches/numa_on_early_glibc.patch \
 	patches/openjdk/6853592-badwindow-warning-fix.patch \
-	patches/6703377-freetypescaler.patch
-
+	patches/6703377-freetypescaler.patch \
+	patches/openjdk/6622432-bigdecimal_performance.patch \
+	patches/openjdk/6850606-bigdecimal_regression.patch \
+	patches/openjdk/6876282-bigdecimal_divide.patch
 
 if !WITH_ALT_HSBUILD
 ICEDTEA_PATCHES += \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/openjdk/6622432-bigdecimal_performance.patch	Wed Nov 10 19:17:09 2010 +0000
@@ -0,0 +1,4211 @@
+# HG changeset patch
+# User aph
+# Date 1288788231 0
+# Node ID cadc64fc2282d7704a3c80799a5723b502b7d69f
+# Parent  2b1a7d4b9ac69c2366f38b5b0e9ebcf61f1e3277
+6622432: RFE: Performance improvements to java.math.BigDecimal
+Reviewed-by: darcy
+
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/BigDecimal.java
+--- openjdk.orig/jdk/src/share/classes/java/math/BigDecimal.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/BigDecimal.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -29,6 +29,9 @@
+ 
+ package java.math;
+ 
++import java.util.Arrays;
++import static java.math.BigInteger.LONG_MASK;
++
+ /**
+  * Immutable, arbitrary-precision signed decimal numbers.  A
+  * {@code BigDecimal} consists of an arbitrary precision integer
+@@ -229,8 +232,8 @@
+      * @serial
+      * @see #scale
+      */
+-    private int scale = 0;  // Note: this may have any value, so
+-                            // calculations must be done in longs
++    private int scale;  // Note: this may have any value, so
++                        // calculations must be done in longs
+     /**
+      * The number of decimal digits in this BigDecimal, or 0 if the
+      * number of digits are not known (lookaside information).  If
+@@ -240,25 +243,25 @@
+      *
+      * @since  1.5
+      */
+-    private volatile transient int precision = 0;
++    private transient int precision;
+ 
+     /**
+      * Used to store the canonical string representation, if computed.
+      */
+-    private volatile transient String stringCache = null;
++    private transient String stringCache;
+ 
+     /**
+      * Sentinel value for {@link #intCompact} indicating the
+      * significand information is only available from {@code intVal}.
+      */
+-    private static final long INFLATED = Long.MIN_VALUE;
++    static final long INFLATED = Long.MIN_VALUE;
+ 
+     /**
+      * If the absolute value of the significand of this BigDecimal is
+      * less than or equal to {@code Long.MAX_VALUE}, the value can be
+      * compactly stored in this field and used in computations.
+      */
+-    private transient long intCompact = INFLATED;
++    private transient long intCompact;
+ 
+     // All 18-digit base ten strings fit into a long; not all 19-digit
+     // strings will
+@@ -269,19 +272,47 @@
+     /* Appease the serialization gods */
+     private static final long serialVersionUID = 6108874887143696463L;
+ 
++    private static final ThreadLocal<StringBuilderHelper>
++        threadLocalStringBuilderHelper = new ThreadLocal<StringBuilderHelper>() {
++        @Override
++        protected StringBuilderHelper initialValue() {
++            return new StringBuilderHelper();
++        }
++    };
++
+     // Cache of common small BigDecimal values.
+     private static final BigDecimal zeroThroughTen[] = {
+-        new BigDecimal(BigInteger.ZERO,         0,  0),
+-        new BigDecimal(BigInteger.ONE,          1,  0),
+-        new BigDecimal(BigInteger.valueOf(2),   2,  0),
+-        new BigDecimal(BigInteger.valueOf(3),   3,  0),
+-        new BigDecimal(BigInteger.valueOf(4),   4,  0),
+-        new BigDecimal(BigInteger.valueOf(5),   5,  0),
+-        new BigDecimal(BigInteger.valueOf(6),   6,  0),
+-        new BigDecimal(BigInteger.valueOf(7),   7,  0),
+-        new BigDecimal(BigInteger.valueOf(8),   8,  0),
+-        new BigDecimal(BigInteger.valueOf(9),   9,  0),
+-        new BigDecimal(BigInteger.TEN,          10, 0),
++        new BigDecimal(BigInteger.ZERO,         0,  0, 1),
++        new BigDecimal(BigInteger.ONE,          1,  0, 1),
++        new BigDecimal(BigInteger.valueOf(2),   2,  0, 1),
++        new BigDecimal(BigInteger.valueOf(3),   3,  0, 1),
++        new BigDecimal(BigInteger.valueOf(4),   4,  0, 1),
++        new BigDecimal(BigInteger.valueOf(5),   5,  0, 1),
++        new BigDecimal(BigInteger.valueOf(6),   6,  0, 1),
++        new BigDecimal(BigInteger.valueOf(7),   7,  0, 1),
++        new BigDecimal(BigInteger.valueOf(8),   8,  0, 1),
++        new BigDecimal(BigInteger.valueOf(9),   9,  0, 1),
++        new BigDecimal(BigInteger.TEN,          10, 0, 2),
++    };
++
++    // Cache of zero scaled by 0 - 15
++    private static final BigDecimal[] ZERO_SCALED_BY = {
++        zeroThroughTen[0],
++        new BigDecimal(BigInteger.ZERO, 0, 1, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 2, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 3, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 4, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 5, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 6, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 7, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 8, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 9, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 10, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 11, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 12, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 13, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 14, 1),
++        new BigDecimal(BigInteger.ZERO, 0, 15, 1),
+     };
+ 
+     // Constants
+@@ -312,6 +343,18 @@
+     // Constructors
+ 
+     /**
++     * Trusted package private constructor.
++     * Trusted simply means if val is INFLATED, intVal could not be null and
++     * if intVal is null, val could not be INFLATED.
++     */
++    BigDecimal(BigInteger intVal, long val, int scale, int prec) {
++        this.scale = scale;
++        this.precision = prec;
++        this.intCompact = val;
++        this.intVal = intVal;
++    }
++
++    /**
+      * Translates a character array representation of a
+      * {@code BigDecimal} into a {@code BigDecimal}, accepting the
+      * same sequence of characters as the {@link #BigDecimal(String)}
+@@ -331,10 +374,19 @@
+      * @since  1.5
+      */
+     public BigDecimal(char[] in, int offset, int len) {
++        // protect against huge length.
++        if (offset+len > in.length || offset < 0)
++            throw new NumberFormatException();
+         // This is the primary string to BigDecimal constructor; all
+         // incoming strings end up here; it uses explicit (inline)
+         // parsing for speed and generates at most one intermediate
+-        // (temporary) object (a char[] array).
++        // (temporary) object (a char[] array) for non-compact case.
++
++        // Use locals for all fields values until completion
++        int prec = 0;                 // record precision value
++        int scl = 0;                  // record scale value
++        long rs = 0;                  // the compact value in long
++        BigInteger rb = null;         // the inflated value in BigInteger
+ 
+         // use array bounds checking to handle too-long, len == 0,
+         // bad offset, etc.
+@@ -351,27 +403,62 @@
+             }
+ 
+             // should now be at numeric part of the significand
+-            int dotoff = -1;                 // '.' offset, -1 if none
++            boolean dot = false;             // true when there is a '.'
+             int cfirst = offset;             // record start of integer
+             long exp = 0;                    // exponent
+-            if (len > in.length)             // protect against huge length
+-                throw new NumberFormatException();
+-            char coeff[] = new char[len];    // integer significand array
+-            char c;                          // work
++            char c;                          // current character
++
++            boolean isCompact = (len <= MAX_COMPACT_DIGITS);
++            // integer significand array & idx is the index to it. The array
++            // is ONLY used when we can't use a compact representation.
++            char coeff[] = isCompact ? null : new char[len];
++            int idx = 0;
+ 
+             for (; len > 0; offset++, len--) {
+                 c = in[offset];
++                // have digit
+                 if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
+-                    // have digit
+-                    coeff[precision] = c;
+-                    precision++;             // count of digits
++                    // First compact case, we need not to preserve the character
++                    // and we can just compute the value in place.
++                    if (isCompact) {
++                        int digit = Character.digit(c, 10);
++                        if (digit == 0) {
++                            if (prec == 0)
++                                prec = 1;
++                            else if (rs != 0) {
++                                rs *= 10;
++                                ++prec;
++                            } // else digit is a redundant leading zero
++                        } else {
++                            if (prec != 1 || rs != 0)
++                                ++prec; // prec unchanged if preceded by 0s
++                            rs = rs * 10 + digit;
++                        }
++                    } else { // the unscaled value is likely a BigInteger object.
++                        if (c == '0' || Character.digit(c, 10) == 0) {
++                            if (prec == 0) {
++                                coeff[idx] = c;
++                                prec = 1;
++                            } else if (idx != 0) {
++                                coeff[idx++] = c;
++                                ++prec;
++                            } // else c must be a redundant leading zero
++                        } else {
++                            if (prec != 1 || idx != 0)
++                                ++prec; // prec unchanged if preceded by 0s
++                            coeff[idx++] = c;
++                        }
++                    }
++                    if (dot)
++                        ++scl;
+                     continue;
+                 }
++                // have dot
+                 if (c == '.') {
+                     // have dot
+-                    if (dotoff >= 0)         // two dots
++                    if (dot)         // two dots
+                         throw new NumberFormatException();
+-                    dotoff = offset;
++                    dot = true;
+                     continue;
+                 }
+                 // exponent expected
+@@ -380,10 +467,9 @@
+                 offset++;
+                 c = in[offset];
+                 len--;
+-                boolean negexp = false;
++                boolean negexp = (c == '-');
+                 // optional sign
+-                if (c == '-' || c == '+') {
+-                    negexp = (c == '-');
++                if (negexp || c == '+') {
+                     offset++;
+                     c = in[offset];
+                     len--;
+@@ -392,9 +478,9 @@
+                     throw new NumberFormatException();
+                 // skip leading zeros in the exponent
+                 while (len > 10 && Character.digit(c, 10) == 0) {
+-                        offset++;
+-                        c = in[offset];
+-                        len--;
++                    offset++;
++                    c = in[offset];
++                    len--;
+                 }
+                 if (len > 10)  // too many nonzero exponent digits
+                     throw new NumberFormatException();
+@@ -420,55 +506,46 @@
+                 if ((int)exp != exp)         // overflow
+                     throw new NumberFormatException();
+                 break;                       // [saves a test]
+-                }
++            }
+             // here when no characters left
+-            if (precision == 0)              // no digits found
++            if (prec == 0)              // no digits found
+                 throw new NumberFormatException();
+ 
+-            if (dotoff >= 0) {               // had dot; set scale
+-                scale = precision - (dotoff - cfirst);
+-                // [cannot overflow]
+-            }
++            // Adjust scale if exp is not zero.
+             if (exp != 0) {                  // had significant exponent
+-                try {
+-                    scale = checkScale(-exp + scale); // adjust
+-                } catch (ArithmeticException e) {
++                // Can't call checkScale which relies on proper fields value
++                long adjustedScale = scl - exp;
++                if (adjustedScale > Integer.MAX_VALUE ||
++                    adjustedScale < Integer.MIN_VALUE)
+                     throw new NumberFormatException("Scale out of range.");
+-                }
++                scl = (int)adjustedScale;
+             }
+ 
+             // Remove leading zeros from precision (digits count)
+-            int first = 0;
+-            for (; (coeff[first] == '0' || Character.digit(coeff[first], 10) == 0) &&
+-                     precision > 1;
+-                 first++)
+-                precision--;
+-
+-            // Set the significand ..
+-            // Copy significand to exact-sized array, with sign if
+-            // negative
+-            // Later use: BigInteger(coeff, first, precision) for
+-            //   both cases, by allowing an extra char at the front of
+-            //   coeff.
+-            char quick[];
+-            if (!isneg) {
+-                quick = new char[precision];
+-                System.arraycopy(coeff, first, quick, 0, precision);
++            if (isCompact) {
++                rs = isneg ? -rs : rs;
+             } else {
+-                quick = new char[precision+1];
+-                quick[0] = '-';
+-                System.arraycopy(coeff, first, quick, 1, precision);
++                char quick[];
++                if (!isneg) {
++                    quick = (coeff.length != prec) ?
++                        Arrays.copyOf(coeff, prec) : coeff;
++                } else {
++                    quick = new char[prec + 1];
++                    quick[0] = '-';
++                    System.arraycopy(coeff, 0, quick, 1, prec);
++                }
++                rb = new BigInteger(quick);
++                rs = compactValFor(rb);
+             }
+-            if (precision <= MAX_COMPACT_DIGITS)
+-                intCompact = Long.parseLong(new String(quick));
+-            else
+-                intVal = new BigInteger(quick);
+-            // System.out.println(" new: " +intVal+" ["+scale+"] "+precision);
+         } catch (ArrayIndexOutOfBoundsException e) {
+             throw new NumberFormatException();
+         } catch (NegativeArraySizeException e) {
+             throw new NumberFormatException();
+         }
++        this.scale = scl;
++        this.precision = prec;
++        this.intCompact = rs;
++        this.intVal = (rs != INFLATED) ? null : rb;
+     }
+ 
+     /**
+@@ -754,16 +831,18 @@
+         }
+ 
+         // Calculate intVal and scale
+-        intVal = BigInteger.valueOf(sign*significand);
++        long s = sign * significand;
++        BigInteger b;
+         if (exponent < 0) {
+-            intVal = intVal.multiply(BigInteger.valueOf(5).pow(-exponent));
++            b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
+             scale = -exponent;
+         } else if (exponent > 0) {
+-            intVal = intVal.multiply(BigInteger.valueOf(2).pow(exponent));
++            b = BigInteger.valueOf(2).pow(exponent).multiply(s);
++        } else {
++            b = BigInteger.valueOf(s);
+         }
+-        if (intVal.bitLength() <= MAX_BIGINT_BITS) {
+-            intCompact = intVal.longValue();
+-        }
++        intCompact = compactValFor(b);
++        intVal = (intCompact != INFLATED) ? null : b;
+     }
+ 
+     /**
+@@ -798,10 +877,8 @@
+      *            {@code BigDecimal}.
+      */
+     public BigDecimal(BigInteger val) {
+-        intVal = val;
+-        if (val.bitLength() <= MAX_BIGINT_BITS) {
+-            intCompact = val.longValue();
+-        }
++        intCompact = compactValFor(val);
++        intVal = (intCompact != INFLATED) ? null : val;
+     }
+ 
+     /**
+@@ -817,7 +894,7 @@
+      * @since  1.5
+      */
+     public BigDecimal(BigInteger val, MathContext mc) {
+-        intVal = val;
++        this(val);
+         if (mc.precision > 0)
+             roundThis(mc);
+     }
+@@ -833,11 +910,8 @@
+      */
+     public BigDecimal(BigInteger unscaledVal, int scale) {
+         // Negative scales are now allowed
+-        intVal = unscaledVal;
++        this(unscaledVal);
+         this.scale = scale;
+-        if (unscaledVal.bitLength() <= MAX_BIGINT_BITS) {
+-            intCompact = unscaledVal.longValue();
+-        }
+     }
+ 
+     /**
+@@ -856,7 +930,7 @@
+      * @since  1.5
+      */
+     public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
+-        intVal = unscaledVal;
++        this(unscaledVal);
+         this.scale = scale;
+         if (mc.precision > 0)
+             roundThis(mc);
+@@ -899,10 +973,8 @@
+      * @since  1.5
+      */
+     public BigDecimal(long val) {
+-        if (compactLong(val))
+-            intCompact = val;
+-        else
+-            intVal = BigInteger.valueOf(val);
++        this.intCompact = val;
++        this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
+     }
+ 
+     /**
+@@ -917,31 +989,11 @@
+      * @since  1.5
+      */
+     public BigDecimal(long val, MathContext mc) {
+-        if (compactLong(val))
+-            intCompact = val;
+-        else
+-            intVal = BigInteger.valueOf(val);
++        this(val);
+         if (mc.precision > 0)
+             roundThis(mc);
+     }
+ 
+-    /**
+-     * Trusted internal constructor
+-     */
+-    private BigDecimal(long val, int scale) {
+-        this.intCompact = val;
+-        this.scale = scale;
+-    }
+-
+-    /**
+-     * Trusted internal constructor
+-     */
+-    private BigDecimal(BigInteger intVal, long val, int scale) {
+-        this.intVal = intVal;
+-        this.intCompact = val;
+-        this.scale = scale;
+-    }
+-
+     // Static Factory Methods
+ 
+     /**
+@@ -957,12 +1009,17 @@
+      *         <tt>(unscaledVal &times; 10<sup>-scale</sup>)</tt>.
+      */
+     public static BigDecimal valueOf(long unscaledVal, int scale) {
+-        if (scale == 0 && unscaledVal >= 0 && unscaledVal <= 10) {
+-            return zeroThroughTen[(int)unscaledVal];
++        if (scale == 0)
++            return valueOf(unscaledVal);
++        else if (unscaledVal == 0) {
++            if (scale > 0 && scale < ZERO_SCALED_BY.length)
++                return ZERO_SCALED_BY[scale];
++            else
++                return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
+         }
+-        if (compactLong(unscaledVal))
+-            return new BigDecimal(unscaledVal, scale);
+-        return new BigDecimal(BigInteger.valueOf(unscaledVal), scale);
++        return new BigDecimal(unscaledVal == INFLATED ?
++                              BigInteger.valueOf(unscaledVal) : null,
++                              unscaledVal, scale, 0);
+     }
+ 
+     /**
+@@ -976,7 +1033,11 @@
+      * @return a {@code BigDecimal} whose value is {@code val}.
+      */
+     public static BigDecimal valueOf(long val) {
+-        return valueOf(val, 0);
++        if (val >= 0 && val < zeroThroughTen.length)
++            return zeroThroughTen[(int)val];
++        else if (val != INFLATED)
++            return new BigDecimal(null, val, 0, 0);
++        return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
+     }
+ 
+     /**
+@@ -1014,27 +1075,42 @@
+      * @return {@code this + augend}
+      */
+     public BigDecimal add(BigDecimal augend) {
+-        BigDecimal arg[] = {this, augend};
+-        matchScale(arg);
++        long xs = this.intCompact;
++        long ys = augend.intCompact;
++        BigInteger fst = (xs != INFLATED) ? null : this.intVal;
++        BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
++        int rscale = this.scale;
+ 
+-        long x = arg[0].intCompact;
+-        long y = arg[1].intCompact;
+-
+-        // Might be able to do a more clever check incorporating the
+-        // inflated check into the overflow computation.
+-        if (x != INFLATED && y != INFLATED) {
+-            long sum = x + y;
+-            /*
+-             * If the sum is not an overflowed value, continue to use
+-             * the compact representation.  if either of x or y is
+-             * INFLATED, the sum should also be regarded as an
+-             * overflow.  See "Hacker's Delight" section 2-12 for
+-             * explanation of the overflow test.
+-             */
+-            if ( (((sum ^ x) & (sum ^ y)) >> 63) == 0L )        // not overflowed
+-                return BigDecimal.valueOf(sum, arg[0].scale);
++        long sdiff = (long)rscale - augend.scale;
++        if (sdiff != 0) {
++            if (sdiff < 0) {
++                int raise = checkScale(-sdiff);
++                rscale = augend.scale;
++                if (xs == INFLATED ||
++                    (xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
++                    fst = bigMultiplyPowerTen(raise);
++            } else {
++                int raise = augend.checkScale(sdiff);
++                if (ys == INFLATED ||
++                    (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
++                    snd = augend.bigMultiplyPowerTen(raise);
++            }
+         }
+-        return new BigDecimal(arg[0].inflate().intVal.add(arg[1].inflate().intVal), arg[0].scale);
++        if (xs != INFLATED && ys != INFLATED) {
++            long sum = xs + ys;
++            // See "Hacker's Delight" section 2-12 for explanation of
++            // the overflow test.
++            if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
++                return new BigDecimal(null, sum, rscale, 0);
++        }
++        if (fst == null)
++            fst = BigInteger.valueOf(xs);
++        if (snd == null)
++            snd = BigInteger.valueOf(ys);
++        BigInteger sum = fst.add(snd);
++        return (fst.signum == snd.signum) ?
++            new BigDecimal(sum, INFLATED, rscale, 0) :
++            new BigDecimal(sum, rscale);
+     }
+ 
+     /**
+@@ -1072,17 +1148,19 @@
+ 
+                 // Could use a factory for zero instead of a new object
+                 if (lhsIsZero && augendIsZero)
+-                    return new BigDecimal(BigInteger.ZERO, 0, preferredScale);
++                    return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
+ 
+-
+-                result = lhsIsZero ? augend.doRound(mc) : lhs.doRound(mc);
++                result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
+ 
+                 if (result.scale() == preferredScale)
+                     return result;
+-                else if (result.scale() > preferredScale)
+-                    return new BigDecimal(result.intVal, result.intCompact, result.scale).
+-                        stripZerosToMatchScale(preferredScale);
+-                else { // result.scale < preferredScale
++                else if (result.scale() > preferredScale) {
++                    BigDecimal scaledResult =
++                        new BigDecimal(result.intVal, result.intCompact,
++                                       result.scale, 0);
++                    scaledResult.stripZerosToMatchScale(preferredScale);
++                    return scaledResult;
++                } else { // result.scale < preferredScale
+                     int precisionDiff = mc.precision - result.precision();
+                     int scaleDiff     = preferredScale - result.scale();
+ 
+@@ -1102,8 +1180,9 @@
+             augend = arg[1];
+         }
+ 
+-        return new BigDecimal(lhs.inflate().intVal.add(augend.inflate().intVal),
+-                              lhs.scale).doRound(mc);
++        BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
++                                      lhs.scale);
++        return doRound(d, mc);
+     }
+ 
+     /**
+@@ -1181,28 +1260,7 @@
+      * @return {@code this - subtrahend}
+      */
+     public BigDecimal subtract(BigDecimal subtrahend) {
+-        BigDecimal arg[] = {this, subtrahend};
+-        matchScale(arg);
+-
+-        long x = arg[0].intCompact;
+-        long y = arg[1].intCompact;
+-
+-        // Might be able to do a more clever check incorporating the
+-        // inflated check into the overflow computation.
+-        if (x != INFLATED && y != INFLATED) {
+-            long difference = x - y;
+-            /*
+-             * If the difference is not an overflowed value, continue
+-             * to use the compact representation.  if either of x or y
+-             * is INFLATED, the difference should also be regarded as
+-             * an overflow.  See "Hacker's Delight" section 2-12 for
+-             * explanation of the overflow test.
+-             */
+-            if ( ((x ^ y) & (difference ^ x) ) >> 63 == 0L )    // not overflowed
+-                return BigDecimal.valueOf(difference, arg[0].scale);
+-        }
+-        return new BigDecimal(arg[0].inflate().intVal.subtract(arg[1].inflate().intVal),
+-                              arg[0].scale);
++        return add(subtrahend.negate());
+     }
+ 
+     /**
+@@ -1220,14 +1278,11 @@
+      * @since  1.5
+      */
+     public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
++        BigDecimal nsubtrahend = subtrahend.negate();
+         if (mc.precision == 0)
+-            return subtract(subtrahend);
++            return add(nsubtrahend);
+         // share the special rounding code in add()
+-        this.inflate();
+-        subtrahend.inflate();
+-        BigDecimal rhs = new BigDecimal(subtrahend.intVal.negate(), subtrahend.scale);
+-        rhs.precision = subtrahend.precision;
+-        return add(rhs, mc);
++        return add(nsubtrahend, mc);
+     }
+ 
+     /**
+@@ -1241,7 +1296,7 @@
+     public BigDecimal multiply(BigDecimal multiplicand) {
+         long x = this.intCompact;
+         long y = multiplicand.intCompact;
+-        int productScale = checkScale((long)scale+multiplicand.scale);
++        int productScale = checkScale((long)scale + multiplicand.scale);
+ 
+         // Might be able to do a more clever check incorporating the
+         // inflated check into the overflow computation.
+@@ -1250,16 +1305,26 @@
+              * If the product is not an overflowed value, continue
+              * to use the compact representation.  if either of x or y
+              * is INFLATED, the product should also be regarded as
+-             * an overflow.  See "Hacker's Delight" section 2-12 for
+-             * explanation of the overflow test.
++             * an overflow. Before using the overflow test suggested in
++             * "Hacker's Delight" section 2-12, we perform quick checks
++             * using the precision information to see whether the overflow
++             * would occur since division is expensive on most CPUs.
+              */
+             long product = x * y;
+-            if ( !(y != 0L && product/y != x)  )        // not overflowed
+-                return BigDecimal.valueOf(product, productScale);
++            int prec = this.precision() + multiplicand.precision();
++            if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
++                return new BigDecimal(null, product, productScale, 0);
++            return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
++                                  productScale, 0);
+         }
+-
+-        BigDecimal result = new BigDecimal(this.inflate().intVal.multiply(multiplicand.inflate().intVal), productScale);
+-        return result;
++        BigInteger rb;
++        if (x == INFLATED && y == INFLATED)
++            rb = this.intVal.multiply(multiplicand.intVal);
++        else if (x != INFLATED)
++            rb = multiplicand.intVal.multiply(x);
++        else
++            rb = this.intVal.multiply(y);
++        return new BigDecimal(rb, INFLATED, productScale, 0);
+     }
+ 
+     /**
+@@ -1276,8 +1341,7 @@
+     public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
+         if (mc.precision == 0)
+             return multiply(multiplicand);
+-        BigDecimal lhs = this;
+-        return lhs.inflate().multiply(multiplicand.inflate()).doRound(mc);
++        return doRound(this.multiply(multiplicand), mc);
+     }
+ 
+     /**
+@@ -1311,7 +1375,7 @@
+     public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
+         /*
+          * IMPLEMENTATION NOTE: This method *must* return a new object
+-         * since dropDigits uses divide to generate a value whose
++         * since divideAndRound uses divide to generate a value whose
+          * scale is then modified.
+          */
+         if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
+@@ -1321,87 +1385,103 @@
+          * produce correctly scaled quotient).
+          * Take care to detect out-of-range scales
+          */
+-        BigDecimal dividend;
+-        if (checkScale((long)scale + divisor.scale) >= this.scale) {
+-            dividend = this.setScale(scale + divisor.scale);
++        BigDecimal dividend = this;
++        if (checkScale((long)scale + divisor.scale) > this.scale)
++            dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
++        else
++            divisor = divisor.setScale(checkScale((long)this.scale - scale),
++                                       ROUND_UNNECESSARY);
++        return divideAndRound(dividend.intCompact, dividend.intVal,
++                              divisor.intCompact, divisor.intVal,
++                              scale, roundingMode, scale);
++    }
++
++    /**
++     * Internally used for division operation. The dividend and divisor are
++     * passed both in {@code long} format and {@code BigInteger} format. The
++     * returned {@code BigDecimal} object is the quotient whose scale is set to
++     * the passed in scale. If the remainder is not zero, it will be rounded
++     * based on the passed in roundingMode. Also, if the remainder is zero and
++     * the last parameter, i.e. preferredScale is NOT equal to scale, the
++     * trailing zeros of the result is stripped to match the preferredScale.
++     */
++    private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
++                                             long ldivisor,  BigInteger bdivisor,
++                                             int scale, int roundingMode,
++                                             int preferredScale) {
++        boolean isRemainderZero;       // record remainder is zero or not
++        int qsign;                     // quotient sign
++        long q = 0, r = 0;             // store quotient & remainder in long
++        MutableBigInteger mq = null;   // store quotient
++        MutableBigInteger mr = null;   // store remainder
++        MutableBigInteger mdivisor = null;
++        boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
++        if (isLongDivision) {
++            q = ldividend / ldivisor;
++            if (roundingMode == ROUND_DOWN && scale == preferredScale)
++                return new BigDecimal(null, q, scale, 0);
++            r = ldividend % ldivisor;
++            isRemainderZero = (r == 0);
++            qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+         } else {
+-            dividend = this;
+-            divisor = divisor.setScale(checkScale((long)this.scale - scale));
++            if (bdividend == null)
++                bdividend = BigInteger.valueOf(ldividend);
++            // Descend into mutables for faster remainder checks
++            MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
++            mq = new MutableBigInteger();
++            if (ldivisor != INFLATED) {
++                r = mdividend.divide(ldivisor, mq);
++                isRemainderZero = (r == 0);
++                qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
++            } else {
++                mdivisor = new MutableBigInteger(bdivisor.mag);
++                mr = mdividend.divide(mdivisor, mq);
++                isRemainderZero = mr.isZero();
++                qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
++            }
+         }
+-
+-        boolean compact = dividend.intCompact != INFLATED && divisor.intCompact != INFLATED;
+-        long div = INFLATED;
+-        long rem = INFLATED;;
+-        BigInteger q=null, r=null;
+-
+-        if (compact) {
+-            div = dividend.intCompact / divisor.intCompact;
+-            rem = dividend.intCompact % divisor.intCompact;
+-        } else {
+-            // Do the division and return result if it's exact.
+-            BigInteger i[] = dividend.inflate().intVal.divideAndRemainder(divisor.inflate().intVal);
+-            q = i[0];
+-            r = i[1];
+-        }
+-
+-        // Check for exact result
+-        if (compact) {
+-            if (rem == 0)
+-                return new BigDecimal(div, scale);
+-        } else {
+-            if (r.signum() == 0)
+-                return new BigDecimal(q, scale);
+-        }
+-
+-        if (roundingMode == ROUND_UNNECESSARY)      // Rounding prohibited
+-            throw new ArithmeticException("Rounding necessary");
+-
+-        /* Round as appropriate */
+-        int signum = dividend.signum() * divisor.signum(); // Sign of result
+-        boolean increment;
+-        if (roundingMode == ROUND_UP) {             // Away from zero
+-            increment = true;
+-        } else if (roundingMode == ROUND_DOWN) {    // Towards zero
+-            increment = false;
+-        } else if (roundingMode == ROUND_CEILING) { // Towards +infinity
+-            increment = (signum > 0);
+-        } else if (roundingMode == ROUND_FLOOR) {   // Towards -infinity
+-            increment = (signum < 0);
+-        } else { // Remaining modes based on nearest-neighbor determination
++        boolean increment = false;
++        if (!isRemainderZero) {
+             int cmpFracHalf;
+-            if (compact) {
+-                 cmpFracHalf = longCompareTo(Math.abs(2*rem), Math.abs(divisor.intCompact));
++            /* Round as appropriate */
++            if (roundingMode == ROUND_UNNECESSARY) {  // Rounding prohibited
++                throw new ArithmeticException("Rounding necessary");
++            } else if (roundingMode == ROUND_UP) {      // Away from zero
++                increment = true;
++            } else if (roundingMode == ROUND_DOWN) {    // Towards zero
++                increment = false;
++            } else if (roundingMode == ROUND_CEILING) { // Towards +infinity
++                increment = (qsign > 0);
++            } else if (roundingMode == ROUND_FLOOR) {   // Towards -infinity
++                increment = (qsign < 0);
+             } else {
+-                // add(r) here is faster than multiply(2) or shiftLeft(1)
+-                cmpFracHalf= r.add(r).abs().compareTo(divisor.intVal.abs());
+-            }
+-            if (cmpFracHalf < 0) {         // We're closer to higher digit
+-                increment = false;
+-            } else if (cmpFracHalf > 0) {  // We're closer to lower digit
+-                increment = true;
+-            } else {                       // We're dead-center
+-                if (roundingMode == ROUND_HALF_UP)
++                if (isLongDivision || ldivisor != INFLATED)
++                    cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
++                else
++                    cmpFracHalf = mr.compareHalf(mdivisor);
++                if (cmpFracHalf < 0)
++                    increment = false;     // We're closer to higher digit
++                else if (cmpFracHalf > 0)  // We're closer to lower digit
++                    increment = true;
++                else if (roundingMode == ROUND_HALF_UP)
+                     increment = true;
+                 else if (roundingMode == ROUND_HALF_DOWN)
+                     increment = false;
+-                else { // roundingMode == ROUND_HALF_EVEN
+-                    if (compact)
+-                        increment = (div & 1L) != 0L;
+-                    else
+-                        increment = q.testBit(0);   // true iff q is odd
+-                }
++                else  // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
++                    increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
+             }
+         }
+-
+-        if (compact) {
++        BigDecimal res;
++        if (isLongDivision)
++            res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
++        else {
+             if (increment)
+-                div += signum; // guaranteed not to overflow
+-            return new BigDecimal(div, scale);
+-        } else {
+-            return (increment
+-                    ? new BigDecimal(q.add(BigInteger.valueOf(signum)), scale)
+-                    : new BigDecimal(q, scale));
++                mq.add(MutableBigInteger.ONE);
++            res = mq.toBigDecimal(qsign, scale);
+         }
++        if (isRemainderZero && preferredScale != scale)
++            res.stripZerosToMatchScale(preferredScale);
++        return res;
+     }
+ 
+     /**
+@@ -1499,10 +1579,12 @@
+         }
+ 
+         // Calculate preferred scale
+-        int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
+-                                                    Integer.MAX_VALUE), Integer.MIN_VALUE);
++        int preferredScale = saturateLong((long)this.scale - divisor.scale);
+         if (this.signum() == 0)        // 0/y
+-            return new BigDecimal(0, preferredScale);
++            return (preferredScale >= 0 &&
++                    preferredScale < ZERO_SCALED_BY.length) ?
++                ZERO_SCALED_BY[preferredScale] :
++                new BigDecimal(null, 0, preferredScale, 1);
+         else {
+             this.inflate();
+             divisor.inflate();
+@@ -1534,7 +1616,7 @@
+             // limit, we can add zeros too.
+ 
+             if (preferredScale > quotientScale)
+-                return quotient.setScale(preferredScale);
++                return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
+ 
+             return quotient;
+         }
+@@ -1554,14 +1636,12 @@
+      * @since  1.5
+      */
+     public BigDecimal divide(BigDecimal divisor, MathContext mc) {
+-        if (mc.precision == 0)
++        int mcp = mc.precision;
++        if (mcp == 0)
+             return divide(divisor);
+-        BigDecimal lhs = this.inflate();     // left-hand-side
+-        BigDecimal rhs = divisor.inflate();  // right-hand-side
+-        BigDecimal result;                   // work
+ 
+-        long preferredScale = (long)lhs.scale() - rhs.scale();
+-
++        BigDecimal dividend = this;
++        long preferredScale = (long)dividend.scale - divisor.scale;
+         // Now calculate the answer.  We use the existing
+         // divide-and-round method, but as this rounds to scale we have
+         // to normalize the values here to achieve the desired result.
+@@ -1574,54 +1654,43 @@
+         // the right number of digits (except in the case of a result of
+         // 1.000... which can arise when x=y, or when rounding overflows
+         // The 1.000... case will reduce properly to 1.
+-        if (rhs.signum() == 0) {      // x/0
+-            if (lhs.signum() == 0)    // 0/0
++        if (divisor.signum() == 0) {      // x/0
++            if (dividend.signum() == 0)    // 0/0
+                 throw new ArithmeticException("Division undefined");  // NaN
+             throw new ArithmeticException("Division by zero");
+         }
+-        if (lhs.signum() == 0)        // 0/y
+-            return new BigDecimal(BigInteger.ZERO,
+-                                  (int)Math.max(Math.min(preferredScale,
+-                                                         Integer.MAX_VALUE),
+-                                                Integer.MIN_VALUE));
++        if (dividend.signum() == 0)        // 0/y
++            return new BigDecimal(BigInteger.ZERO, 0,
++                                  saturateLong(preferredScale), 1);
+ 
+-        BigDecimal xprime = new BigDecimal(lhs.intVal.abs(), lhs.precision());
+-        BigDecimal yprime = new BigDecimal(rhs.intVal.abs(), rhs.precision());
+-        // xprime and yprime are now both in range 0.1 through 0.999...
+-        if (mc.roundingMode == RoundingMode.CEILING ||
+-            mc.roundingMode == RoundingMode.FLOOR) {
+-            // The floor (round toward negative infinity) and ceil
+-            // (round toward positive infinity) rounding modes are not
+-            // invariant under a sign flip.  If xprime/yprime has a
+-            // different sign than lhs/rhs, the rounding mode must be
+-            // changed.
+-            if ((xprime.signum() != lhs.signum()) ^
+-                (yprime.signum() != rhs.signum())) {
+-                mc = new MathContext(mc.precision,
+-                                     (mc.roundingMode==RoundingMode.CEILING)?
+-                                     RoundingMode.FLOOR:RoundingMode.CEILING);
+-            }
+-        }
++        // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
++        int xscale = dividend.precision();
++        int yscale = divisor.precision();
++        dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
++                                  xscale, xscale);
++        divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
++                                 yscale, yscale);
++        if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
++            yscale = divisor.scale -= 1;            // [that is, divisor *= 10]
+ 
+-        if (xprime.compareTo(yprime) > 0)    // satisfy constraint (b)
+-          yprime.scale -= 1;                 // [that is, yprime *= 10]
+-        result = xprime.divide(yprime, mc.precision, mc.roundingMode.oldMode);
+-        // correct the scale of the result...
+-        result.scale = checkScale((long)yprime.scale - xprime.scale
+-            - (rhs.scale - lhs.scale) + mc.precision);
+-        // apply the sign
+-        if (lhs.signum() != rhs.signum())
+-            result = result.negate();
++        // In order to find out whether the divide generates the exact result,
++        // we avoid calling the above divide method. 'quotient' holds the
++        // return BigDecimal object whose scale will be set to 'scl'.
++        BigDecimal quotient;
++        int scl = checkScale(preferredScale + yscale - xscale + mcp);
++        if (checkScale((long)mcp + yscale) > xscale)
++            dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
++        else
++            divisor = divisor.setScale(checkScale((long)xscale - mcp),
++                                       ROUND_UNNECESSARY);
++        quotient = divideAndRound(dividend.intCompact, dividend.intVal,
++                                  divisor.intCompact, divisor.intVal,
++                                  scl, mc.roundingMode.oldMode,
++                                  checkScale(preferredScale));
+         // doRound, here, only affects 1000000000 case.
+-        result = result.doRound(mc);
++        quotient = doRound(quotient, mc);
+ 
+-        if (result.multiply(divisor).compareTo(this) == 0) {
+-            // Apply preferred scale rules for exact quotients
+-            return result.stripZerosToMatchScale(preferredScale);
+-        }
+-        else {
+-            return result;
+-        }
++        return quotient;
+     }
+ 
+     /**
+@@ -1637,17 +1706,14 @@
+      */
+     public BigDecimal divideToIntegralValue(BigDecimal divisor) {
+         // Calculate preferred scale
+-        int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
+-                                                    Integer.MAX_VALUE), Integer.MIN_VALUE);
+-        this.inflate();
+-        divisor.inflate();
+-        if (this.abs().compareTo(divisor.abs()) < 0) {
++        int preferredScale = saturateLong((long)this.scale - divisor.scale);
++        if (this.compareMagnitude(divisor) < 0) {
+             // much faster when this << divisor
+             return BigDecimal.valueOf(0, preferredScale);
+         }
+ 
+         if(this.signum() == 0 && divisor.signum() != 0)
+-            return this.setScale(preferredScale);
++            return this.setScale(preferredScale, ROUND_UNNECESSARY);
+ 
+         // Perform a divide with enough digits to round to a correct
+         // integer value; then remove any fractional digits
+@@ -1656,19 +1722,17 @@
+                                       (long)Math.ceil(10.0*divisor.precision()/3.0) +
+                                       Math.abs((long)this.scale() - divisor.scale()) + 2,
+                                       Integer.MAX_VALUE);
+-
+         BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
+                                                                    RoundingMode.DOWN));
+         if (quotient.scale > 0) {
+-            quotient = quotient.setScale(0, RoundingMode.DOWN).
+-                stripZerosToMatchScale(preferredScale);
++            quotient = quotient.setScale(0, RoundingMode.DOWN);
++            quotient.stripZerosToMatchScale(preferredScale);
+         }
+ 
+         if (quotient.scale < preferredScale) {
+             // pad with zeros if necessary
+-            quotient = quotient.setScale(preferredScale);
++            quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
+         }
+-
+         return quotient;
+     }
+ 
+@@ -1694,12 +1758,11 @@
+      */
+     public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
+         if (mc.precision == 0 ||                        // exact result
+-            (this.abs().compareTo(divisor.abs()) < 0) ) // zero result
++            (this.compareMagnitude(divisor) < 0) )      // zero result
+             return divideToIntegralValue(divisor);
+ 
+         // Calculate preferred scale
+-        int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(),
+-                                                    Integer.MAX_VALUE), Integer.MIN_VALUE);
++        int preferredScale = saturateLong((long)this.scale - divisor.scale);
+ 
+         /*
+          * Perform a normal divide to mc.precision digits.  If the
+@@ -1708,9 +1771,8 @@
+          * digits.  Next, remove any fractional digits from the
+          * quotient and adjust the scale to the preferred value.
+          */
+-        BigDecimal result = this.divide(divisor, new MathContext(mc.precision,
+-                                                                 RoundingMode.DOWN));
+-        int resultScale = result.scale();
++        BigDecimal result = this.
++            divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
+ 
+         if (result.scale() < 0) {
+             /*
+@@ -1721,7 +1783,7 @@
+             BigDecimal product = result.multiply(divisor);
+             // If the quotient is the full integer value,
+             // |dividend-product| < |divisor|.
+-            if (this.subtract(product).abs().compareTo(divisor.abs()) >= 0) {
++            if (this.subtract(product).compareMagnitude(divisor) >= 0) {
+                 throw new ArithmeticException("Division impossible");
+             }
+         } else if (result.scale() > 0) {
+@@ -1736,11 +1798,13 @@
+ 
+         int precisionDiff;
+         if ((preferredScale > result.scale()) &&
+-            (precisionDiff = mc.precision - result.precision()) > 0  ) {
++            (precisionDiff = mc.precision - result.precision()) > 0) {
+             return result.setScale(result.scale() +
+                                    Math.min(precisionDiff, preferredScale - result.scale) );
+-        } else
+-            return result.stripZerosToMatchScale(preferredScale);
++        } else {
++            result.stripZerosToMatchScale(preferredScale);
++            return result;
++        }
+     }
+ 
+     /**
+@@ -1949,7 +2013,7 @@
+         int mag = Math.abs(n);               // magnitude of n
+         if (mc.precision > 0) {
+ 
+-            int elength = intLength(mag);    // length of n in digits
++            int elength = longDigitLength(mag); // length of n in digits
+             if (elength > mc.precision)        // X3.274 rule
+                 throw new ArithmeticException("Invalid operation");
+             workmc = new MathContext(mc.precision + elength + 1,
+@@ -1974,7 +2038,7 @@
+         if (n<0)                          // [hence mc.precision>0]
+             acc=ONE.divide(acc, workmc);
+         // round to final precision and strip zeros
+-        return acc.doRound(mc);
++        return doRound(acc, mc);
+     }
+ 
+     /**
+@@ -2068,7 +2132,7 @@
+     public BigDecimal plus(MathContext mc) {
+         if (mc.precision == 0)                 // no rounding please
+             return this;
+-        return this.doRound(mc);
++        return doRound(this, mc);
+     }
+ 
+     /**
+@@ -2109,7 +2173,11 @@
+     public int precision() {
+         int result = precision;
+         if (result == 0) {
+-            result = digitLength();
++            long s = intCompact;
++            if (s != INFLATED)
++                result = longDigitLength(s);
++            else
++                result = bigDigitLength(inflate());
+             precision = result;
+         }
+         return result;
+@@ -2125,7 +2193,7 @@
+      * @since  1.2
+      */
+     public BigInteger unscaledValue() {
+-        return this.inflate().intVal;
++        return this.inflate();
+     }
+ 
+     // Rounding Modes
+@@ -2302,30 +2370,34 @@
+         if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
+             throw new IllegalArgumentException("Invalid rounding mode");
+ 
+-        if (newScale == this.scale)        // easy case
++        int oldScale = this.scale;
++        if (newScale == oldScale)        // easy case
+             return this;
+         if (this.signum() == 0)            // zero can have any scale
+             return BigDecimal.valueOf(0, newScale);
+-        if (newScale > this.scale) {
+-            // [we can use checkScale to assure multiplier is valid]
+-            int raise = checkScale((long)newScale - this.scale);
+ 
+-            if (intCompact != INFLATED) {
+-                long scaledResult = longTenToThe(intCompact, raise);
+-                if (scaledResult != INFLATED)
+-                    return BigDecimal.valueOf(scaledResult, newScale);
+-                this.inflate();
+-            }
+-
+-            BigDecimal result = new BigDecimal(intVal.multiply(tenToThe(raise)),
+-                                               newScale);
+-            if (this.precision > 0)
+-                result.precision = this.precision + newScale - this.scale;
+-            return result;
++        long rs = this.intCompact;
++        if (newScale > oldScale) {
++            int raise = checkScale((long)newScale - oldScale);
++            BigInteger rb = null;
++            if (rs == INFLATED ||
++                (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
++                rb = bigMultiplyPowerTen(raise);
++            return new BigDecimal(rb, rs, newScale,
++                                  (precision > 0) ? precision + raise : 0);
++        } else {
++            // newScale < oldScale -- drop some digits
++            // Can't predict the precision due to the effect of rounding.
++            int drop = checkScale((long)oldScale - newScale);
++            if (drop < LONG_TEN_POWERS_TABLE.length)
++                return divideAndRound(rs, this.intVal,
++                                      LONG_TEN_POWERS_TABLE[drop], null,
++                                      newScale, roundingMode, newScale);
++            else
++                return divideAndRound(rs, this.intVal,
++                                      INFLATED, bigTenToThe(drop),
++                                      newScale, roundingMode, newScale);
+         }
+-        // scale < this.scale
+-        // we cannot perfectly predict the precision after rounding
+-        return divide(ONE, newScale, roundingMode);
+     }
+ 
+     /**
+@@ -2388,12 +2460,8 @@
+     public BigDecimal movePointLeft(int n) {
+         // Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
+         int newScale = checkScale((long)scale + n);
+-        BigDecimal num;
+-        if (intCompact != INFLATED)
+-            num = BigDecimal.valueOf(intCompact, newScale);
+-        else
+-            num = new BigDecimal(intVal, newScale);
+-        return (num.scale<0 ? num.setScale(0) : num);
++        BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
++        return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
+     }
+ 
+     /**
+@@ -2414,12 +2482,8 @@
+     public BigDecimal movePointRight(int n) {
+         // Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
+         int newScale = checkScale((long)scale - n);
+-        BigDecimal num;
+-        if (intCompact != INFLATED)
+-            num = BigDecimal.valueOf(intCompact, newScale);
+-        else
+-            num = new BigDecimal(intVal, newScale);
+-        return (num.scale<0 ? num.setScale(0) : num);
++        BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
++        return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
+     }
+ 
+     /**
+@@ -2433,10 +2497,8 @@
+      * @since 1.5
+      */
+     public BigDecimal scaleByPowerOfTen(int n) {
+-        this.inflate();
+-        BigDecimal num = new BigDecimal(intVal, checkScale((long)scale - n));
+-        num.precision = precision;
+-        return num;
++        return new BigDecimal(intVal, intCompact,
++                              checkScale((long)scale - n), precision);
+     }
+ 
+     /**
+@@ -2454,7 +2516,9 @@
+      */
+     public BigDecimal stripTrailingZeros() {
+         this.inflate();
+-        return (new BigDecimal(intVal, scale)).stripZerosToMatchScale(Long.MIN_VALUE);
++        BigDecimal result = new BigDecimal(intVal, scale);
++        result.stripZerosToMatchScale(Long.MIN_VALUE);
++        return result;
+     }
+ 
+     // Comparison Operations
+@@ -2477,32 +2541,67 @@
+      *          less than, equal to, or greater than {@code val}.
+      */
+     public int compareTo(BigDecimal val) {
+-        if (this.scale == val.scale &&
+-            this.intCompact != INFLATED &&
+-            val.intCompact  != INFLATED)
+-            return longCompareTo(this.intCompact, val.intCompact);
++        // Quick path for equal scale and non-inflated case.
++        if (scale == val.scale) {
++            long xs = intCompact;
++            long ys = val.intCompact;
++            if (xs != INFLATED && ys != INFLATED)
++                return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
++        }
++        int xsign = this.signum();
++        int ysign = val.signum();
++        if (xsign != ysign)
++            return (xsign > ysign) ? 1 : -1;
++        if (xsign == 0)
++            return 0;
++        int cmp = compareMagnitude(val);
++        return (xsign > 0) ? cmp : -cmp;
++    }
+ 
+-        // Optimization: would run fine without the next three lines
+-        int sigDiff = signum() - val.signum();
+-        if (sigDiff != 0)
+-            return (sigDiff > 0 ? 1 : -1);
++    /**
++     * Version of compareTo that ignores sign.
++     */
++    private int compareMagnitude(BigDecimal val) {
++        // Match scales, avoid unnecessary inflation
++        long ys = val.intCompact;
++        long xs = this.intCompact;
++        if (xs == 0)
++            return (ys == 0) ? 0 : -1;
++        if (ys == 0)
++            return 1;
+ 
+-        // If the (adjusted) exponents are different we do not need to
+-        // expensively match scales and compare the significands
+-        int aethis = this.precision() - this.scale;    // [-1]
+-        int aeval  =  val.precision() - val.scale;     // [-1]
+-        if (aethis < aeval)
+-            return -this.signum();
+-        else if (aethis > aeval)
+-            return this.signum();
+-
+-        // Scale and compare intVals
+-        BigDecimal arg[] = {this, val};
+-        matchScale(arg);
+-        if (arg[0].intCompact != INFLATED &&
+-            arg[1].intCompact != INFLATED)
+-            return longCompareTo(arg[0].intCompact, arg[1].intCompact);
+-        return arg[0].inflate().intVal.compareTo(arg[1].inflate().intVal);
++        int sdiff = this.scale - val.scale;
++        if (sdiff != 0) {
++            // Avoid matching scales if the (adjusted) exponents differ
++            int xae = this.precision() - this.scale;   // [-1]
++            int yae = val.precision() - val.scale;     // [-1]
++            if (xae < yae)
++                return -1;
++            if (xae > yae)
++                return 1;
++            BigInteger rb = null;
++            if (sdiff < 0) {
++                if ( (xs == INFLATED ||
++                      (xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
++                     ys == INFLATED) {
++                    rb = bigMultiplyPowerTen(-sdiff);
++                    return rb.compareMagnitude(val.intVal);
++                }
++            } else { // sdiff > 0
++                if ( (ys == INFLATED ||
++                      (ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
++                     xs == INFLATED) {
++                    rb = val.bigMultiplyPowerTen(sdiff);
++                    return this.intVal.compareMagnitude(rb);
++                }
++            }
++        }
++        if (xs != INFLATED)
++            return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
++        else if (ys != INFLATED)
++            return 1;
++        else
++            return this.intVal.compareMagnitude(val.intVal);
+     }
+ 
+     /**
+@@ -2521,15 +2620,25 @@
+      * @see    #compareTo(java.math.BigDecimal)
+      * @see    #hashCode
+      */
++    @Override
+     public boolean equals(Object x) {
+         if (!(x instanceof BigDecimal))
+             return false;
+         BigDecimal xDec = (BigDecimal) x;
++        if (x == this)
++            return true;
+         if (scale != xDec.scale)
+             return false;
+-        if (this.intCompact != INFLATED && xDec.intCompact != INFLATED)
+-            return this.intCompact == xDec.intCompact;
+-        return this.inflate().intVal.equals(xDec.inflate().intVal);
++        long s = this.intCompact;
++        long xs = xDec.intCompact;
++        if (s != INFLATED) {
++            if (xs == INFLATED)
++                xs = compactValFor(xDec.intVal);
++            return xs == s;
++        } else if (xs != INFLATED)
++            return xs == compactValFor(this.intVal);
++
++        return this.inflate().equals(xDec.inflate());
+     }
+ 
+     /**
+@@ -2572,11 +2681,12 @@
+      * @return hash code for this {@code BigDecimal}.
+      * @see #equals(Object)
+      */
++    @Override
+     public int hashCode() {
+         if (intCompact != INFLATED) {
+-            long val2 = (intCompact < 0)?-intCompact:intCompact;
++            long val2 = (intCompact < 0)? -intCompact : intCompact;
+             int temp = (int)( ((int)(val2 >>> 32)) * 31  +
+-                              (val2 & 0xffffffffL));
++                              (val2 & LONG_MASK));
+             return 31*((intCompact < 0) ?-temp:temp) + scale;
+         } else
+             return 31*intVal.hashCode() + scale;
+@@ -2683,10 +2793,12 @@
+      * @see    Character#forDigit
+      * @see    #BigDecimal(java.lang.String)
+      */
++    @Override
+     public String toString() {
+-        if (stringCache == null)
+-            stringCache = layoutChars(true);
+-        return stringCache;
++        String sc = stringCache;
++        if (sc == null)
++            stringCache = sc = layoutChars(true);
++        return sc;
+     }
+ 
+     /**
+@@ -2802,7 +2914,7 @@
+      */
+     public BigInteger toBigInteger() {
+         // force to an integer, quietly
+-        return this.setScale(0, ROUND_DOWN).inflate().intVal;
++        return this.setScale(0, ROUND_DOWN).inflate();
+     }
+ 
+     /**
+@@ -2817,7 +2929,7 @@
+      */
+     public BigInteger toBigIntegerExact() {
+         // round to an integer, with Exception if decimal part non-0
+-        return this.setScale(0, ROUND_UNNECESSARY).inflate().intVal;
++        return this.setScale(0, ROUND_UNNECESSARY).inflate();
+     }
+ 
+     /**
+@@ -2868,10 +2980,10 @@
+         if ((this.precision() - this.scale) <= 0)
+             throw new ArithmeticException("Rounding necessary");
+         // round to an integer, with Exception if decimal part non-0
+-        BigDecimal num = this.setScale(0, ROUND_UNNECESSARY).inflate();
++        BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
+         if (num.precision() >= 19) // need to check carefully
+             LongOverflow.check(num);
+-        return num.intVal.longValue();
++        return num.inflate().longValue();
+     }
+ 
+     private static class LongOverflow {
+@@ -2882,6 +2994,7 @@
+         private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
+ 
+         public static void check(BigDecimal num) {
++            num.inflate();
+             if ((num.intVal.compareTo(LONGMIN) < 0) ||
+                 (num.intVal.compareTo(LONGMAX) > 0))
+                 throw new java.lang.ArithmeticException("Overflow");
+@@ -3037,7 +3150,105 @@
+         return BigDecimal.valueOf(1, this.scale());
+     }
+ 
+-    // Private "Helper" Methods
++
++    // Private class to build a string representation for BigDecimal object.
++    // "StringBuilderHelper" is constructed as a thread local variable so it is
++    // thread safe. The StringBuilder field acts as a buffer to hold the temporary
++    // representation of BigDecimal. The cmpCharArray holds all the characters for
++    // the compact representation of BigDecimal (except for '-' sign' if it is
++    // negative) if its intCompact field is not INFLATED. It is shared by all
++    // calls to toString() and its variants in that particular thread.
++    static class StringBuilderHelper {
++        final StringBuilder sb;    // Placeholder for BigDecimal string
++        final char[] cmpCharArray; // character array to place the intCompact
++
++        StringBuilderHelper() {
++            sb = new StringBuilder();
++            // All non negative longs can be made to fit into 19 character array.
++            cmpCharArray = new char[19];
++        }
++
++        // Accessors.
++        StringBuilder getStringBuilder() {
++            sb.setLength(0);
++            return sb;
++        }
++
++        char[] getCompactCharArray() {
++            return cmpCharArray;
++        }
++
++        /**
++         * Places characters representing the intCompact in {@code long} into
++         * cmpCharArray and returns the offset to the array where the
++         * representation starts.
++         *
++         * @param intCompact the number to put into the cmpCharArray.
++         * @return offset to the array where the representation starts.
++         * Note: intCompact must be greater or equal to zero.
++         */
++        int putIntCompact(long intCompact) {
++            assert intCompact >= 0;
++
++            long q;
++            int r;
++            // since we start from the least significant digit, charPos points to
++            // the last character in cmpCharArray.
++            int charPos = cmpCharArray.length;
++
++            // Get 2 digits/iteration using longs until quotient fits into an int
++            while (intCompact > Integer.MAX_VALUE) {
++                q = intCompact / 100;
++                r = (int)(intCompact - q * 100);
++                intCompact = q;
++                cmpCharArray[--charPos] = DIGIT_ONES[r];
++                cmpCharArray[--charPos] = DIGIT_TENS[r];
++            }
++
++            // Get 2 digits/iteration using ints when i2 >= 100
++            int q2;
++            int i2 = (int)intCompact;
++            while (i2 >= 100) {
++                q2 = i2 / 100;
++                r  = i2 - q2 * 100;
++                i2 = q2;
++                cmpCharArray[--charPos] = DIGIT_ONES[r];
++                cmpCharArray[--charPos] = DIGIT_TENS[r];
++            }
++
++            cmpCharArray[--charPos] = DIGIT_ONES[i2];
++            if (i2 >= 10)
++                cmpCharArray[--charPos] = DIGIT_TENS[i2];
++
++            return charPos;
++        }
++
++        final static char[] DIGIT_TENS = {
++            '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
++            '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
++            '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
++            '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
++            '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
++            '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
++            '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
++            '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
++            '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
++            '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
++        };
++
++        final static char[] DIGIT_ONES = {
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
++        };
++    }
+ 
+     /**
+      * Lay out this {@code BigDecimal} into a {@code char[]} array.
+@@ -3054,41 +3265,47 @@
+                 Long.toString(intCompact):
+                 intVal.toString();
+ 
++        StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
++        char[] coeff;
++        int offset;  // offset is the starting index for coeff array
+         // Get the significand as an absolute value
+-        char coeff[];
+-        if (intCompact != INFLATED)
+-            coeff = Long.toString(Math.abs(intCompact)).toCharArray();
+-        else
+-            coeff = intVal.abs().toString().toCharArray();
++        if (intCompact != INFLATED) {
++            offset = sbHelper.putIntCompact(Math.abs(intCompact));
++            coeff  = sbHelper.getCompactCharArray();
++        } else {
++            offset = 0;
++            coeff  = intVal.abs().toString().toCharArray();
++        }
+ 
+         // Construct a buffer, with sufficient capacity for all cases.
+         // If E-notation is needed, length will be: +1 if negative, +1
+         // if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
+         // Otherwise it could have +1 if negative, plus leading "0.00000"
+-        StringBuilder buf=new StringBuilder(coeff.length+14);
++        StringBuilder buf = sbHelper.getStringBuilder();
+         if (signum() < 0)             // prefix '-' if negative
+             buf.append('-');
+-        long adjusted = -(long)scale + (coeff.length-1);
++        int coeffLen = coeff.length - offset;
++        long adjusted = -(long)scale + (coeffLen -1);
+         if ((scale >= 0) && (adjusted >= -6)) { // plain number
+-            int pad = scale - coeff.length;  // count of padding zeros
+-            if (pad >= 0) {                  // 0.xxx form
++            int pad = scale - coeffLen;         // count of padding zeros
++            if (pad >= 0) {                     // 0.xxx form
+                 buf.append('0');
+                 buf.append('.');
+                 for (; pad>0; pad--) {
+                     buf.append('0');
+                 }
+-                buf.append(coeff);
++                buf.append(coeff, offset, coeffLen);
+             } else {                         // xx.xx form
+-                buf.append(coeff, 0, -pad);
++                buf.append(coeff, offset, -pad);
+                 buf.append('.');
+-                buf.append(coeff, -pad, scale);
++                buf.append(coeff, -pad + offset, scale);
+             }
+         } else { // E-notation is needed
+             if (sci) {                       // Scientific notation
+-                buf.append(coeff[0]);        // first character
+-                if (coeff.length > 1) {      // more to come
++                buf.append(coeff[offset]);   // first character
++                if (coeffLen > 1) {          // more to come
+                     buf.append('.');
+-                    buf.append(coeff, 1, coeff.length-1);
++                    buf.append(coeff, offset + 1, coeffLen - 1);
+                 }
+             } else {                         // Engineering notation
+                 int sig = (int)(adjusted % 3);
+@@ -3112,15 +3329,15 @@
+                     default:
+                         throw new AssertionError("Unexpected sig value " + sig);
+                     }
+-                } else if (sig >= coeff.length) {   // significand all in integer
+-                    buf.append(coeff, 0, coeff.length);
++                } else if (sig >= coeffLen) {   // significand all in integer
++                    buf.append(coeff, offset, coeffLen);
+                     // may need some zeros, too
+-                    for (int i = sig - coeff.length; i > 0; i--)
++                    for (int i = sig - coeffLen; i > 0; i--)
+                         buf.append('0');
+                 } else {                     // xx.xxE form
+-                    buf.append(coeff, 0, sig);
++                    buf.append(coeff, offset, sig);
+                     buf.append('.');
+-                    buf.append(coeff, sig, coeff.length-sig);
++                    buf.append(coeff, offset + sig, coeffLen - sig);
+                 }
+             }
+             if (adjusted != 0) {             // [!sci could have made 0]
+@@ -3139,9 +3356,17 @@
+      * @param  n the power of ten to be returned (>=0)
+      * @return a {@code BigInteger} with the value (10<sup>n</sup>)
+      */
+-    private static BigInteger tenToThe(int n) {
+-        if (n < TENPOWERS.length)     // use value from constant array
+-            return TENPOWERS[n];
++    private static BigInteger bigTenToThe(int n) {
++        if (n < 0)
++            return BigInteger.ZERO;
++
++        if (n < BIG_TEN_POWERS_TABLE_MAX) {
++            BigInteger[] pows = BIG_TEN_POWERS_TABLE;
++            if (n < pows.length)
++                return pows[n];
++            else
++                return expandBigIntegerTenPowers(n);
++        }
+         // BigInteger.pow is slow, so make 10**n by constructing a
+         // BigInteger from a character string (still not very fast)
+         char tenpow[] = new char[n + 1];
+@@ -3150,58 +3375,145 @@
+             tenpow[i] = '0';
+         return new BigInteger(tenpow);
+     }
+-    private static BigInteger TENPOWERS[] = {BigInteger.ONE,
++
++    /**
++     * Expand the BIG_TEN_POWERS_TABLE array to contain at least 10**n.
++     *
++     * @param n the power of ten to be returned (>=0)
++     * @return a {@code BigDecimal} with the value (10<sup>n</sup>) and
++     *         in the meantime, the BIG_TEN_POWERS_TABLE array gets
++     *         expanded to the size greater than n.
++     */
++    private static BigInteger expandBigIntegerTenPowers(int n) {
++        synchronized(BigDecimal.class) {
++            BigInteger[] pows = BIG_TEN_POWERS_TABLE;
++            int curLen = pows.length;
++            // The following comparison and the above synchronized statement is
++            // to prevent multiple threads from expanding the same array.
++            if (curLen <= n) {
++                int newLen = curLen << 1;
++                while (newLen <= n)
++                    newLen <<= 1;
++                pows = Arrays.copyOf(pows, newLen);
++                for (int i = curLen; i < newLen; i++)
++                    pows[i] = pows[i - 1].multiply(BigInteger.TEN);
++                // Based on the following facts:
++                // 1. pows is a private local varible;
++                // 2. the following store is a volatile store.
++                // the newly created array elements can be safely published.
++                BIG_TEN_POWERS_TABLE = pows;
++            }
++            return pows[n];
++        }
++    }
++
++    private static final long[] LONG_TEN_POWERS_TABLE = {
++        1,                     // 0 / 10^0
++        10,                    // 1 / 10^1
++        100,                   // 2 / 10^2
++        1000,                  // 3 / 10^3
++        10000,                 // 4 / 10^4
++        100000,                // 5 / 10^5
++        1000000,               // 6 / 10^6
++        10000000,              // 7 / 10^7
++        100000000,             // 8 / 10^8
++        1000000000,            // 9 / 10^9
++        10000000000L,          // 10 / 10^10
++        100000000000L,         // 11 / 10^11
++        1000000000000L,        // 12 / 10^12
++        10000000000000L,       // 13 / 10^13
++        100000000000000L,      // 14 / 10^14
++        1000000000000000L,     // 15 / 10^15
++        10000000000000000L,    // 16 / 10^16
++        100000000000000000L,   // 17 / 10^17
++        1000000000000000000L   // 18 / 10^18
++    };
++
++    private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
+         BigInteger.valueOf(10),       BigInteger.valueOf(100),
+         BigInteger.valueOf(1000),     BigInteger.valueOf(10000),
+         BigInteger.valueOf(100000),   BigInteger.valueOf(1000000),
+         BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
+-        BigInteger.valueOf(1000000000)};
++        BigInteger.valueOf(1000000000),
++        BigInteger.valueOf(10000000000L),
++        BigInteger.valueOf(100000000000L),
++        BigInteger.valueOf(1000000000000L),
++        BigInteger.valueOf(10000000000000L),
++        BigInteger.valueOf(100000000000000L),
++        BigInteger.valueOf(1000000000000000L),
++        BigInteger.valueOf(10000000000000000L),
++        BigInteger.valueOf(100000000000000000L),
++        BigInteger.valueOf(1000000000000000000L)
++    };
++
++    private static final int BIG_TEN_POWERS_TABLE_INITLEN =
++        BIG_TEN_POWERS_TABLE.length;
++    private static final int BIG_TEN_POWERS_TABLE_MAX =
++        16 * BIG_TEN_POWERS_TABLE_INITLEN;
++
++    private static final long THRESHOLDS_TABLE[] = {
++        Long.MAX_VALUE,                     // 0
++        Long.MAX_VALUE/10L,                 // 1
++        Long.MAX_VALUE/100L,                // 2
++        Long.MAX_VALUE/1000L,               // 3
++        Long.MAX_VALUE/10000L,              // 4
++        Long.MAX_VALUE/100000L,             // 5
++        Long.MAX_VALUE/1000000L,            // 6
++        Long.MAX_VALUE/10000000L,           // 7
++        Long.MAX_VALUE/100000000L,          // 8
++        Long.MAX_VALUE/1000000000L,         // 9
++        Long.MAX_VALUE/10000000000L,        // 10
++        Long.MAX_VALUE/100000000000L,       // 11
++        Long.MAX_VALUE/1000000000000L,      // 12
++        Long.MAX_VALUE/10000000000000L,     // 13
++        Long.MAX_VALUE/100000000000000L,    // 14
++        Long.MAX_VALUE/1000000000000000L,   // 15
++        Long.MAX_VALUE/10000000000000000L,  // 16
++        Long.MAX_VALUE/100000000000000000L, // 17
++        Long.MAX_VALUE/1000000000000000000L // 18
++    };
+ 
+     /**
+      * Compute val * 10 ^ n; return this product if it is
+      * representable as a long, INFLATED otherwise.
+      */
+-    private static long longTenToThe(long val, int n) {
+-        // System.err.print("\tval " + val + "\t power " + n + "\tresult ");
+-        if (n >= 0 && n < thresholds.length) {
+-            if (Math.abs(val) <= thresholds[n][0] ) {
+-                // System.err.println(val * thresholds[n][1]);
+-                return val * thresholds[n][1];
+-            }
++    private static long longMultiplyPowerTen(long val, int n) {
++        if (val == 0 || n <= 0)
++            return val;
++        long[] tab = LONG_TEN_POWERS_TABLE;
++        long[] bounds = THRESHOLDS_TABLE;
++        if (n < tab.length && n < bounds.length) {
++            long tenpower = tab[n];
++            if (val == 1)
++                return tenpower;
++            if (Math.abs(val) <= bounds[n])
++                return val * tenpower;
+         }
+-        // System.err.println(INFLATED);
+         return INFLATED;
+     }
+ 
+-    private static long thresholds[][] = {
+-        {Long.MAX_VALUE,                        1L},            // 0
+-        {Long.MAX_VALUE/10L,                    10L},           // 1
+-        {Long.MAX_VALUE/100L,                   100L},          // 2
+-        {Long.MAX_VALUE/1000L,                  1000L},         // 3
+-        {Long.MAX_VALUE/10000L,                 10000L},        // 4
+-        {Long.MAX_VALUE/100000L,                100000L},       // 5
+-        {Long.MAX_VALUE/1000000L,               1000000L},      // 6
+-        {Long.MAX_VALUE/10000000L,              10000000L},     // 7
+-        {Long.MAX_VALUE/100000000L,             100000000L},    // 8
+-        {Long.MAX_VALUE/1000000000L,            1000000000L},   // 9
+-        {Long.MAX_VALUE/10000000000L,           10000000000L},  // 10
+-        {Long.MAX_VALUE/100000000000L,          100000000000L}, // 11
+-        {Long.MAX_VALUE/1000000000000L,         1000000000000L},// 12
+-        {Long.MAX_VALUE/100000000000000L,       10000000000000L},// 13
+-    };
++    /**
++     * Compute this * 10 ^ n.
++     * Needed mainly to allow special casing to trap zero value
++     */
++    private BigInteger bigMultiplyPowerTen(int n) {
++        if (n <= 0)
++            return this.inflate();
+ 
+-    private static boolean compactLong(long val) {
+-        return (val != Long.MIN_VALUE);
++        if (intCompact != INFLATED)
++            return bigTenToThe(n).multiply(intCompact);
++        else
++            return intVal.multiply(bigTenToThe(n));
+     }
+ 
+     /**
+      * Assign appropriate BigInteger to intVal field if intVal is
+      * null, i.e. the compact representation is in use.
+      */
+-    private BigDecimal inflate() {
++    private BigInteger inflate() {
+         if (intVal == null)
+             intVal = BigInteger.valueOf(intCompact);
+-        return this;
++        return intVal;
+     }
+ 
+     /**
+@@ -3218,10 +3530,13 @@
+      *         {@code BigDecimal}s to be aligned.
+      */
+     private static void matchScale(BigDecimal[] val) {
+-        if (val[0].scale < val[1].scale)
+-            val[0] = val[0].setScale(val[1].scale);
+-        else if (val[1].scale < val[0].scale)
+-            val[1] = val[1].setScale(val[0].scale);
++        if (val[0].scale == val[1].scale) {
++            return;
++        } else if (val[0].scale < val[1].scale) {
++            val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
++        } else if (val[1].scale < val[0].scale) {
++            val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
++        }
+     }
+ 
+     /**
+@@ -3240,9 +3555,7 @@
+             throw new java.io.StreamCorruptedException(message);
+         // [all values of scale are now allowed]
+         }
+-        // Set intCompact to uninitialized value; could also see if the
+-        // intVal was small enough to fit as a compact value.
+-        intCompact = INFLATED;
++        intCompact = compactValFor(intVal);
+     }
+ 
+    /**
+@@ -3259,83 +3572,65 @@
+        s.defaultWriteObject();
+    }
+ 
++
+     /**
+-     * Returns the length of this {@code BigDecimal}, in decimal digits.
++     * Returns the length of the absolute value of a {@code long}, in decimal
++     * digits.
+      *
+-     * Notes:
+-     *<ul>
+-     * <li> This is performance-critical; most operations where a
+-     *      context is supplied will need at least one call to this
+-     *      method.
++     * @param x the {@code long}
++     * @return the length of the unscaled value, in deciaml digits.
++     */
++    private static int longDigitLength(long x) {
++        /*
++         * As described in "Bit Twiddling Hacks" by Sean Anderson,
++         * (http://graphics.stanford.edu/~seander/bithacks.html)
++         * integer log 10 of x is within 1 of
++         * (1233/4096)* (1 + integer log 2 of x).
++         * The fraction 1233/4096 approximates log10(2). So we first
++         * do a version of log2 (a variant of Long class with
++         * pre-checks and opposite directionality) and then scale and
++         * check against powers table. This is a little simpler in
++         * present context than the version in Hacker's Delight sec
++         * 11-4.  Adding one to bit length allows comparing downward
++         * from the LONG_TEN_POWERS_TABLE that we need anyway.
++         */
++        assert x != INFLATED;
++        if (x < 0)
++            x = -x;
++        if (x < 10) // must screen for 0, might as well 10
++            return 1;
++        int n = 64; // not 63, to avoid needing to add 1 later
++        int y = (int)(x >>> 32);
++        if (y == 0) { n -= 32; y = (int)x; }
++        if (y >>> 16 == 0) { n -= 16; y <<= 16; }
++        if (y >>> 24 == 0) { n -=  8; y <<=  8; }
++        if (y >>> 28 == 0) { n -=  4; y <<=  4; }
++        if (y >>> 30 == 0) { n -=  2; y <<=  2; }
++        int r = (((y >>> 31) + n) * 1233) >>> 12;
++        long[] tab = LONG_TEN_POWERS_TABLE;
++        // if r >= length, must have max possible digits for long
++        return (r >= tab.length || x < tab[r])? r : r+1;
++    }
++
++    /**
++     * Returns the length of the absolute value of a BigInteger, in
++     * decimal digits.
+      *
+-     * <li> This should be a method on BigInteger; the call to this
+-     *      method in precision() can then be replaced with the
+-     *      term: intVal.digitLength().  It could also be called
+-     *      precision() in BigInteger.
+-     *
+-     *      Better still -- the precision lookaside could be moved to
+-     *      BigInteger, too.
+-     *
+-     * <li> This could/should use MutableBigIntegers directly for the
+-     *      reduction loop.
+-     *<ul>
++     * @param b the BigInteger
+      * @return the length of the unscaled value, in decimal digits
+      */
+-    private int digitLength() {
+-        if (intCompact != INFLATED && Math.abs(intCompact) <= Integer.MAX_VALUE)
+-            return intLength(Math.abs((int)intCompact));
+-        if (signum() == 0)       // 0 is one decimal digit
++    private static int bigDigitLength(BigInteger b) {
++        /*
++         * Same idea as the long version, but we need a better
++         * approximation of log10(2). Using 646456993/2^31
++         * is accurate up to max possible reported bitLength.
++         */
++        if (b.signum == 0)
+             return 1;
+-        this.inflate();
+-        // we have a nonzero magnitude
+-        BigInteger work = intVal;
+-        int digits = 0;                 // counter
+-        for (;work.mag.length>1;) {
+-            // here when more than one integer in the magnitude; divide
+-            // by a billion (reduce by 9 digits) and try again
+-            work = work.divide(TENPOWERS[9]);
+-            digits += 9;
+-            if (work.signum() == 0)     // the division was exact
+-                return digits;          // (a power of a billion)
+-        }
+-        // down to a simple nonzero integer
+-        digits += intLength(work.mag[0]);
+-        // System.out.println("digitLength... "+this+"  ->  "+digits);
+-        return digits;
++        int r = (int)((((long)b.bitLength() + 1) * 646456993) >>> 31);
++        return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
+     }
+ 
+-    private static int[] ilogTable = {
+-        0,
+-        9,
+-        99,
+-        999,
+-        9999,
+-        99999,
+-        999999,
+-        9999999,
+-        99999999,
+-        999999999,
+-        Integer.MAX_VALUE};
+-
+-    /**
+-     * Returns the length of an unsigned {@code int}, in decimal digits.
+-     * @param i the {@code int} (treated as unsigned)
+-     * @return the length of the unscaled value, in decimal digits
+-     */
+-    private int intLength(int x) {
+-        int digits;
+-        if (x < 0) {            // 'negative' is 10 digits unsigned
+-            return  10;
+-        } else {                // positive integer
+-            if (x <= 9)
+-                return 1;
+-            // "Hacker's Delight"  section 11-4
+-            for(int i = -1; ; i++) {
+-                if (x <= ilogTable[i+1])
+-                    return i +1;
+-            }
+-        }
+-    }
+ 
+     /**
+      * Remove insignificant trailing zeros from this
+@@ -3352,10 +3647,9 @@
+      * to be closed to the preferred scale.
+      */
+     private BigDecimal stripZerosToMatchScale(long preferredScale) {
+-        boolean compact = (intCompact != INFLATED);
+         this.inflate();
+         BigInteger qr[];                // quotient-remainder pair
+-        while ( intVal.abs().compareTo(BigInteger.TEN) >= 0 &&
++        while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
+                 scale > preferredScale) {
+             if (intVal.testBit(0))
+                 break;                  // odd number cannot end in 0
+@@ -3367,17 +3661,16 @@
+             if (precision > 0)          // adjust precision if known
+               precision--;
+         }
+-        if (compact)
+-            intCompact = intVal.longValue();
++        if (intVal != null)
++            intCompact = compactValFor(intVal);
+         return this;
+     }
+ 
+     /**
+      * Check a scale for Underflow or Overflow.  If this BigDecimal is
+-     * uninitialized or initialized and nonzero, throw an exception if
+-     * the scale is out of range.  If this is zero, saturate the scale
+-     * to the extreme value of the right sign if the scale is out of
+-     * range.
++     * nonzero, throw an exception if the scale is outof range. If this
++     * is zero, saturate the scale to the extreme value of the right
++     * sign if the scale is out of range.
+      *
+      * @param val The new scale.
+      * @throws ArithmeticException (overflow or underflow) if the new
+@@ -3385,19 +3678,15 @@
+      * @return validated scale as an int.
+      */
+     private int checkScale(long val) {
+-        if ((int)val != val) {
+-            if ((this.intCompact != INFLATED && this.intCompact != 0) ||
+-                (this.intVal   != null     && this.signum() != 0) ||
+-                (this.intVal == null && this.intCompact == INFLATED) ) {
+-                if (val > Integer.MAX_VALUE)
+-                    throw new ArithmeticException("Underflow");
+-                if (val < Integer.MIN_VALUE)
+-                    throw new ArithmeticException("Overflow");
+-            } else {
+-                return (val > Integer.MAX_VALUE)?Integer.MAX_VALUE:Integer.MIN_VALUE;
+-            }
++        int asInt = (int)val;
++        if (asInt != val) {
++            asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
++            BigInteger b;
++            if (intCompact != 0 &&
++                ((b = intVal) == null || b.signum() != 0))
++                throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+         }
+-        return (int)val;
++        return asInt;
+     }
+ 
+     /**
+@@ -3410,7 +3699,7 @@
+      *         rounding mode is {@code UNNECESSARY}.
+      */
+     private BigDecimal roundOp(MathContext mc) {
+-        BigDecimal rounded = doRound(mc);
++        BigDecimal rounded = doRound(this, mc);
+         return rounded;
+     }
+ 
+@@ -3426,7 +3715,7 @@
+      *         {@code BigDecimal} operation would require rounding.
+      */
+     private void roundThis(MathContext mc) {
+-        BigDecimal rounded = doRound(mc);
++        BigDecimal rounded = doRound(this, mc);
+         if (rounded == this)                 // wasn't rounded
+             return;
+         this.intVal     = rounded.intVal;
+@@ -3448,56 +3737,56 @@
+      *         {@code RoundingMode.UNNECESSARY} and the
+      *         result is inexact.
+      */
+-    private BigDecimal doRound(MathContext mc) {
+-        this.inflate();
+-        if (precision == 0) {
+-            if (mc.roundingMax != null
+-                && intVal.compareTo(mc.roundingMax) < 0
+-                && intVal.compareTo(mc.roundingMin) > 0)
+-                return this; // no rounding needed
+-            precision();                     // find it
++    private static BigDecimal doRound(BigDecimal d, MathContext mc) {
++        int mcp = mc.precision;
++        int drop;
++        // This might (rarely) iterate to cover the 999=>1000 case
++        while ((drop = d.precision() - mcp) > 0) {
++            int newScale = d.checkScale((long)d.scale - drop);
++            int mode = mc.roundingMode.oldMode;
++            if (drop < LONG_TEN_POWERS_TABLE.length)
++                d = divideAndRound(d.intCompact, d.intVal,
++                                   LONG_TEN_POWERS_TABLE[drop], null,
++                                   newScale, mode, newScale);
++            else
++                d = divideAndRound(d.intCompact, d.intVal,
++                                   INFLATED, bigTenToThe(drop),
++                                   newScale, mode, newScale);
+         }
+-        int drop = precision - mc.precision;   // digits to discard
+-        if (drop <= 0)                       // we fit
+-            return this;
+-        BigDecimal rounded = dropDigits(mc, drop);
+-        // we need to double-check, in case of the 999=>1000 case
+-        return rounded.doRound(mc);
++        return d;
+     }
+ 
+     /**
+-     * Removes digits from the significand of a {@code BigDecimal},
+-     * rounding according to the MathContext settings.  Does not
+-     * change {@code this}; a new {@code BigDecimal} is always
+-     * created and returned.
+-     *
+-     * <p>Actual rounding is carried out, as before, by the divide
+-     * method, as this minimized code changes.  It might be more
+-     * efficient in most cases to move rounding to here, so we can do
+-     * a round-to-length rather than round-to-scale.
+-     *
+-     * @param mc the context to use.
+-     * @param drop the number of digits to drop, must be {@literal >} 0
+-     * @return a {@code BigDecimal} rounded according to the MathContext
+-     *         settings.  May return {@code this}, if no rounding needed.
+-     * @throws ArithmeticException if the rounding mode is
+-     *         {@code RoundingMode.UNNECESSARY} and the
+-     *         result is inexact.
++     * Returns the compact value for given {@code BigInteger}, or
++     * INFLATED if too big. Relies on internal representation of
++     * {@code BigInteger}.
+      */
+-    private BigDecimal dropDigits(MathContext mc, int drop) {
+-        // here if we need to round; make the divisor = 10**drop)
+-        // [calculating the BigInteger here saves setScale later]
+-        BigDecimal divisor = new BigDecimal(tenToThe(drop), 0);
++    private static long compactValFor(BigInteger b) {
++        int[] m = b.mag;
++        int len = m.length;
++        if (len == 0)
++            return 0;
++        int d = m[0];
++        if (len > 2 || (len == 2 && d < 0))
++            return INFLATED;
+ 
+-        // divide to same scale to force round to length
+-        BigDecimal rounded = this.divide(divisor, scale,
+-                                         mc.roundingMode.oldMode);
+-        rounded.scale = checkScale((long)rounded.scale - drop ); // adjust the scale
+-        return rounded;
++        long u = (len == 2)?
++            (((long) m[1] & LONG_MASK) + (((long)d) << 32)) :
++            (((long)d)   & LONG_MASK);
++        return (b.signum < 0)? -u : u;
+     }
+ 
+-    private static int longCompareTo(long x, long y) {
+-        return (x < y) ? -1 : (x == y) ? 0 : 1;
++    private static int longCompareMagnitude(long x, long y) {
++        if (x < 0)
++            x = -x;
++        if (y < 0)
++            y = -y;
++        return (x < y) ? -1 : ((x == y) ? 0 : 1);
++    }
++
++    private static int saturateLong(long s) {
++        int i = (int)s;
++        return (s == i) ? i : (s < 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE);
+     }
+ 
+     /*
+@@ -3527,21 +3816,21 @@
+      *
+      * <li>If precision is nonzero, it must have the right value.
+      * </ul>
++     *
++     * Note: Since this is an audit method, we are not supposed to change the
++     * state of this BigDecimal object.
+      */
+     private BigDecimal audit() {
+-        // Check precision
+-        if (precision > 0) {
+-            if (precision != digitLength()) {
+-                print("audit", this);
+-                throw new AssertionError("precision mismatch");
+-            }
+-        }
+-
+         if (intCompact == INFLATED) {
+             if (intVal == null) {
+                 print("audit", this);
+                 throw new AssertionError("null intVal");
+             }
++            // Check precision
++            if (precision > 0 && precision != bigDigitLength(intVal)) {
++                print("audit", this);
++                throw new AssertionError("precision mismatch");
++            }
+         } else {
+             if (intVal != null) {
+                 long val = intVal.longValue();
+@@ -3551,6 +3840,11 @@
+                                              intCompact + "\t intVal=" + val);
+                 }
+             }
++            // Check precision
++            if (precision > 0 && precision != longDigitLength(intCompact)) {
++                print("audit", this);
++                throw new AssertionError("precision mismatch");
++            }
+         }
+         return this;
+     }
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/BigInteger.java
+--- openjdk.orig/jdk/src/share/classes/java/math/BigInteger.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/BigInteger.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -105,7 +105,7 @@
+      *
+      * @serial
+      */
+-    int signum;
++    final int signum;
+ 
+     /**
+      * The magnitude of this BigInteger, in <i>big-endian</i> order: the
+@@ -116,61 +116,62 @@
+      * value.  Note that this implies that the BigInteger zero has a
+      * zero-length mag array.
+      */
+-    int[] mag;
++    final int[] mag;
+ 
+     // These "redundant fields" are initialized with recognizable nonsense
+     // values, and cached the first time they are needed (or never, if they
+     // aren't needed).
+ 
+-    /**
+-     * The bitCount of this BigInteger, as returned by bitCount(), or -1
+-     * (either value is acceptable).
++     /**
++     * One plus the bitCount of this BigInteger. Zeros means unitialized.
+      *
+      * @serial
+      * @see #bitCount
++     * @deprecated Deprecated since logical value is offset from stored
++     * value and correction factor is applied in accessor method.
+      */
+-    private int bitCount =  -1;
++    @Deprecated
++    private int bitCount;
+ 
+     /**
+-     * The bitLength of this BigInteger, as returned by bitLength(), or -1
++     * One plus the bitLength of this BigInteger. Zeros means unitialized.
+      * (either value is acceptable).
+      *
+      * @serial
+      * @see #bitLength()
++     * @deprecated Deprecated since logical value is offset from stored
++     * value and correction factor is applied in accessor method.
+      */
+-    private int bitLength = -1;
++    @Deprecated
++    private int bitLength;
+ 
+     /**
+-     * The lowest set bit of this BigInteger, as returned by getLowestSetBit(),
+-     * or -2 (either value is acceptable).
++     * Two plus the lowest set bit of this BigInteger, as returned by
++     * getLowestSetBit().
+      *
+      * @serial
+      * @see #getLowestSetBit
++     * @deprecated Deprecated since logical value is offset from stored
++     * value and correction factor is applied in accessor method.
+      */
+-    private int lowestSetBit = -2;
++    @Deprecated
++    private int lowestSetBit;
+ 
+     /**
+-     * The index of the lowest-order byte in the magnitude of this BigInteger
+-     * that contains a nonzero byte, or -2 (either value is acceptable).  The
+-     * least significant byte has int-number 0, the next byte in order of
+-     * increasing significance has byte-number 1, and so forth.
+-     *
+-     * @serial
++     * Two plus the index of the lowest-order int in the magnitude of this
++     * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
++     * The least significant int has int-number 0, the next int in order of
++     * increasing significance has int-number 1, and so forth.
++     * @deprecated Deprecated since logical value is offset from stored
++     * value and correction factor is applied in accessor method.
+      */
+-    private int firstNonzeroByteNum = -2;
+-
+-    /**
+-     * The index of the lowest-order int in the magnitude of this BigInteger
+-     * that contains a nonzero int, or -2 (either value is acceptable).  The
+-     * least significant int has int-number 0, the next int in order of
+-     * increasing significance has int-number 1, and so forth.
+-     */
+-    private int firstNonzeroIntNum = -2;
++    @Deprecated
++    private int firstNonzeroIntNum;
+ 
+     /**
+      * This mask is used to obtain the value of an int as if it were unsigned.
+      */
+-    private final static long LONG_MASK = 0xffffffffL;
++    final static long LONG_MASK = 0xffffffffL;
+ 
+     //Constructors
+ 
+@@ -295,13 +296,13 @@
+             throw new NumberFormatException("Zero length BigInteger");
+ 
+         // Check for at most one leading sign
+-        signum = 1;
++        int sign = 1;
+         int index = val.lastIndexOf('-');
+         if (index != -1) {
+             if (index == 0 ) {
+                 if (val.length() == 1)
+                     throw new NumberFormatException("Zero length BigInteger");
+-                signum = -1;
++                sign = -1;
+                 cursor = 1;
+             } else {
+                 throw new NumberFormatException("Illegal embedded sign character");
+@@ -316,23 +317,24 @@
+             signum = 0;
+             mag = ZERO.mag;
+             return;
+-        } else {
+-            numDigits = len - cursor;
+         }
+ 
++        numDigits = len - cursor;
++        signum = sign;
++
+         // Pre-allocate array of expected size. May be too large but can
+         // never be too small. Typically exact.
+         int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);
+-        int numWords = (numBits + 31) /32;
+-        mag = new int[numWords];
++        int numWords = (numBits + 31) >>> 5;
++        int[] magnitude = new int[numWords];
+ 
+         // Process first (potentially short) digit group
+         int firstGroupLen = numDigits % digitsPerInt[radix];
+         if (firstGroupLen == 0)
+             firstGroupLen = digitsPerInt[radix];
+         String group = val.substring(cursor, cursor += firstGroupLen);
+-        mag[mag.length - 1] = Integer.parseInt(group, radix);
+-        if (mag[mag.length - 1] < 0)
++        magnitude[numWords - 1] = Integer.parseInt(group, radix);
++        if (magnitude[numWords - 1] < 0)
+             throw new NumberFormatException("Illegal digit");
+ 
+         // Process remaining digit groups
+@@ -343,10 +345,10 @@
+             groupVal = Integer.parseInt(group, radix);
+             if (groupVal < 0)
+                 throw new NumberFormatException("Illegal digit");
+-            destructiveMulAdd(mag, superRadix, groupVal);
++            destructiveMulAdd(magnitude, superRadix, groupVal);
+         }
+         // Required for cases where the array was overallocated.
+-        mag = trustedStripLeadingZeroInts(mag);
++        mag = trustedStripLeadingZeroInts(magnitude);
+     }
+ 
+     // Constructs a new BigInteger using a char array with radix=10
+@@ -355,11 +357,11 @@
+         int len = val.length;
+ 
+         // Check for leading minus sign
+-        signum = 1;
++        int sign = 1;
+         if (val[0] == '-') {
+             if (len == 1)
+                 throw new NumberFormatException("Zero length BigInteger");
+-            signum = -1;
++            sign = -1;
+             cursor = 1;
+         }
+ 
+@@ -370,32 +372,33 @@
+             signum = 0;
+             mag = ZERO.mag;
+             return;
+-        } else {
+-            numDigits = len - cursor;
+         }
+ 
++        numDigits = len - cursor;
++        signum = sign;
++
+         // Pre-allocate array of expected size
+         int numWords;
+         if (len < 10) {
+             numWords = 1;
+         } else {
+             int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1);
+-            numWords = (numBits + 31) /32;
++            numWords = (numBits + 31) >>> 5;
+         }
+-        mag = new int[numWords];
++        int[] magnitude = new int[numWords];
+ 
+         // Process first (potentially short) digit group
+         int firstGroupLen = numDigits % digitsPerInt[10];
+         if (firstGroupLen == 0)
+             firstGroupLen = digitsPerInt[10];
+-        mag[mag.length-1] = parseInt(val, cursor,  cursor += firstGroupLen);
++        magnitude[numWords - 1] = parseInt(val, cursor,  cursor += firstGroupLen);
+ 
+         // Process remaining digit groups
+         while (cursor < len) {
+             int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]);
+-            destructiveMulAdd(mag, intRadix[10], groupVal);
++            destructiveMulAdd(magnitude, intRadix[10], groupVal);
+         }
+-        mag = trustedStripLeadingZeroInts(mag);
++        mag = trustedStripLeadingZeroInts(magnitude);
+     }
+ 
+     // Create an integer with the digits between the two indexes
+@@ -836,26 +839,21 @@
+             u2 = u.multiply(v).mod(n);
+ 
+             v2 = v.square().add(d.multiply(u.square())).mod(n);
+-            if (v2.testBit(0)) {
+-                v2 = n.subtract(v2);
+-                v2.signum = - v2.signum;
+-            }
++            if (v2.testBit(0))
++                v2 = v2.subtract(n);
++
+             v2 = v2.shiftRight(1);
+ 
+             u = u2; v = v2;
+             if (k.testBit(i)) {
+                 u2 = u.add(v).mod(n);
+-                if (u2.testBit(0)) {
+-                    u2 = n.subtract(u2);
+-                    u2.signum = - u2.signum;
+-                }
++                if (u2.testBit(0))
++                    u2 = u2.subtract(n);
++
+                 u2 = u2.shiftRight(1);
+-
+                 v2 = v.add(d.multiply(u)).mod(n);
+-                if (v2.testBit(0)) {
+-                    v2 = n.subtract(v2);
+-                    v2.signum = - v2.signum;
+-                }
++                if (v2.testBit(0))
++                    v2 = v2.subtract(n);
+                 v2 = v2.shiftRight(1);
+ 
+                 u = u2; v = v2;
+@@ -912,11 +910,11 @@
+     }
+ 
+     /**
+-     * This private constructor differs from its public cousin
++     * This internal constructor differs from its public cousin
+      * with the arguments reversed in two ways: it assumes that its
+      * arguments are correct, and it doesn't copy the magnitude array.
+      */
+-    private BigInteger(int[] magnitude, int signum) {
++    BigInteger(int[] magnitude, int signum) {
+         this.signum = (magnitude.length==0 ? 0 : signum);
+         this.mag = magnitude;
+     }
+@@ -930,22 +928,6 @@
+         this.mag = stripLeadingZeroBytes(magnitude);
+     }
+ 
+-    /**
+-     * This private constructor is for internal use in converting
+-     * from a MutableBigInteger object into a BigInteger.
+-     */
+-    BigInteger(MutableBigInteger val, int sign) {
+-        if (val.offset > 0 || val.value.length != val.intLen) {
+-            mag = new int[val.intLen];
+-            for(int i=0; i<val.intLen; i++)
+-                mag[i] = val.value[val.offset+i];
+-        } else {
+-            mag = val.value;
+-        }
+-
+-        this.signum = (val.intLen == 0) ? 0 : sign;
+-    }
+-
+     //Static Factory Methods
+ 
+     /**
+@@ -974,8 +956,8 @@
+      */
+     private BigInteger(long val) {
+         if (val < 0) {
++            val = -val;
+             signum = -1;
+-            val = -val;
+         } else {
+             signum = 1;
+         }
+@@ -1052,7 +1034,6 @@
+      * @return {@code this + val}
+      */
+     public BigInteger add(BigInteger val) {
+-        int[] resultMag;
+         if (val.signum == 0)
+             return this;
+         if (signum == 0)
+@@ -1060,14 +1041,14 @@
+         if (val.signum == signum)
+             return new BigInteger(add(mag, val.mag), signum);
+ 
+-        int cmp = intArrayCmp(mag, val.mag);
+-        if (cmp==0)
++        int cmp = compareMagnitude(val);
++        if (cmp == 0)
+             return ZERO;
+-        resultMag = (cmp>0 ? subtract(mag, val.mag)
++        int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
+                            : subtract(val.mag, mag));
+         resultMag = trustedStripLeadingZeroInts(resultMag);
+ 
+-        return new BigInteger(resultMag, cmp*signum);
++        return new BigInteger(resultMag, cmp == signum ? 1 : -1);
+     }
+ 
+     /**
+@@ -1106,12 +1087,10 @@
+ 
+         // Grow result if necessary
+         if (carry) {
+-            int newLen = result.length + 1;
+-            int temp[] = new int[newLen];
+-            for (int i = 1; i<newLen; i++)
+-                temp[i] = result[i-1];
+-            temp[0] = 0x01;
+-            result = temp;
++            int bigger[] = new int[result.length + 1];
++            System.arraycopy(result, 0, bigger, 1, result.length);
++            bigger[0] = 0x01;
++            return bigger;
+         }
+         return result;
+     }
+@@ -1123,7 +1102,6 @@
+      * @return {@code this - val}
+      */
+     public BigInteger subtract(BigInteger val) {
+-        int[] resultMag;
+         if (val.signum == 0)
+             return this;
+         if (signum == 0)
+@@ -1131,13 +1109,13 @@
+         if (val.signum != signum)
+             return new BigInteger(add(mag, val.mag), signum);
+ 
+-        int cmp = intArrayCmp(mag, val.mag);
+-        if (cmp==0)
++        int cmp = compareMagnitude(val);
++        if (cmp == 0)
+             return ZERO;
+-        resultMag = (cmp>0 ? subtract(mag, val.mag)
++        int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
+                            : subtract(val.mag, mag));
+         resultMag = trustedStripLeadingZeroInts(resultMag);
+-        return new BigInteger(resultMag, cmp*signum);
++        return new BigInteger(resultMag, cmp == signum ? 1 : -1);
+     }
+ 
+     /**
+@@ -1185,12 +1163,54 @@
+         int[] result = multiplyToLen(mag, mag.length,
+                                      val.mag, val.mag.length, null);
+         result = trustedStripLeadingZeroInts(result);
+-        return new BigInteger(result, signum*val.signum);
++        return new BigInteger(result, signum == val.signum ? 1 : -1);
++    }
++
++    /**
++     * Package private methods used by BigDecimal code to multiply a BigInteger
++     * with a long. Assumes v is not equal to INFLATED.
++     */
++    BigInteger multiply(long v) {
++        if (v == 0 || signum == 0)
++          return ZERO;
++        if (v == BigDecimal.INFLATED)
++            return multiply(BigInteger.valueOf(v));
++        int rsign = (v > 0 ? signum : -signum);
++        if (v < 0)
++            v = -v;
++        long dh = v >>> 32;      // higher order bits
++        long dl = v & LONG_MASK; // lower order bits
++
++        int xlen = mag.length;
++        int[] value = mag;
++        int[] rmag = (dh == 0L) ? (new int[xlen + 1]) : (new int[xlen + 2]);
++        long carry = 0;
++        int rstart = rmag.length - 1;
++        for (int i = xlen - 1; i >= 0; i--) {
++            long product = (value[i] & LONG_MASK) * dl + carry;
++            rmag[rstart--] = (int)product;
++            carry = product >>> 32;
++        }
++        rmag[rstart] = (int)carry;
++        if (dh != 0L) {
++            carry = 0;
++            rstart = rmag.length - 2;
++            for (int i = xlen - 1; i >= 0; i--) {
++                long product = (value[i] & LONG_MASK) * dh +
++                    (rmag[rstart] & LONG_MASK) + carry;
++                rmag[rstart--] = (int)product;
++                carry = product >>> 32;
++            }
++            rmag[0] = (int)carry;
++        }
++        if (carry == 0L)
++            rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
++        return new BigInteger(rmag, rsign);
+     }
+ 
+     /**
+      * Multiplies int arrays x and y to the specified lengths and places
+-     * the result into z.
++     * the result into z. There will be no leading zeros in the resultant array.
+      */
+     private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
+         int xstart = xlen - 1;
+@@ -1310,12 +1330,11 @@
+      */
+     public BigInteger divide(BigInteger val) {
+         MutableBigInteger q = new MutableBigInteger(),
+-                          r = new MutableBigInteger(),
+                           a = new MutableBigInteger(this.mag),
+                           b = new MutableBigInteger(val.mag);
+ 
+-        a.divide(b, q, r);
+-        return new BigInteger(q, this.signum * val.signum);
++        a.divide(b, q);
++        return q.toBigInteger(this.signum == val.signum ? 1 : -1);
+     }
+ 
+     /**
+@@ -1332,12 +1351,11 @@
+     public BigInteger[] divideAndRemainder(BigInteger val) {
+         BigInteger[] result = new BigInteger[2];
+         MutableBigInteger q = new MutableBigInteger(),
+-                          r = new MutableBigInteger(),
+                           a = new MutableBigInteger(this.mag),
+                           b = new MutableBigInteger(val.mag);
+-        a.divide(b, q, r);
+-        result[0] = new BigInteger(q, this.signum * val.signum);
+-        result[1] = new BigInteger(r, this.signum);
++        MutableBigInteger r = a.divide(b, q);
++        result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
++        result[1] = r.toBigInteger(this.signum);
+         return result;
+     }
+ 
+@@ -1351,12 +1369,10 @@
+      */
+     public BigInteger remainder(BigInteger val) {
+         MutableBigInteger q = new MutableBigInteger(),
+-                          r = new MutableBigInteger(),
+                           a = new MutableBigInteger(this.mag),
+                           b = new MutableBigInteger(val.mag);
+ 
+-        a.divide(b, q, r);
+-        return new BigInteger(r, this.signum);
++        return a.divide(b, q).toBigInteger(this.signum);
+     }
+ 
+     /**
+@@ -1412,7 +1428,14 @@
+ 
+         MutableBigInteger result = a.hybridGCD(b);
+ 
+-        return new BigInteger(result, 1);
++        return result.toBigInteger(1);
++    }
++
++    /**
++     * Package private method to return bit length for an integer.
++     */
++    static int bitLengthForInt(int n) {
++        return 32 - Integer.numberOfLeadingZeros(n);
+     }
+ 
+     /**
+@@ -1422,7 +1445,7 @@
+     private static int[] leftShift(int[] a, int len, int n) {
+         int nInts = n >>> 5;
+         int nBits = n&0x1F;
+-        int bitsInHighWord = bitLen(a[0]);
++        int bitsInHighWord = bitLengthForInt(a[0]);
+ 
+         // If shift can be done without recopy, do so
+         if (n <= (32-bitsInHighWord)) {
+@@ -1475,9 +1498,9 @@
+      * assuming there are no leading zero ints.
+      */
+     private static int bitLength(int[] val, int len) {
+-        if (len==0)
++        if (len == 0)
+             return 0;
+-        return ((len-1)<<5) + bitLen(val[0]);
++        return ((len - 1) << 5) + bitLengthForInt(val[0]);
+     }
+ 
+     /**
+@@ -1704,11 +1727,10 @@
+         int[] a = leftShift(base, base.length, modLen << 5);
+ 
+         MutableBigInteger q = new MutableBigInteger(),
+-                          r = new MutableBigInteger(),
+                           a2 = new MutableBigInteger(a),
+                           b2 = new MutableBigInteger(mod);
+ 
+-        a2.divide(b2, q, r);
++        MutableBigInteger r= a2.divide(b2, q);
+         table[0] = r.toIntArray();
+ 
+         // Pad table[0] with leading zeros so its length is at least modLen
+@@ -1970,7 +1992,7 @@
+             return this;
+ 
+         // Copy remaining ints of mag
+-        int numInts = (p+31)/32;
++        int numInts = (p + 31) >>> 5;
+         int[] mag = new int[numInts];
+         for (int i=0; i<numInts; i++)
+             mag[i] = this.mag[i + (this.mag.length - numInts)];
+@@ -2000,7 +2022,7 @@
+ 
+         // Calculate (this mod m)
+         BigInteger modVal = this;
+-        if (signum < 0 || (intArrayCmp(mag, m.mag) >= 0))
++        if (signum < 0 || (this.compareMagnitude(m) >= 0))
+             modVal = this.mod(m);
+ 
+         if (modVal.equals(ONE))
+@@ -2010,7 +2032,7 @@
+         MutableBigInteger b = new MutableBigInteger(m);
+ 
+         MutableBigInteger result = a.mutableModInverse(b);
+-        return new BigInteger(result, 1);
++        return result.toBigInteger(1);
+     }
+ 
+     // Shift Operations
+@@ -2235,7 +2257,7 @@
+         if (n<0)
+             throw new ArithmeticException("Negative bit address");
+ 
+-        return (getInt(n/32) & (1 << (n%32))) != 0;
++        return (getInt(n >>> 5) & (1 << (n & 31))) != 0;
+     }
+ 
+     /**
+@@ -2250,13 +2272,13 @@
+         if (n<0)
+             throw new ArithmeticException("Negative bit address");
+ 
+-        int intNum = n/32;
++        int intNum = n >>> 5;
+         int[] result = new int[Math.max(intLength(), intNum+2)];
+ 
+         for (int i=0; i<result.length; i++)
+             result[result.length-i-1] = getInt(i);
+ 
+-        result[result.length-intNum-1] |= (1 << (n%32));
++        result[result.length-intNum-1] |= (1 << (n & 31));
+ 
+         return valueOf(result);
+     }
+@@ -2274,13 +2296,13 @@
+         if (n<0)
+             throw new ArithmeticException("Negative bit address");
+ 
+-        int intNum = n/32;
+-        int[] result = new int[Math.max(intLength(), (n+1)/32+1)];
++        int intNum = n >>> 5;
++        int[] result = new int[Math.max(intLength(), ((n + 1) >>> 5) + 1)];
+ 
+         for (int i=0; i<result.length; i++)
+             result[result.length-i-1] = getInt(i);
+ 
+-        result[result.length-intNum-1] &= ~(1 << (n%32));
++        result[result.length-intNum-1] &= ~(1 << (n & 31));
+ 
+         return valueOf(result);
+     }
+@@ -2298,13 +2320,13 @@
+         if (n<0)
+             throw new ArithmeticException("Negative bit address");
+ 
+-        int intNum = n/32;
++        int intNum = n >>> 5;
+         int[] result = new int[Math.max(intLength(), intNum+2)];
+ 
+         for (int i=0; i<result.length; i++)
+             result[result.length-i-1] = getInt(i);
+ 
+-        result[result.length-intNum-1] ^= (1 << (n%32));
++        result[result.length-intNum-1] ^= (1 << (n & 31));
+ 
+         return valueOf(result);
+     }
+@@ -2318,23 +2340,21 @@
+      * @return index of the rightmost one bit in this BigInteger.
+      */
+     public int getLowestSetBit() {
+-        /*
+-         * Initialize lowestSetBit field the first time this method is
+-         * executed. This method depends on the atomicity of int modifies;
+-         * without this guarantee, it would have to be synchronized.
+-         */
+-        if (lowestSetBit == -2) {
++        @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
++        if (lsb == -2) {  // lowestSetBit not initialized yet
++            lsb = 0;
+             if (signum == 0) {
+-                lowestSetBit = -1;
++                lsb -= 1;
+             } else {
+                 // Search for lowest order nonzero int
+                 int i,b;
+                 for (i=0; (b = getInt(i))==0; i++)
+                     ;
+-                lowestSetBit = (i << 5) + trailingZeroCnt(b);
++                lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
+             }
++            lowestSetBit = lsb + 2;
+         }
+-        return lowestSetBit;
++        return lsb;
+     }
+ 
+ 
+@@ -2351,79 +2371,32 @@
+      *         representation of this BigInteger, <i>excluding</i> a sign bit.
+      */
+     public int bitLength() {
+-        /*
+-         * Initialize bitLength field the first time this method is executed.
+-         * This method depends on the atomicity of int modifies; without
+-         * this guarantee, it would have to be synchronized.
+-         */
+-        if (bitLength == -1) {
+-            if (signum == 0) {
+-                bitLength = 0;
+-            } else {
++        @SuppressWarnings("deprecation") int n = bitLength - 1;
++        if (n == -1) { // bitLength not initialized yet
++            int[] m = mag;
++            int len = m.length;
++            if (len == 0) {
++                n = 0; // offset by one to initialize
++            }  else {
+                 // Calculate the bit length of the magnitude
+-                int magBitLength = ((mag.length-1) << 5) + bitLen(mag[0]);
+-
+-                if (signum < 0) {
+-                    // Check if magnitude is a power of two
+-                    boolean pow2 = (bitCnt(mag[0]) == 1);
+-                    for(int i=1; i<mag.length && pow2; i++)
+-                        pow2 = (mag[i]==0);
+-
+-                    bitLength = (pow2 ? magBitLength-1 : magBitLength);
+-                } else {
+-                    bitLength = magBitLength;
+-                }
++                int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]);
++                 if (signum < 0) {
++                     // Check if magnitude is a power of two
++                     boolean pow2 = (Integer.bitCount(mag[0]) == 1);
++                     for(int i=1; i< len && pow2; i++)
++                         pow2 = (mag[i] == 0);
++
++                     n = (pow2 ? magBitLength -1 : magBitLength);
++                 } else {
++                     n = magBitLength;
++                 }
+             }
++            bitLength = n + 1;
+         }
+-        return bitLength;
++        return n;
+     }
+ 
+     /**
+-     * bitLen(val) is the number of bits in val.
+-     */
+-    static int bitLen(int w) {
+-        // Binary search - decision tree (5 tests, rarely 6)
+-        return
+-         (w < 1<<15 ?
+-          (w < 1<<7 ?
+-           (w < 1<<3 ?
+-            (w < 1<<1 ? (w < 1<<0 ? (w<0 ? 32 : 0) : 1) : (w < 1<<2 ? 2 : 3)) :
+-            (w < 1<<5 ? (w < 1<<4 ? 4 : 5) : (w < 1<<6 ? 6 : 7))) :
+-           (w < 1<<11 ?
+-            (w < 1<<9 ? (w < 1<<8 ? 8 : 9) : (w < 1<<10 ? 10 : 11)) :
+-            (w < 1<<13 ? (w < 1<<12 ? 12 : 13) : (w < 1<<14 ? 14 : 15)))) :
+-          (w < 1<<23 ?
+-           (w < 1<<19 ?
+-            (w < 1<<17 ? (w < 1<<16 ? 16 : 17) : (w < 1<<18 ? 18 : 19)) :
+-            (w < 1<<21 ? (w < 1<<20 ? 20 : 21) : (w < 1<<22 ? 22 : 23))) :
+-           (w < 1<<27 ?
+-            (w < 1<<25 ? (w < 1<<24 ? 24 : 25) : (w < 1<<26 ? 26 : 27)) :
+-            (w < 1<<29 ? (w < 1<<28 ? 28 : 29) : (w < 1<<30 ? 30 : 31)))));
+-    }
+-
+-    /*
+-     * trailingZeroTable[i] is the number of trailing zero bits in the binary
+-     * representation of i.
+-     */
+-    final static byte trailingZeroTable[] = {
+-      -25, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+-        4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
+-
+-    /**
+      * Returns the number of bits in the two's complement representation
+      * of this BigInteger that differ from its sign bit.  This method is
+      * useful when implementing bit-vector style sets atop BigIntegers.
+@@ -2432,58 +2405,23 @@
+      *         of this BigInteger that differ from its sign bit.
+      */
+     public int bitCount() {
+-        /*
+-         * Initialize bitCount field the first time this method is executed.
+-         * This method depends on the atomicity of int modifies; without
+-         * this guarantee, it would have to be synchronized.
+-         */
+-        if (bitCount == -1) {
++        @SuppressWarnings("deprecation") int bc = bitCount - 1;
++        if (bc == -1) {  // bitCount not initialized yet
++            bc = 0;      // offset by one to initialize
+             // Count the bits in the magnitude
+-            int magBitCount = 0;
+             for (int i=0; i<mag.length; i++)
+-                magBitCount += bitCnt(mag[i]);
+-
++                bc += Integer.bitCount(mag[i]);
+             if (signum < 0) {
+                 // Count the trailing zeros in the magnitude
+                 int magTrailingZeroCount = 0, j;
+                 for (j=mag.length-1; mag[j]==0; j--)
+                     magTrailingZeroCount += 32;
+-                magTrailingZeroCount +=
+-                            trailingZeroCnt(mag[j]);
+-
+-                bitCount = magBitCount + magTrailingZeroCount - 1;
+-            } else {
+-                bitCount = magBitCount;
++                magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
++                bc += magTrailingZeroCount - 1;
+             }
++            bitCount = bc + 1;
+         }
+-        return bitCount;
+-    }
+-
+-    static int bitCnt(int val) {
+-        val -= (0xaaaaaaaa & val) >>> 1;
+-        val = (val & 0x33333333) + ((val >>> 2) & 0x33333333);
+-        val = val + (val >>> 4) & 0x0f0f0f0f;
+-        val += val >>> 8;
+-        val += val >>> 16;
+-        return val & 0xff;
+-    }
+-
+-    static int trailingZeroCnt(int val) {
+-        // Loop unrolled for performance
+-        int byteVal = val & 0xff;
+-        if (byteVal != 0)
+-            return trailingZeroTable[byteVal];
+-
+-        byteVal = (val >>> 8) & 0xff;
+-        if (byteVal != 0)
+-            return trailingZeroTable[byteVal] + 8;
+-
+-        byteVal = (val >>> 16) & 0xff;
+-        if (byteVal != 0)
+-            return trailingZeroTable[byteVal] + 16;
+-
+-        byteVal = (val >>> 24) & 0xff;
+-        return trailingZeroTable[byteVal] + 24;
++        return bc;
+     }
+ 
+     // Primality Testing
+@@ -2530,29 +2468,41 @@
+      *         to, or greater than {@code val}.
+      */
+     public int compareTo(BigInteger val) {
+-        return (signum==val.signum
+-                ? signum*intArrayCmp(mag, val.mag)
+-                : (signum>val.signum ? 1 : -1));
++        if (signum == val.signum) {
++            switch (signum) {
++            case 1:
++                return compareMagnitude(val);
++            case -1:
++                return val.compareMagnitude(this);
++            default:
++                return 0;
++            }
++        }
++        return signum > val.signum ? 1 : -1;
+     }
+ 
+-    /*
+-     * Returns -1, 0 or +1 as big-endian unsigned int array arg1 is
+-     * less than, equal to, or greater than arg2.
++    /**
++     * Compares the magnitude array of this BigInteger with the specified
++     * BigInteger's. This is the version of compareTo ignoring sign.
++     *
++     * @param val BigInteger whose magnitude array to be compared.
++     * @return -1, 0 or 1 as this magnitude array is less than, equal to or
++     *         greater than the magnitude aray for the specified BigInteger's.
+      */
+-    private static int intArrayCmp(int[] arg1, int[] arg2) {
+-        if (arg1.length < arg2.length)
++    final int compareMagnitude(BigInteger val) {
++        int[] m1 = mag;
++        int len1 = m1.length;
++        int[] m2 = val.mag;
++        int len2 = m2.length;
++        if (len1 < len2)
+             return -1;
+-        if (arg1.length > arg2.length)
++        if (len1 > len2)
+             return 1;
+-
+-        // Argument lengths are equal; compare the values
+-        for (int i=0; i<arg1.length; i++) {
+-            long b1 = arg1[i] & LONG_MASK;
+-            long b2 = arg2[i] & LONG_MASK;
+-            if (b1 < b2)
+-                return -1;
+-            if (b1 > b2)
+-                return 1;
++        for (int i = 0; i < len1; i++) {
++            int a = m1[i];
++            int b = m2[i];
++            if (a != b)
++                return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
+         }
+         return 0;
+     }
+@@ -2571,13 +2521,19 @@
+ 
+         if (!(x instanceof BigInteger))
+             return false;
++
+         BigInteger xInt = (BigInteger) x;
+-
+-        if (xInt.signum != signum || xInt.mag.length != mag.length)
++        if (xInt.signum != signum)
+             return false;
+ 
+-        for (int i=0; i<mag.length; i++)
+-            if (xInt.mag[i] != mag[i])
++        int[] m = mag;
++        int len = m.length;
++        int[] xm = xInt.mag;
++        if (len != xm.length)
++            return false;
++
++        for (int i = 0; i < len; i++)
++            if (xm[i] != m[i])
+                 return false;
+ 
+         return true;
+@@ -2656,12 +2612,11 @@
+             BigInteger d = longRadix[radix];
+ 
+             MutableBigInteger q = new MutableBigInteger(),
+-                              r = new MutableBigInteger(),
+                               a = new MutableBigInteger(tmp.mag),
+                               b = new MutableBigInteger(d.mag);
+-            a.divide(b, q, r);
+-            BigInteger q2 = new BigInteger(q, tmp.signum * d.signum);
+-            BigInteger r2 = new BigInteger(r, tmp.signum * d.signum);
++            MutableBigInteger r = a.divide(b, q);
++            BigInteger q2 = q.toBigInteger(tmp.signum * d.signum);
++            BigInteger r2 = r.toBigInteger(tmp.signum * d.signum);
+ 
+             digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);
+             tmp = q2;
+@@ -2830,18 +2785,13 @@
+      * Returns a copy of the input array stripped of any leading zero bytes.
+      */
+     private static int[] stripLeadingZeroInts(int val[]) {
+-        int byteLength = val.length;
++        int vlen = val.length;
+         int keep;
+ 
+         // Find first nonzero byte
+-        for (keep=0; keep<val.length && val[keep]==0; keep++)
++        for (keep = 0; keep < vlen && val[keep] == 0; keep++)
+             ;
+-
+-        int result[] = new int[val.length - keep];
+-        for(int i=0; i<val.length - keep; i++)
+-            result[i] = val[keep+i];
+-
+-        return result;
++        return java.util.Arrays.copyOfRange(val, keep, vlen);
+     }
+ 
+     /**
+@@ -2849,21 +2799,13 @@
+      * Since the source is trusted the copying may be skipped.
+      */
+     private static int[] trustedStripLeadingZeroInts(int val[]) {
+-        int byteLength = val.length;
++        int vlen = val.length;
+         int keep;
+ 
+         // Find first nonzero byte
+-        for (keep=0; keep<val.length && val[keep]==0; keep++)
++        for (keep = 0; keep < vlen && val[keep] == 0; keep++)
+             ;
+-
+-        // Only perform copy if necessary
+-        if (keep > 0) {
+-            int result[] = new int[val.length - keep];
+-            for(int i=0; i<val.length - keep; i++)
+-               result[i] = val[keep+i];
+-            return result;
+-        }
+-        return val;
++        return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen);
+     }
+ 
+     /**
+@@ -2874,18 +2816,18 @@
+         int keep;
+ 
+         // Find first nonzero byte
+-        for (keep=0; keep<a.length && a[keep]==0; keep++)
++        for (keep = 0; keep < byteLength && a[keep]==0; keep++)
+             ;
+ 
+         // Allocate new array and copy relevant part of input array
+-        int intLength = ((byteLength - keep) + 3)/4;
++        int intLength = ((byteLength - keep) + 3) >>> 2;
+         int[] result = new int[intLength];
+         int b = byteLength - 1;
+         for (int i = intLength-1; i >= 0; i--) {
+             result[i] = a[b--] & 0xff;
+             int bytesRemaining = b - keep + 1;
+             int bytesToTransfer = Math.min(3, bytesRemaining);
+-            for (int j=8; j <= 8*bytesToTransfer; j += 8)
++            for (int j=8; j <= (bytesToTransfer << 3); j += 8)
+                 result[i] |= ((a[b--] & 0xff) << j);
+         }
+         return result;
+@@ -3031,7 +2973,7 @@
+      * including space for at least one sign bit.
+      */
+     private int intLength() {
+-        return bitLength()/32 + 1;
++        return (bitLength() >>> 5) + 1;
+     }
+ 
+     /* Returns sign bit */
+@@ -3068,20 +3010,20 @@
+      * least significant). If the magnitude is zero, return value is undefined.
+      */
+      private int firstNonzeroIntNum() {
+-        /*
+-         * Initialize firstNonzeroIntNum field the first time this method is
+-         * executed. This method depends on the atomicity of int modifies;
+-         * without this guarantee, it would have to be synchronized.
+-         */
+-        if (firstNonzeroIntNum == -2) {
+-            // Search for the first nonzero int
+-            int i;
+-            for (i=mag.length-1; i>=0 && mag[i]==0; i--)
+-                ;
+-            firstNonzeroIntNum = mag.length-i-1;
+-        }
+-        return firstNonzeroIntNum;
+-    }
++         int fn = firstNonzeroIntNum - 2;
++         if (fn == -2) { // firstNonzeroIntNum not initialized yet
++             fn = 0;
++
++             // Search for the first nonzero int
++             int i;
++             int mlen = mag.length;
++             for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
++                 ;
++             fn = mlen - i - 1;
++             firstNonzeroIntNum = fn + 2; // offset by two to initialize
++         }
++         return fn;
++     }
+ 
+     /** use serialVersionUID from JDK 1.1. for interoperability */
+     private static final long serialVersionUID = -8287574255936472291L;
+@@ -3115,6 +3057,12 @@
+      * deserialize it). The magnitude is read in as an array of bytes
+      * for historical reasons, but it is converted to an array of ints
+      * and the byte array is discarded.
++     * Note:
++     * The current convention is to initialize the cache fields, bitCount,
++     * bitLength and lowestSetBit, to 0 rather than some other marker value.
++     * Therefore, no explicit action to set these fields needs to be taken in
++     * readObject because those fields already have a 0 value be default since
++     * defaultReadObject is not being used.
+      */
+     private void readObject(java.io.ObjectInputStream s)
+         throws java.io.IOException, ClassNotFoundException {
+@@ -3130,29 +3078,44 @@
+         ObjectInputStream.GetField fields = s.readFields();
+ 
+         // Read the alternate persistent fields that we care about
+-        signum = fields.get("signum", -2);
++        int sign = fields.get("signum", -2);
+         byte[] magnitude = (byte[])fields.get("magnitude", null);
+ 
+         // Validate signum
+-        if (signum < -1 || signum > 1) {
++        if (sign < -1 || sign > 1) {
+             String message = "BigInteger: Invalid signum value";
+             if (fields.defaulted("signum"))
+                 message = "BigInteger: Signum not present in stream";
+             throw new java.io.StreamCorruptedException(message);
+         }
+-        if ((magnitude.length==0) != (signum==0)) {
++        if ((magnitude.length == 0) != (sign == 0)) {
+             String message = "BigInteger: signum-magnitude mismatch";
+             if (fields.defaulted("magnitude"))
+                 message = "BigInteger: Magnitude not present in stream";
+             throw new java.io.StreamCorruptedException(message);
+         }
+ 
+-        // Set "cached computation" fields to their initial values
+-        bitCount = bitLength = -1;
+-        lowestSetBit = firstNonzeroByteNum = firstNonzeroIntNum = -2;
++        // Commit final fields via Unsafe
++        unsafe.putIntVolatile(this, signumOffset, sign);
+ 
+         // Calculate mag field from magnitude and discard magnitude
+-        mag = stripLeadingZeroBytes(magnitude);
++        unsafe.putObjectVolatile(this, magOffset,
++                                 stripLeadingZeroBytes(magnitude));
++    }
++
++    // Support for resetting final fields while deserializing
++    private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
++    private static final long signumOffset;
++    private static final long magOffset;
++    static {
++        try {
++            signumOffset = unsafe.objectFieldOffset
++                (BigInteger.class.getDeclaredField("signum"));
++            magOffset = unsafe.objectFieldOffset
++                (BigInteger.class.getDeclaredField("mag"));
++        } catch (Exception ex) {
++            throw new Error(ex);
++        }
+     }
+ 
+     /**
+@@ -3168,6 +3131,8 @@
+         ObjectOutputStream.PutField fields = s.putFields();
+         fields.put("signum", signum);
+         fields.put("magnitude", magSerializedForm());
++        // The values written for cached fields are compatible with older
++        // versions, but are ignored in readObject so don't otherwise matter.
+         fields.put("bitCount", -1);
+         fields.put("bitLength", -1);
+         fields.put("lowestSetBit", -2);
+@@ -3181,12 +3146,13 @@
+      * Returns the mag array as an array of bytes.
+      */
+     private byte[] magSerializedForm() {
+-        int bitLen = (mag.length == 0 ? 0 :
+-                      ((mag.length - 1) << 5) + bitLen(mag[0]));
+-        int byteLen = (bitLen + 7)/8;
++        int len = mag.length;
++
++        int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0]));
++        int byteLen = (bitLen + 7) >>> 3;
+         byte[] result = new byte[byteLen];
+ 
+-        for (int i=byteLen-1, bytesCopied=4, intIndex=mag.length-1, nextInt=0;
++        for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0;
+              i>=0; i--) {
+             if (bytesCopied == 4) {
+                 nextInt = mag[intIndex--];
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/BitSieve.java
+--- openjdk.orig/jdk/src/share/classes/java/math/BitSieve.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/BitSieve.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -110,13 +110,11 @@
+         int convertedStep = (step *2) + 1;
+ 
+         // Construct the large sieve at an even offset specified by base
+-        MutableBigInteger r = new MutableBigInteger();
++        MutableBigInteger b = new MutableBigInteger(base);
+         MutableBigInteger q = new MutableBigInteger();
+         do {
+             // Calculate base mod convertedStep
+-            r.copyValue(base.mag);
+-            r.divideOneWord(convertedStep, q);
+-            start = r.value[r.offset];
++            start = b.divideOneWord(convertedStep, q);
+ 
+             // Take each multiple of step out of sieve
+             start = convertedStep - start;
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/MathContext.java
+--- openjdk.orig/jdk/src/share/classes/java/math/MathContext.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/MathContext.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -126,19 +126,6 @@
+      */
+     final RoundingMode roundingMode;
+ 
+-    /**
+-     *  Lookaside for the rounding points (the numbers which determine
+-     *  whether the coefficient of a number will require rounding).
+-     *  These will be present if {@code precision > 0} and
+-     *  {@code precision <= MAX_LOOKASIDE}.  In this case they will share the
+-     *  {@code BigInteger int[]} array.  Note that the transients
+-     *  cannot be {@code final} because they are reconstructed on
+-     *  deserialization.
+-     */
+-    transient BigInteger roundingMax = null;
+-    transient BigInteger roundingMin = null;
+-    private static final int MAX_LOOKASIDE = 1000;
+-
+     /* ----- Constructors ----- */
+ 
+     /**
+@@ -173,11 +160,6 @@
+             throw new NullPointerException("null RoundingMode");
+ 
+         precision = setPrecision;
+-        if (precision > 0 && precision <= MAX_LOOKASIDE) {
+-            roundingMax = BigInteger.TEN.pow(precision);
+-            roundingMin = roundingMax.negate();
+-        }
+-
+         roundingMode = setRoundingMode;
+         return;
+     }
+@@ -221,10 +203,6 @@
+             throw new IllegalArgumentException("Digits < 0");
+         // the other parameters cannot be invalid if we got here
+         precision = setPrecision;
+-        if (precision > 0 && precision <= MAX_LOOKASIDE) {
+-            roundingMax = BigInteger.TEN.pow(precision);
+-            roundingMin = roundingMax.negate();
+-        }
+     }
+ 
+     /**
+@@ -343,11 +321,6 @@
+             String message = "MathContext: null roundingMode in stream";
+             throw new java.io.StreamCorruptedException(message);
+         }
+-        // Set the lookaside, if applicable
+-        if (precision <= MAX_LOOKASIDE) {
+-            roundingMax = BigInteger.TEN.pow(precision);
+-            roundingMin = roundingMax.negate();
+-        }
+     }
+ 
+ }
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/MutableBigInteger.java
+--- openjdk.orig/jdk/src/share/classes/java/math/MutableBigInteger.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/MutableBigInteger.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -41,6 +41,11 @@
+  * @since   1.3
+  */
+ 
++import java.util.Arrays;
++
++import static java.math.BigInteger.LONG_MASK;
++import static java.math.BigDecimal.INFLATED;
++
+ class MutableBigInteger {
+     /**
+      * Holds the magnitude of this MutableBigInteger in big endian order.
+@@ -62,10 +67,13 @@
+      */
+     int offset = 0;
+ 
++    // Constants
+     /**
+-     * This mask is used to obtain the value of an int as if it were unsigned.
++     * MutableBigInteger with one element value array with the value 1. Used by
++     * BigDecimal divideAndRound to increment the quotient. Use this constant
++     * only when the method is not going to modify this object.
+      */
+-    private final static long LONG_MASK = 0xffffffffL;
++    static final MutableBigInteger ONE = new MutableBigInteger(1);
+ 
+     // Constructors
+ 
+@@ -90,15 +98,6 @@
+ 
+     /**
+      * Construct a new MutableBigInteger with the specified value array
+-     * up to the specified length.
+-     */
+-    MutableBigInteger(int[] val, int len) {
+-        value = val;
+-        intLen = len;
+-    }
+-
+-    /**
+-     * Construct a new MutableBigInteger with the specified value array
+      * up to the length of the array supplied.
+      */
+     MutableBigInteger(int[] val) {
+@@ -111,8 +110,8 @@
+      * specified BigInteger.
+      */
+     MutableBigInteger(BigInteger b) {
+-        value = b.mag.clone();
+-        intLen = value.length;
++        intLen = b.mag.length;
++        value = Arrays.copyOf(b.mag, intLen);
+     }
+ 
+     /**
+@@ -121,10 +120,58 @@
+      */
+     MutableBigInteger(MutableBigInteger val) {
+         intLen = val.intLen;
+-        value = new int[intLen];
++        value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen);
++    }
+ 
+-        for(int i=0; i<intLen; i++)
+-            value[i] = val.value[val.offset+i];
++    /**
++     * Internal helper method to return the magnitude array. The caller is not
++     * supposed to modify the returned array.
++     */
++    private int[] getMagnitudeArray() {
++        if (offset > 0 || value.length != intLen)
++            return Arrays.copyOfRange(value, offset, offset + intLen);
++        return value;
++    }
++
++    /**
++     * Convert this MutableBigInteger to a long value. The caller has to make
++     * sure this MutableBigInteger can be fit into long.
++     */
++    private long toLong() {
++        assert (intLen <= 2) : "this MutableBigInteger exceeds the range of long";
++        if (intLen == 0)
++            return 0;
++        long d = value[offset] & LONG_MASK;
++        return (intLen == 2) ? d << 32 | (value[offset + 1] & LONG_MASK) : d;
++    }
++
++    /**
++     * Convert this MutableBigInteger to a BigInteger object.
++     */
++    BigInteger toBigInteger(int sign) {
++        if (intLen == 0 || sign == 0)
++            return BigInteger.ZERO;
++        return new BigInteger(getMagnitudeArray(), sign);
++    }
++
++    /**
++     * Convert this MutableBigInteger to BigDecimal object with the specified sign
++     * and scale.
++     */
++    BigDecimal toBigDecimal(int sign, int scale) {
++        if (intLen == 0 || sign == 0)
++            return BigDecimal.valueOf(0, scale);
++        int[] mag = getMagnitudeArray();
++        int len = mag.length;
++        int d = mag[0];
++        // If this MutableBigInteger can't be fit into long, we need to
++        // make a BigInteger object for the resultant BigDecimal object.
++        if (len > 2 || (d < 0 && len == 2))
++            return new BigDecimal(new BigInteger(mag, sign), INFLATED, scale, 0);
++        long v = (len == 2) ?
++            ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
++            d & LONG_MASK;
++        return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
+     }
+ 
+     /**
+@@ -146,17 +193,21 @@
+     /**
+      * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1
+      * as this MutableBigInteger is numerically less than, equal to, or
+-     * greater than {@code b}.
++     * greater than <tt>b</tt>.
+      */
+     final int compare(MutableBigInteger b) {
+-        if (intLen < b.intLen)
++        int blen = b.intLen;
++        if (intLen < blen)
+             return -1;
+-        if (intLen > b.intLen)
+-            return 1;
++        if (intLen > blen)
++           return 1;
+ 
+-        for (int i=0; i<intLen; i++) {
+-            int b1 = value[offset+i]     + 0x80000000;
+-            int b2 = b.value[b.offset+i] + 0x80000000;
++        // Add Integer.MIN_VALUE to make the comparison act as unsigned integer
++        // comparison.
++        int[] bval = b.value;
++        for (int i = offset, j = b.offset; i < intLen + offset; i++, j++) {
++            int b1 = value[i] + 0x80000000;
++            int b2 = bval[j]  + 0x80000000;
+             if (b1 < b2)
+                 return -1;
+             if (b1 > b2)
+@@ -166,6 +217,46 @@
+     }
+ 
+     /**
++     * Compare this against half of a MutableBigInteger object (Needed for
++     * remainder tests).
++     * Assumes no leading unnecessary zeros, which holds for results
++     * from divide().
++     */
++    final int compareHalf(MutableBigInteger b) {
++        int blen = b.intLen;
++        int len = intLen;
++        if (len <= 0)
++            return blen <=0 ? 0 : -1;
++        if (len > blen)
++            return 1;
++        if (len < blen - 1)
++            return -1;
++        int[] bval = b.value;
++        int bstart = 0;
++        int carry = 0;
++        // Only 2 cases left:len == blen or len == blen - 1
++        if (len != blen) { // len == blen - 1
++            if (bval[bstart] == 1) {
++                ++bstart;
++                carry = 0x80000000;
++            } else
++                return -1;
++        }
++        // compare values with right-shifted values of b,
++        // carrying shifted-out bits across words
++        int[] val = value;
++        for (int i = offset, j = bstart; i < len + offset;) {
++            int bv = bval[j++];
++            long hb = ((bv >>> 1) + carry) & LONG_MASK;
++            long v = val[i++] & LONG_MASK;
++            if (v != hb)
++                return v < hb ? -1 : 1;
++            carry = (bv & 1) << 31; // carray will be either 0x80000000 or 0
++        }
++        return carry == 0? 0 : -1;
++    }
++
++    /**
+      * Return the index of the lowest set bit in this MutableBigInteger. If the
+      * magnitude of this MutableBigInteger is zero, -1 is returned.
+      */
+@@ -178,7 +269,7 @@
+         b = value[j+offset];
+         if (b==0)
+             return -1;
+-        return ((intLen-1-j)<<5) + BigInteger.trailingZeroCnt(b);
++        return ((intLen-1-j)<<5) + Integer.numberOfTrailingZeros(b);
+     }
+ 
+     /**
+@@ -270,13 +361,11 @@
+      * Sets this MutableBigInteger's value array to a copy of the specified
+      * array. The intLen is set to the length of the new array.
+      */
+-    void copyValue(MutableBigInteger val) {
+-        int len = val.intLen;
++    void copyValue(MutableBigInteger src) {
++        int len = src.intLen;
+         if (value.length < len)
+             value = new int[len];
+-
+-        for(int i=0; i<len; i++)
+-            value[i] = val.value[val.offset+i];
++        System.arraycopy(src.value, src.offset, value, 0, len);
+         intLen = len;
+         offset = 0;
+     }
+@@ -289,8 +378,7 @@
+         int len = val.length;
+         if (value.length < len)
+             value = new int[len];
+-        for(int i=0; i<len; i++)
+-            value[i] = val[i];
++        System.arraycopy(val, 0, value, 0, len);
+         intLen = len;
+         offset = 0;
+     }
+@@ -320,7 +408,7 @@
+      * Returns true iff this MutableBigInteger is odd.
+      */
+     boolean isOdd() {
+-        return ((value[offset + intLen - 1] & 1) == 1);
++        return isZero() ? false : ((value[offset + intLen - 1] & 1) == 1);
+     }
+ 
+     /**
+@@ -340,7 +428,7 @@
+      * Returns a String representation of this MutableBigInteger in radix 10.
+      */
+     public String toString() {
+-        BigInteger b = new BigInteger(this, 1);
++        BigInteger b = toBigInteger(1);
+         return b.toString();
+     }
+ 
+@@ -356,7 +444,7 @@
+         this.intLen -= nInts;
+         if (nBits == 0)
+             return;
+-        int bitsInHighWord = BigInteger.bitLen(value[offset]);
++        int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
+         if (nBits >= bitsInHighWord) {
+             this.primitiveLeftShift(32 - nBits);
+             this.intLen--;
+@@ -379,7 +467,7 @@
+            return;
+         int nInts = n >>> 5;
+         int nBits = n&0x1F;
+-        int bitsInHighWord = BigInteger.bitLen(value[offset]);
++        int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
+ 
+         // If shift can be done without moving words, do so
+         if (n <= (32-bitsInHighWord)) {
+@@ -499,34 +587,41 @@
+         int[] result = (value.length < resultLen ? new int[resultLen] : value);
+ 
+         int rstart = result.length-1;
+-        long sum = 0;
++        long sum;
++        long carry = 0;
+ 
+         // Add common parts of both numbers
+         while(x>0 && y>0) {
+             x--; y--;
+             sum = (value[x+offset] & LONG_MASK) +
+-                (addend.value[y+addend.offset] & LONG_MASK) + (sum >>> 32);
++                (addend.value[y+addend.offset] & LONG_MASK) + carry;
+             result[rstart--] = (int)sum;
++            carry = sum >>> 32;
+         }
+ 
+         // Add remainder of the longer number
+         while(x>0) {
+             x--;
+-            sum = (value[x+offset] & LONG_MASK) + (sum >>> 32);
++            if (carry == 0 && result == value && rstart == (x + offset))
++                return;
++            sum = (value[x+offset] & LONG_MASK) + carry;
+             result[rstart--] = (int)sum;
++            carry = sum >>> 32;
+         }
+         while(y>0) {
+             y--;
+-            sum = (addend.value[y+addend.offset] & LONG_MASK) + (sum >>> 32);
++            sum = (addend.value[y+addend.offset] & LONG_MASK) + carry;
+             result[rstart--] = (int)sum;
++            carry = sum >>> 32;
+         }
+ 
+-        if ((sum >>> 32) > 0) { // Result must grow in length
++        if (carry > 0) { // Result must grow in length
+             resultLen++;
+             if (result.length < resultLen) {
+                 int temp[] = new int[resultLen];
+-                for (int i=resultLen-1; i>0; i--)
+-                    temp[i] = result[i-1];
++                // Result one word longer from carry-out; copy low-order
++                // bits into new result.
++                System.arraycopy(result, 0, temp, 1, result.length);
+                 temp[0] = 1;
+                 result = temp;
+             } else {
+@@ -708,29 +803,26 @@
+         z.value = zval;
+     }
+ 
+-    /**
++     /**
+      * This method is used for division of an n word dividend by a one word
+      * divisor. The quotient is placed into quotient. The one word divisor is
+-     * specified by divisor. The value of this MutableBigInteger is the
+-     * dividend at invocation but is replaced by the remainder.
++     * specified by divisor.
+      *
+-     * NOTE: The value of this MutableBigInteger is modified by this method.
++     * @return the remainder of the division is returned.
++     *
+      */
+-    void divideOneWord(int divisor, MutableBigInteger quotient) {
+-        long divLong = divisor & LONG_MASK;
++    int divideOneWord(int divisor, MutableBigInteger quotient) {
++        long divisorLong = divisor & LONG_MASK;
+ 
+         // Special case of one word dividend
+         if (intLen == 1) {
+-            long remValue = value[offset] & LONG_MASK;
+-            quotient.value[0] = (int) (remValue / divLong);
+-            quotient.intLen = (quotient.value[0] == 0) ? 0 : 1;
++            long dividendValue = value[offset] & LONG_MASK;
++            int q = (int) (dividendValue / divisorLong);
++            int r = (int) (dividendValue - q * divisorLong);
++            quotient.value[0] = q;
++            quotient.intLen = (q == 0) ? 0 : 1;
+             quotient.offset = 0;
+-
+-            value[0] = (int) (remValue - (quotient.value[0] * divLong));
+-            offset = 0;
+-            intLen = (value[0] == 0) ? 0 : 1;
+-
+-            return;
++            return r;
+         }
+ 
+         if (quotient.value.length < intLen)
+@@ -739,15 +831,15 @@
+         quotient.intLen = intLen;
+ 
+         // Normalize the divisor
+-        int shift = 32 - BigInteger.bitLen(divisor);
++        int shift = Integer.numberOfLeadingZeros(divisor);
+ 
+         int rem = value[offset];
+         long remLong = rem & LONG_MASK;
+-        if (remLong < divLong) {
++        if (remLong < divisorLong) {
+             quotient.value[0] = 0;
+         } else {
+-            quotient.value[0] = (int)(remLong/divLong);
+-            rem = (int) (remLong - (quotient.value[0] * divLong));
++            quotient.value[0] = (int)(remLong / divisorLong);
++            rem = (int) (remLong - (quotient.value[0] * divisorLong));
+             remLong = rem & LONG_MASK;
+         }
+ 
+@@ -757,8 +849,8 @@
+             long dividendEstimate = (remLong<<32) |
+                 (value[offset + intLen - xlen] & LONG_MASK);
+             if (dividendEstimate >= 0) {
+-                qWord[0] = (int) (dividendEstimate/divLong);
+-                qWord[1] = (int) (dividendEstimate - (qWord[0] * divLong));
++                qWord[0] = (int) (dividendEstimate / divisorLong);
++                qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
+             } else {
+                 divWord(qWord, dividendEstimate, divisor);
+             }
+@@ -767,81 +859,110 @@
+             remLong = rem & LONG_MASK;
+         }
+ 
++        quotient.normalize();
+         // Unnormalize
+         if (shift > 0)
+-            value[0] = rem %= divisor;
++            return rem % divisor;
+         else
+-            value[0] = rem;
+-        intLen = (value[0] == 0) ? 0 : 1;
+-
+-        quotient.normalize();
++            return rem;
+     }
+ 
+-
+     /**
+-     * Calculates the quotient and remainder of this div b and places them
+-     * in the MutableBigInteger objects provided.
++     * Calculates the quotient of this div b and places the quotient in the
++     * provided MutableBigInteger objects and the remainder object is returned.
+      *
+      * Uses Algorithm D in Knuth section 4.3.1.
+      * Many optimizations to that algorithm have been adapted from the Colin
+      * Plumb C library.
+-     * It special cases one word divisors for speed.
+-     * The contents of a and b are not changed.
++     * It special cases one word divisors for speed. The content of b is not
++     * changed.
+      *
+      */
+-    void divide(MutableBigInteger b,
+-                        MutableBigInteger quotient, MutableBigInteger rem) {
++    MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
+         if (b.intLen == 0)
+             throw new ArithmeticException("BigInteger divide by zero");
+ 
+         // Dividend is zero
+         if (intLen == 0) {
+-            quotient.intLen = quotient.offset = rem.intLen = rem.offset = 0;
+-            return;
++            quotient.intLen = quotient.offset;
++            return new MutableBigInteger();
+         }
+ 
+         int cmp = compare(b);
+-
+         // Dividend less than divisor
+         if (cmp < 0) {
+             quotient.intLen = quotient.offset = 0;
+-            rem.copyValue(this);
+-            return;
++            return new MutableBigInteger(this);
+         }
+         // Dividend equal to divisor
+         if (cmp == 0) {
+             quotient.value[0] = quotient.intLen = 1;
+-            quotient.offset = rem.intLen = rem.offset = 0;
+-            return;
++            quotient.offset = 0;
++            return new MutableBigInteger();
+         }
+ 
+         quotient.clear();
+-
+         // Special case one word divisor
+         if (b.intLen == 1) {
+-            rem.copyValue(this);
+-            rem.divideOneWord(b.value[b.offset], quotient);
+-            return;
++            int r = divideOneWord(b.value[b.offset], quotient);
++            if (r == 0)
++                return new MutableBigInteger();
++            return new MutableBigInteger(r);
+         }
+ 
+         // Copy divisor value to protect divisor
+-        int[] d = new int[b.intLen];
+-        for(int i=0; i<b.intLen; i++)
+-            d[i] = b.value[b.offset+i];
+-        int dlen = b.intLen;
++        int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
++        return divideMagnitude(div, quotient);
++    }
++
++    /**
++     * Internally used  to calculate the quotient of this div v and places the
++     * quotient in the provided MutableBigInteger object and the remainder is
++     * returned.
++     *
++     * @return the remainder of the division will be returned.
++     */
++    long divide(long v, MutableBigInteger quotient) {
++        if (v == 0)
++            throw new ArithmeticException("BigInteger divide by zero");
++
++        // Dividend is zero
++        if (intLen == 0) {
++            quotient.intLen = quotient.offset = 0;
++            return 0;
++        }
++        if (v < 0)
++            v = -v;
++
++        int d = (int)(v >>> 32);
++        quotient.clear();
++        // Special case on word divisor
++        if (d == 0)
++            return divideOneWord((int)v, quotient) & LONG_MASK;
++        else {
++            int[] div = new int[]{ d, (int)(v & LONG_MASK) };
++            return divideMagnitude(div, quotient).toLong();
++        }
++    }
++
++    /**
++     * Divide this MutableBigInteger by the divisor represented by its magnitude
++     * array. The quotient will be placed into the provided quotient object &
++     * the remainder object is returned.
++     */
++    private MutableBigInteger divideMagnitude(int[] divisor,
++                                              MutableBigInteger quotient) {
+ 
+         // Remainder starts as dividend with space for a leading zero
+-        if (rem.value.length < intLen +1)
+-            rem.value = new int[intLen+1];
+-
+-        for (int i=0; i<intLen; i++)
+-            rem.value[i+1] = value[i+offset];
++        MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
++        System.arraycopy(value, offset, rem.value, 1, intLen);
+         rem.intLen = intLen;
+         rem.offset = 1;
+ 
+         int nlen = rem.intLen;
+ 
+         // Set the quotient size
++        int dlen = divisor.length;
+         int limit = nlen - dlen + 1;
+         if (quotient.value.length < limit) {
+             quotient.value = new int[limit];
+@@ -851,10 +972,10 @@
+         int[] q = quotient.value;
+ 
+         // D1 normalize the divisor
+-        int shift = 32 - BigInteger.bitLen(d[0]);
++        int shift = Integer.numberOfLeadingZeros(divisor[0]);
+         if (shift > 0) {
+             // First shift will not grow array
+-            BigInteger.primitiveLeftShift(d, dlen, shift);
++            BigInteger.primitiveLeftShift(divisor, dlen, shift);
+             // But this one might
+             rem.leftShift(shift);
+         }
+@@ -866,9 +987,9 @@
+             rem.intLen++;
+         }
+ 
+-        int dh = d[0];
++        int dh = divisor[0];
+         long dhLong = dh & LONG_MASK;
+-        int dl = d[1];
++        int dl = divisor[1];
+         int[] qWord = new int[2];
+ 
+         // D2 Initialize j
+@@ -910,7 +1031,7 @@
+                     qhat--;
+                     qrem = (int)((qrem & LONG_MASK) + dhLong);
+                     if ((qrem & LONG_MASK) >=  dhLong) {
+-                        estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
++                        estProduct -= (dl & LONG_MASK);
+                         rs = ((qrem & LONG_MASK) << 32) | nl;
+                         if (unsignedLongCompare(estProduct, rs))
+                             qhat--;
+@@ -920,12 +1041,12 @@
+ 
+             // D4 Multiply and subtract
+             rem.value[j+rem.offset] = 0;
+-            int borrow = mulsub(rem.value, d, qhat, dlen, j+rem.offset);
++            int borrow = mulsub(rem.value, divisor, qhat, dlen, j+rem.offset);
+ 
+             // D5 Test remainder
+             if (borrow + 0x80000000 > nh2) {
+                 // D6 Add back
+-                divadd(d, rem.value, j+1+rem.offset);
++                divadd(divisor, rem.value, j+1+rem.offset);
+                 qhat--;
+             }
+ 
+@@ -937,8 +1058,9 @@
+         if (shift > 0)
+             rem.rightShift(shift);
+ 
++        quotient.normalize();
+         rem.normalize();
+-        quotient.normalize();
++        return rem;
+     }
+ 
+     /**
+@@ -989,16 +1111,15 @@
+         // Use Euclid's algorithm until the numbers are approximately the
+         // same length, then use the binary GCD algorithm to find the GCD.
+         MutableBigInteger a = this;
+-        MutableBigInteger q = new MutableBigInteger(),
+-                          r = new MutableBigInteger();
++        MutableBigInteger q = new MutableBigInteger();
+ 
+         while (b.intLen != 0) {
+             if (Math.abs(a.intLen - b.intLen) < 2)
+                 return a.binaryGCD(b);
+ 
+-            a.divide(b, q, r);
+-            MutableBigInteger swapper = a;
+-            a = b; b = r; r = swapper;
++            MutableBigInteger r = a.divide(b, q);
++            a = b;
++            b = r;
+         }
+         return a;
+     }
+@@ -1069,40 +1190,21 @@
+         if (a==0)
+             return b;
+ 
+-        int x;
+-        int aZeros = 0;
+-        while ((x = a & 0xff) == 0) {
+-            a >>>= 8;
+-            aZeros += 8;
+-        }
+-        int y = BigInteger.trailingZeroTable[x];
+-        aZeros += y;
+-        a >>>= y;
+-
+-        int bZeros = 0;
+-        while ((x = b & 0xff) == 0) {
+-            b >>>= 8;
+-            bZeros += 8;
+-        }
+-        y = BigInteger.trailingZeroTable[x];
+-        bZeros += y;
+-        b >>>= y;
++        // Right shift a & b till their last bits equal to 1.
++        int aZeros = Integer.numberOfTrailingZeros(a);
++        int bZeros = Integer.numberOfTrailingZeros(b);
++        a >>>= aZeros;
++        b >>>= bZeros;
+ 
+         int t = (aZeros < bZeros ? aZeros : bZeros);
+ 
+         while (a != b) {
+             if ((a+0x80000000) > (b+0x80000000)) {  // a > b as unsigned
+                 a -= b;
+-
+-                while ((x = a & 0xff) == 0)
+-                    a >>>= 8;
+-                a >>>= BigInteger.trailingZeroTable[x];
++                a >>>= Integer.numberOfTrailingZeros(a);
+             } else {
+                 b -= a;
+-
+-                while ((x = b & 0xff) == 0)
+-                    b >>>= 8;
+-                b >>>= BigInteger.trailingZeroTable[x];
++                b >>>= Integer.numberOfTrailingZeros(b);
+             }
+         }
+         return a<<t;
+@@ -1152,8 +1254,7 @@
+         temp1.multiply(y2, temp2);
+ 
+         result.add(temp2);
+-        result.divide(p, temp1, temp2);
+-        return temp2;
++        return result.divide(p, temp1);
+     }
+ 
+     /*
+@@ -1321,40 +1422,45 @@
+ 
+         MutableBigInteger a = new MutableBigInteger(this);
+         MutableBigInteger q = new MutableBigInteger();
+-        MutableBigInteger r = new MutableBigInteger();
++        MutableBigInteger r = b.divide(a, q);
+ 
+-        b.divide(a, q, r);
+-        MutableBigInteger swapper = b; b = r; r = swapper;
++        MutableBigInteger swapper = b;
++        // swap b & r
++        b = r;
++        r = swapper;
+ 
+         MutableBigInteger t1 = new MutableBigInteger(q);
+         MutableBigInteger t0 = new MutableBigInteger(1);
+         MutableBigInteger temp = new MutableBigInteger();
+ 
+         while (!b.isOne()) {
+-            a.divide(b, q, r);
++            r = a.divide(b, q);
+ 
+             if (r.intLen == 0)
+                 throw new ArithmeticException("BigInteger not invertible.");
+ 
+-            swapper = r; r = a; a = swapper;
++            swapper = r;
++            a = swapper;
+ 
+             if (q.intLen == 1)
+                 t1.mul(q.value[q.offset], temp);
+             else
+                 q.multiply(t1, temp);
+-            swapper = q; q = temp; temp = swapper;
+-
++            swapper = q;
++            q = temp;
++            temp = swapper;
+             t0.add(q);
+ 
+             if (a.isOne())
+                 return t0;
+ 
+-            b.divide(a, q, r);
++            r = b.divide(a, q);
+ 
+             if (r.intLen == 0)
+                 throw new ArithmeticException("BigInteger not invertible.");
+ 
+-            swapper = b; b = r; r = swapper;
++            swapper = b;
++            b =  r;
+ 
+             if (q.intLen == 1)
+                 t0.mul(q.value[q.offset], temp);
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 src/share/classes/java/math/SignedMutableBigInteger.java
+--- openjdk.orig/jdk/src/share/classes/java/math/SignedMutableBigInteger.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/src/share/classes/java/math/SignedMutableBigInteger.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -129,9 +129,7 @@
+      * array starting at offset.
+      */
+     public String toString() {
+-        BigInteger b = new BigInteger(this, sign);
+-        return
+-            b.toString();
++        return this.toBigInteger(sign).toString();
+     }
+ 
+ }
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 test/java/math/BigDecimal/AddTests.java
+--- openjdk.orig/jdk/test/java/math/BigDecimal/AddTests.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/test/java/math/BigDecimal/AddTests.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -39,6 +39,31 @@
+         EnumSet.complementOf(EnumSet.of(RoundingMode.UNNECESSARY));
+ 
+     /**
++     * Test for some simple additions, particularly, it will test
++     * the overflow case.
++     */
++    private static int simpleTests() {
++        int failures = 0;
++
++        BigDecimal[] bd1 = {
++            new BigDecimal(new BigInteger("7812404666936930160"), 11),
++            new BigDecimal(new BigInteger("7812404666936930160"), 12),
++            new BigDecimal(new BigInteger("7812404666936930160"), 13),
++        };
++        BigDecimal bd2 = new BigDecimal(new BigInteger("2790000"), 1);
++        BigDecimal[] expectedResult = {
++            new BigDecimal("78403046.66936930160"),
++            new BigDecimal("8091404.666936930160"),
++            new BigDecimal("1060240.4666936930160"),
++        };
++        for (int i = 0; i < bd1.length; i++) {
++            if (!bd1[i].add(bd2).equals(expectedResult[i]))
++                failures++;
++        }
++        return failures;
++    }
++
++    /**
+      * Test for extreme value of scale and rounding precision that
+      * could cause integer overflow in right-shift-into-sticky-bit
+      * computations.
+diff -r 2b1a7d4b9ac6 -r cadc64fc2282 test/java/math/BigDecimal/DivideTests.java
+--- openjdk.orig/jdk/test/java/math/BigDecimal/DivideTests.java	Fri Jun 25 11:53:15 2010 -0700
++++ openjdk/jdk/test/java/math/BigDecimal/DivideTests.java	Wed Nov 03 12:43:51 2010 +0000
+@@ -281,6 +281,10 @@
+         BigDecimal c = new BigDecimal("31425");
+         BigDecimal c_minus = c.negate();
+ 
++         // Ad hoc tests
++        BigDecimal d = new BigDecimal(new BigInteger("-37361671119238118911893939591735"), 10);
++        BigDecimal e = new BigDecimal(new BigInteger("74723342238476237823787879183470"), 15);
++
+         BigDecimal[][] testCases = {
+             {a,         b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("3.142")},
+             {a_minus,   b,      BigDecimal.valueOf(ROUND_UP, 3),        new BigDecimal("-3.142")},
+@@ -305,6 +309,10 @@
+ 
+             {c,         b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("3.142")},
+             {c_minus,   b,      BigDecimal.valueOf(ROUND_HALF_EVEN, 3), new BigDecimal("-3.142")},
++
++            {d,         e,      BigDecimal.valueOf(ROUND_HALF_UP, -5),   BigDecimal.valueOf(-1, -5)},
++            {d,         e,      BigDecimal.valueOf(ROUND_HALF_DOWN, -5), BigDecimal.valueOf(0, -5)},
++            {d,         e,      BigDecimal.valueOf(ROUND_HALF_EVEN, -5), BigDecimal.valueOf(0, -5)},
+         };
+ 
+         for(BigDecimal tc[] : testCases) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/openjdk/6850606-bigdecimal_regression.patch	Wed Nov 10 19:17:09 2010 +0000
@@ -0,0 +1,144 @@
+# HG changeset patch
+# User aph
+# Date 1288790489 0
+# Node ID 3857c2791784a6e7910a475e9e88233e90f59c0b
+# Parent  cadc64fc2282d7704a3c80799a5723b502b7d69f
+6850606: Regression from JDK 1.6.0_12
+Summary: The returned result from multiply should be constructed by using valueOf to take care of the INFLATED case.
+Reviewed-by: darcy
+
+diff -r cadc64fc2282 -r 3857c2791784 src/share/classes/java/math/BigDecimal.java
+--- openjdk.orig/jdk/src/share/classes/java/math/BigDecimal.java	Wed Nov 03 12:43:51 2010 +0000
++++ openjdk/jdk/src/share/classes/java/math/BigDecimal.java	Wed Nov 03 13:21:29 2010 +0000
+@@ -1101,7 +1101,7 @@
+             // See "Hacker's Delight" section 2-12 for explanation of
+             // the overflow test.
+             if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
+-                return new BigDecimal(null, sum, rscale, 0);
++                return BigDecimal.valueOf(sum, rscale);
+         }
+         if (fst == null)
+             fst = BigInteger.valueOf(xs);
+@@ -1311,9 +1311,9 @@
+              * would occur since division is expensive on most CPUs.
+              */
+             long product = x * y;
+-            int prec = this.precision() + multiplicand.precision();
++            long prec = this.precision() + multiplicand.precision();
+             if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
+-                return new BigDecimal(null, product, productScale, 0);
++                return BigDecimal.valueOf(product, productScale);
+             return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
+                                   productScale, 0);
+         }
+@@ -1584,7 +1584,7 @@
+             return (preferredScale >= 0 &&
+                     preferredScale < ZERO_SCALED_BY.length) ?
+                 ZERO_SCALED_BY[preferredScale] :
+-                new BigDecimal(null, 0, preferredScale, 1);
++                BigDecimal.valueOf(0, preferredScale);
+         else {
+             this.inflate();
+             divisor.inflate();
+diff -r cadc64fc2282 -r 3857c2791784 test/java/math/BigDecimal/MultiplyTests.java
+--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
++++ openjdk/jdk/test/java/math/BigDecimal/MultiplyTests.java	Wed Nov 03 13:21:29 2010 +0000
+@@ -0,0 +1,98 @@
++/*
++ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++/*
++ * @test
++ * @bug 6850606
++ * @summary Test BigDecimal.multiply(BigDecimal)
++ * @author xlu
++ */
++
++import java.math.*;
++import static java.math.BigDecimal.*;
++
++public class MultiplyTests {
++
++    private static int multiplyTests() {
++        int failures = 0;
++
++        BigDecimal[] bd1 = {
++            new BigDecimal("123456789"),
++            new BigDecimal("1234567898"),
++            new BigDecimal("12345678987")
++        };
++
++        BigDecimal[] bd2 = {
++            new BigDecimal("987654321"),
++            new BigDecimal("8987654321"),
++            new BigDecimal("78987654321")
++        };
++
++        // Two dimensonal array recording bd1[i] * bd2[j] &
++        // 0 <= i <= 2 && 0 <= j <= 2;
++        BigDecimal[][] expectedResults = {
++            {new BigDecimal("121932631112635269"),
++             new BigDecimal("1109586943112635269"),
++             new BigDecimal("9751562173112635269")
++            },
++            { new BigDecimal("1219326319027587258"),
++              new BigDecimal("11095869503027587258"),
++              new BigDecimal("97515622363027587258")
++            },
++            { new BigDecimal("12193263197189452827"),
++              new BigDecimal("110958695093189452827"),
++              new BigDecimal("975156224183189452827")
++            }
++        };
++
++        for (int i = 0; i < bd1.length; i++) {
++            for (int j = 0; j < bd2.length; j++) {
++                if (!bd1[i].multiply(bd2[j]).equals(expectedResults[i][j])) {
++                    failures++;
++                }
++            }
++        }
++
++        BigDecimal x = BigDecimal.valueOf(8L, 1);
++        BigDecimal xPower = BigDecimal.valueOf(-1L);
++        try {
++            for (int i = 0; i < 100; i++) {
++                xPower = xPower.multiply(x);
++            }
++        } catch (Exception ex) {
++            failures++;
++        }
++        return failures;
++    }
++
++    public static void main(String[] args) {
++        int failures = 0;
++
++        failures += multiplyTests();
++
++        if (failures > 0) {
++            throw new RuntimeException("Incurred " + failures +
++                                       " failures while testing multiply.");
++        }
++    }
++}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/openjdk/6876282-bigdecimal_divide.patch	Wed Nov 10 19:17:09 2010 +0000
@@ -0,0 +1,89 @@
+# HG changeset patch
+# User xlu
+# Date 1251421216 25200
+# Node ID c2b73679ba94d7e93ddf5766e60fc03c9b63615b
+# Parent  3857c2791784a6e7910a475e9e88233e90f59c0b
+6876282: BigDecimal's divide(BigDecimal bd, RoundingFormat r) produces incorrect result
+Reviewed-by: darcy
+
+diff -r 3857c2791784 -r c2b73679ba94 src/share/classes/java/math/BigDecimal.java
+--- openjdk.orig/jdk/src/share/classes/java/math/BigDecimal.java	Wed Nov 03 13:21:29 2010 +0000
++++ openjdk/jdk/src/share/classes/java/math/BigDecimal.java	Thu Aug 27 18:00:16 2009 -0700
+@@ -315,6 +315,10 @@
+         new BigDecimal(BigInteger.ZERO, 0, 15, 1),
+     };
+ 
++    // Half of Long.MIN_VALUE & Long.MAX_VALUE.
++    private static final long HALF_LONG_MAX_VALUE = Long.MAX_VALUE / 2;
++    private static final long HALF_LONG_MIN_VALUE = Long.MIN_VALUE / 2;
++
+     // Constants
+     /**
+      * The value 0, with a scale of 0.
+@@ -1455,10 +1459,15 @@
+             } else if (roundingMode == ROUND_FLOOR) {   // Towards -infinity
+                 increment = (qsign < 0);
+             } else {
+-                if (isLongDivision || ldivisor != INFLATED)
+-                    cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+-                else
++                if (isLongDivision || ldivisor != INFLATED) {
++                    if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
++                        cmpFracHalf = 1;    // 2 * r can't fit into long
++                    } else {
++                        cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
++                    }
++                } else {
+                     cmpFracHalf = mr.compareHalf(mdivisor);
++                }
+                 if (cmpFracHalf < 0)
+                     increment = false;     // We're closer to higher digit
+                 else if (cmpFracHalf > 0)  // We're closer to lower digit
+diff -r 3857c2791784 -r c2b73679ba94 test/java/math/BigDecimal/DivideTests.java
+--- openjdk.orig/jdk/test/java/math/BigDecimal/DivideTests.java	Wed Nov 03 13:21:29 2010 +0000
++++ openjdk/jdk/test/java/math/BigDecimal/DivideTests.java	Thu Aug 27 18:00:16 2009 -0700
+@@ -23,7 +23,7 @@
+ 
+ /*
+  * @test
+- * @bug 4851776 4907265 6177836
++ * @bug 4851776 4907265 6177836 6876282
+  * @summary Some tests for the divide methods.
+  * @author Joseph D. Darcy
+  * @compile -source 1.5 DivideTests.java
+@@ -328,6 +328,35 @@
+             }
+         }
+ 
++        // 6876282
++        BigDecimal[][] testCases2 = {
++            // { dividend, divisor, expected quotient }
++            { new BigDecimal(3090), new BigDecimal(7), new BigDecimal(441) },
++            { new BigDecimal("309000000000000000000000"), new BigDecimal("700000000000000000000"),
++              new BigDecimal(441) },
++            { new BigDecimal("962.430000000000"), new BigDecimal("8346463.460000000000"),
++              new BigDecimal("0.000115309916") },
++            { new BigDecimal("18446744073709551631"), new BigDecimal("4611686018427387909"),
++              new BigDecimal(4) },
++            { new BigDecimal("18446744073709551630"), new BigDecimal("4611686018427387909"),
++              new BigDecimal(4) },
++            { new BigDecimal("23058430092136939523"), new BigDecimal("4611686018427387905"),
++              new BigDecimal(5) },
++            { new BigDecimal("-18446744073709551661"), new BigDecimal("-4611686018427387919"),
++              new BigDecimal(4) },
++            { new BigDecimal("-18446744073709551660"), new BigDecimal("-4611686018427387919"),
++              new BigDecimal(4) },
++        };
++
++        for (BigDecimal test[] : testCases2) {
++            BigDecimal quo = test[0].divide(test[1], RoundingMode.HALF_UP);
++            if (!quo.equals(test[2])) {
++                failures++;
++                System.err.println("Unexpected quotient from " + test[0] + " / " + test[1] +
++                                   " rounding mode HALF_UP" +
++                                   "; expected " + test[2] + " got " + quo);
++            }
++        }
+         return failures;
+     }
+