6807702: Integer.valueOf cache should be configurable
authoralanb
Tue, 24 Mar 2009 14:05:44 +0000
changeset 2425 99a19a90813e
parent 2424 3663fccf2fc3
child 2426 a528c0830862
6807702: Integer.valueOf cache should be configurable Reviewed-by: darcy
jdk/src/share/classes/java/lang/Integer.java
jdk/src/share/classes/java/lang/Long.java
jdk/src/share/classes/java/lang/System.java
jdk/test/java/lang/Integer/ValueOf.java
--- a/jdk/src/share/classes/java/lang/Integer.java	Tue Mar 24 14:03:46 2009 +0000
+++ b/jdk/src/share/classes/java/lang/Integer.java	Tue Mar 24 14:05:44 2009 +0000
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import java.util.Properties;
+
 /**
  * The {@code Integer} class wraps a value of the primitive type
  * {@code int} in an object. An object of type {@code Integer}
@@ -442,6 +444,12 @@
     public static int parseInt(String s, int radix)
                 throws NumberFormatException
     {
+        /*
+         * WARNING: This method may be invoked early during VM initialization
+         * before IntegerCache is initialized. Care must be taken to not use
+         * the valueOf method.
+         */
+
         if (s == null) {
             throw new NumberFormatException("null");
         }
@@ -545,7 +553,7 @@
      *            does not contain a parsable {@code int}.
      */
     public static Integer valueOf(String s, int radix) throws NumberFormatException {
-        return new Integer(parseInt(s,radix));
+        return Integer.valueOf(parseInt(s,radix));
     }
 
     /**
@@ -570,20 +578,56 @@
      * @exception  NumberFormatException  if the string cannot be parsed
      *             as an integer.
      */
-    public static Integer valueOf(String s) throws NumberFormatException
-    {
-        return new Integer(parseInt(s, 10));
+    public static Integer valueOf(String s) throws NumberFormatException {
+        return Integer.valueOf(parseInt(s, 10));
+    }
+
+    /**
+     * Cache to support the object identity semantics of autoboxing for values between
+     * -128 and 127 (inclusive) as required by JLS.
+     *
+     * The cache is initialized on first usage. During VM initialization the
+     * getAndRemoveCacheProperties method may be used to get and remove any system
+     * properites that configure the cache size. At this time, the size of the
+     * cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.
+     */
+
+    // value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
+    private static String integerCacheHighPropValue;
+
+    static void getAndRemoveCacheProperties() {
+        if (!sun.misc.VM.isBooted()) {
+            Properties props = System.getProperties();
+            integerCacheHighPropValue =
+                (String)props.remove("java.lang.Integer.IntegerCache.high");
+            if (integerCacheHighPropValue != null)
+                System.setProperties(props);  // remove from system props
+        }
     }
 
     private static class IntegerCache {
-        private IntegerCache(){}
-
-        static final Integer cache[] = new Integer[-(-128) + 127 + 1];
+        static final int low = -128;
+        static final int high;
+        static final Integer cache[];
 
         static {
-            for(int i = 0; i < cache.length; i++)
-                cache[i] = new Integer(i - 128);
+            // high value may be configured by property
+            int h = 127;
+            if (integerCacheHighPropValue != null) {
+                int i = parseInt(integerCacheHighPropValue);
+                i = Math.max(i, 127);
+                // Maximum array size is Integer.MAX_VALUE
+                h = Math.min(i, Integer.MAX_VALUE - (-low));
+            }
+            high = h;
+
+            cache = new Integer[(high - low) + 1];
+            int j = low;
+            for(int k = 0; k < cache.length; k++)
+                cache[k] = new Integer(j++);
         }
+
+        private IntegerCache() {}
     }
 
     /**
@@ -599,10 +643,9 @@
      * @since  1.5
      */
     public static Integer valueOf(int i) {
-        final int offset = 128;
-        if (i >= -128 && i <= 127) { // must cache
-            return IntegerCache.cache[i + offset];
-        }
+        assert IntegerCache.high >= 127;
+        if (i >= IntegerCache.low && i <= IntegerCache.high)
+            return IntegerCache.cache[i + (-IntegerCache.low)];
         return new Integer(i);
     }
 
@@ -806,7 +849,7 @@
      */
     public static Integer getInteger(String nm, int val) {
         Integer result = getInteger(nm, null);
-        return (result == null) ? new Integer(val) : result;
+        return (result == null) ? Integer.valueOf(val) : result;
     }
 
     /**
@@ -938,7 +981,7 @@
 
         try {
             result = Integer.valueOf(nm.substring(index), radix);
-            result = negative ? new Integer(-result.intValue()) : result;
+            result = negative ? Integer.valueOf(-result.intValue()) : result;
         } catch (NumberFormatException e) {
             // If number is Integer.MIN_VALUE, we'll end up here. The next line
             // handles this case, and causes any genuine format error to be
--- a/jdk/src/share/classes/java/lang/Long.java	Tue Mar 24 14:03:46 2009 +0000
+++ b/jdk/src/share/classes/java/lang/Long.java	Tue Mar 24 14:05:44 2009 +0000
@@ -510,7 +510,7 @@
      *             contain a parsable {@code long}.
      */
     public static Long valueOf(String s, int radix) throws NumberFormatException {
-        return new Long(parseLong(s, radix));
+        return Long.valueOf(parseLong(s, radix));
     }
 
     /**
@@ -537,7 +537,7 @@
      */
     public static Long valueOf(String s) throws NumberFormatException
     {
-        return new Long(parseLong(s, 10));
+        return Long.valueOf(parseLong(s, 10));
     }
 
     private static class LongCache {
@@ -650,7 +650,7 @@
 
         try {
             result = Long.valueOf(nm.substring(index), radix);
-            result = negative ? new Long(-result.longValue()) : result;
+            result = negative ? Long.valueOf(-result.longValue()) : result;
         } catch (NumberFormatException e) {
             // If number is Long.MIN_VALUE, we'll end up here. The next line
             // handles this case, and causes any genuine format error to be
@@ -869,7 +869,7 @@
      */
     public static Long getLong(String nm, long val) {
         Long result = Long.getLong(nm, null);
-        return (result == null) ? new Long(val) : result;
+        return (result == null) ? Long.valueOf(val) : result;
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/System.java	Tue Mar 24 14:03:46 2009 +0000
+++ b/jdk/src/share/classes/java/lang/System.java	Tue Mar 24 14:05:44 2009 +0000
@@ -1105,6 +1105,13 @@
         props = new Properties();
         initProperties(props);
         sun.misc.Version.init();
+
+        // Gets and removes system properties that configure the Integer
+        // cache used to support the object identity semantics of autoboxing.
+        // At this time, the size of the cache may be controlled by the
+        // -XX:AutoBoxCacheMax=<size> option.
+        Integer.getAndRemoveCacheProperties();
+
         FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
         FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
         FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Integer/ValueOf.java	Tue Mar 24 14:05:44 2009 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6807702
+ * @summary Basic test for Integer.valueOf
+ * @run main ValueOf
+ * @run main/othervm -esa -XX:+AggressiveOpts ValueOf
+ */
+
+public class ValueOf {
+
+    // test Integer.valueOf over this range (inclusive)
+    private static final int TEST_LOW  = -1024;
+    private static final int TEST_HIGH = 24576;
+
+    public static void main(String[] args) {
+        int i = TEST_LOW;
+        while (i <= TEST_HIGH) {
+            // check that valueOf stores i
+            if (Integer.valueOf(i).intValue() != i)
+                throw new RuntimeException();
+
+            // check that the same object is returned for integral values
+            // in the range -128 to 127 (inclusive)
+            if (i >= -128 && i <= 127) {
+                if (Integer.valueOf(i) != Integer.valueOf(i))
+                    throw new RuntimeException();
+            }
+
+            i++;
+        }
+    }
+}