/hg/icedtea6: Backport BigDecimal/Integer performance improvements.

andrew at icedtea.classpath.org andrew at icedtea.classpath.org
Wed Nov 10 06:13:50 PST 2010


changeset 2fafb0bc27f2 in /hg/icedtea6
details: http://icedtea.classpath.org/hg/icedtea6?cmd=changeset;node=2fafb0bc27f2
author: Andrew John Hughes <ahughes at redhat.com>
date: Wed Nov 10 14:13:42 2010 +0000

	Backport BigDecimal/Integer performance improvements.

	2010-11-10 Andrew John Hughes <ahughes at 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.


diffstat:

5 files changed, 4457 insertions(+), 1 deletion(-)
ChangeLog                                            |    9 
Makefile.am                                          |    5 
patches/openjdk/6622432-bigdecimal_performance.patch | 4211 ++++++++++++++++++
patches/openjdk/6850606-bigdecimal_regression.patch  |  144 
patches/openjdk/6876282-bigdecimal_divide.patch      |   89 

diffs (truncated from 4487 to 500 lines):

diff -r 72de51f0a744 -r 2fafb0bc27f2 ChangeLog
--- a/ChangeLog	Tue Nov 09 14:53:31 2010 +0000
+++ b/ChangeLog	Wed Nov 10 14:13:42 2010 +0000
@@ -1,3 +1,12 @@ 2010-11-09  Andrew John Hughes  <ahughes
+2010-11-10  Andrew John Hughes  <ahughes at 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 at redhat.com>
 
 	* Makefile.am:
diff -r 72de51f0a744 -r 2fafb0bc27f2 Makefile.am
--- a/Makefile.am	Tue Nov 09 14:53:31 2010 +0000
+++ b/Makefile.am	Wed Nov 10 14:13:42 2010 +0000
@@ -295,7 +295,10 @@ ICEDTEA_PATCHES = \
 	patches/6703377-freetypescaler.patch \
 	patches/icedtea-jtreg-international-fonts.patch \
 	patches/openjdk/6967436-6976265-6967434-pisces.patch \
-	patches/openjdk/6997495-test_correction_6857159.patch
+	patches/openjdk/6997495-test_correction_6857159.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 += \
diff -r 72de51f0a744 -r 2fafb0bc27f2 patches/openjdk/6622432-bigdecimal_performance.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/openjdk/6622432-bigdecimal_performance.patch	Wed Nov 10 14:13:42 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) {



More information about the distro-pkg-dev mailing list