8081027: Create a common test to check adequacy of initial size of static HashMap/ArrayList fields
Reviewed-by: martin
--- a/jdk/src/java.base/share/classes/java/lang/Character.java Fri May 29 09:08:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/Character.java Fri May 29 19:20:22 2015 +0300
@@ -646,13 +646,11 @@
*/
public static final class UnicodeBlock extends Subset {
/**
- * 510 - the expected number of enteties
+ * 510 - the expected number of entities
* 0.75 - the default load factor of HashMap
*/
- private static final int INITIAL_CAPACITY =
- (int)(510 / 0.75f + 1.0f);
private static Map<String, UnicodeBlock> map =
- new HashMap<>(INITIAL_CAPACITY);
+ new HashMap<>((int)(510 / 0.75f + 1.0f));
/**
* Creates a UnicodeBlock with the given identifier name.
--- a/jdk/src/java.base/share/classes/sun/invoke/anon/ConstantPoolPatch.java Fri May 29 09:08:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/invoke/anon/ConstantPoolPatch.java Fri May 29 19:20:22 2015 +0300
@@ -417,7 +417,7 @@
| CONSTANT_InterfaceMethodref;
private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
- = new IdentityHashMap<Class<?>, Byte>();
+ = new IdentityHashMap<Class<?>, Byte>(6);
private static final Class<?>[] CONSTANT_VALUE_CLASS = new Class<?>[16];
static {
Object[][] values = {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java Fri May 29 09:08:36 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java Fri May 29 19:20:22 2015 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, 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
@@ -43,7 +43,8 @@
return name;
}
- static List<ExtensionType> knownExtensions = new ArrayList<ExtensionType>(9);
+ static List<ExtensionType> knownExtensions =
+ new ArrayList<ExtensionType>(13);
static ExtensionType get(int id) {
for (ExtensionType ext : knownExtensions) {
--- a/jdk/test/java/lang/Character/UnicodeBlock/NonOptimalMapSize.java Fri May 29 09:08:36 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2015, 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 8080535
- * @summary Expected size of Character.UnicodeBlock.map is not optimal
- */
-
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-
-public class NonOptimalMapSize {
- public static void main(String[] args) throws Throwable {
- Class<?> ubCls = Character.UnicodeBlock.class;
- Field mapField = ubCls.getDeclaredField("map");
- mapField.setAccessible(true);
- Map<?,?> map = (Map<?,?>)mapField.get(null);
- if (!map.getClass().equals(HashMap.class)) {
- throw new RuntimeException(
- "Character.UnicodeBlock.map is expected to be HashMap");
- }
- int mapSize = map.size();
-
- Field sizeField = ubCls.getDeclaredField("INITIAL_CAPACITY");
- sizeField.setAccessible(true);
- int INITIAL_CAPACITY = sizeField.getInt(null);
-
- // Construct a HashMap with specified initial capacity
- HashMap<Object,Object> map1 = new HashMap<>(INITIAL_CAPACITY);
- Class<?> hmCls = HashMap.class;
- Field tableField = hmCls.getDeclaredField("table");
- tableField.setAccessible(true);
- // ... and fill it up
- map1.put(new Object(), new Object());
- final Object initialTable = tableField.get(map1);
- while (map1.size() < map.size() &&
- initialTable == tableField.get(map1)) {
- map1.put(new Object(), new Object());
- }
-
- // Now check that internal storage didn't change
- if (initialTable != tableField.get(map1)) {
- throw new RuntimeException(
- "Initial capacity " + INITIAL_CAPACITY +
- " was only enough to hold " + (map1.size()-1) +
- " entries, but needed " + map.size());
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java Fri May 29 19:20:22 2015 +0300
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 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 8080535
+ * @summary Expected size of Character.UnicodeBlock.map is not optimal
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalMapSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+// What will be the number of the Unicode blocks in the future.
+//
+// According to http://www.unicode.org/versions/Unicode7.0.0/ ,
+// in Unicode 7 there will be added 32 new blocks (96 with aliases).
+// According to http://www.unicode.org/versions/beta-8.0.0.html ,
+// in Unicode 8 there will be added 10 more blocks (30 with aliases).
+//
+// After implementing support of Unicode 7 and 8 in Java, there will
+// be 510+96+30 = 636 entries in Character.UnicodeBlock.map.
+//
+// Initialization of the map and this test will have to be adjusted
+// accordingly then.
+
+public class OptimalMapSize {
+ public static void main(String[] args) throws Throwable {
+ // The initial size of Character.UnicodeBlock.map.
+ // See src/java.base/share/classes/java/lang/Character.java
+ int initialCapacity = (int)(510 / 0.75f + 1.0f);
+
+ OptimalCapacity.ofHashMap(Character.UnicodeBlock.class,
+ "map", initialCapacity);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OptimalCapacity.java Fri May 29 19:20:22 2015 +0300
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package jdk.testlibrary;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+
+/**
+ * Utility functions to check that the static storages are pre-sized
+ * optimally.
+ */
+public final class OptimalCapacity {
+
+ private OptimalCapacity() {}
+
+ /**
+ * Checks adequacy of the initial capacity of a static field
+ * of type {@code ArrayList}.
+ *
+ * Having
+ * <pre>
+ * class XClass {
+ * static ArrayList theList = new ArrayList(N);
+ * }
+ * </pre>
+ *
+ * you should call from the test
+ *
+ * <pre>
+ * OptimalCapacity.assertProperlySized(XClass.class, "theList", N);
+ * </pre>
+ */
+ public static void ofArrayList(Class<?> clazz, String fieldName,
+ int initialCapacity)
+ {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Object obj = field.get(null);
+ if (!ArrayList.class.equals(obj.getClass())) {
+ throw new RuntimeException("'" + field +
+ "' expected to be of type ArrayList");
+ }
+ ArrayList<?> list = (ArrayList<?>)obj;
+
+ // For ArrayList the optimal capacity is its final size
+ if (list.size() != initialCapacity) {
+ throw new RuntimeException("Size of '" + field +
+ "' is " + list.size() +
+ ", but expected to be " + initialCapacity);
+ }
+ if (internalArraySize(list) != initialCapacity) {
+ throw new RuntimeException("Capacity of '" + field +
+ "' is " + internalArraySize(list) +
+ ", but expected to be " + initialCapacity);
+ }
+ } catch (ReflectiveOperationException roe) {
+ throw new RuntimeException(roe);
+ }
+ }
+
+ /**
+ * Checks adequacy of the initial capacity of a static field
+ * of type {@code HashMap}.
+ *
+ * Having
+ * <pre>
+ * class XClass {
+ * static HashMap theMap = new HashMap(N);
+ * }
+ * </pre>
+ *
+ * you should call from the test
+ *
+ * <pre>
+ * OptimalCapacity.ofHashMap(XClass.class, "theMap", N);
+ * </pre>
+ */
+ public static void ofHashMap(Class<?> clazz, String fieldName,
+ int initialCapacity)
+ {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Object obj = field.get(null);
+ if (!HashMap.class.equals(obj.getClass())) {
+ throw new RuntimeException(field +
+ " expected to be of type HashMap");
+ }
+ HashMap<?,?> map = (HashMap<?,?>)obj;
+
+ // Check that the map allocates only necessary amount of space
+ HashMap<Object, Object> tmp = new HashMap<>(map);
+ if (internalArraySize(map) != internalArraySize(tmp)) {
+ throw new RuntimeException("Final capacity of '" + field +
+ "' is " + internalArraySize(map) +
+ ", which exceeds necessary minimum " + internalArraySize(tmp));
+ }
+
+ // Check that map is initially properly sized
+ tmp = new HashMap<>(initialCapacity);
+ tmp.put(new Object(), new Object()); // trigger storage init
+ if (internalArraySize(map) != internalArraySize(tmp)) {
+ throw new RuntimeException("Requested capacity of '" + field +
+ "' was " + initialCapacity +
+ ", which resulted in final capacity " + internalArraySize(tmp) +
+ ", which differs from necessary minimum " + internalArraySize(map));
+ }
+
+ } catch (ReflectiveOperationException roe) {
+ throw new RuntimeException(roe);
+ }
+ }
+
+ /**
+ * Checks adequacy of the expected maximum size of a static field
+ * of type {@code IdentityHashMap}.
+ *
+ * Having
+ * <pre>
+ * class XClass {
+ * static IdentityHashMap theMap = new IdentityHashMap(M);
+ * }
+ * </pre>
+ *
+ * you should call from the test
+ *
+ * <pre>
+ * OptimalCapacity.ofIdentityHashMap(XClass.class, "theMap", M);
+ * </pre>
+ */
+ public static void ofIdentityHashMap(Class<?> clazz, String fieldName,
+ int expectedMaxSize)
+ {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Object obj = field.get(null);
+ if (!IdentityHashMap.class.equals(obj.getClass())) {
+ throw new RuntimeException("'" + field +
+ "' expected to be of type IdentityHashMap");
+ }
+ IdentityHashMap<?,?> map = (IdentityHashMap<?,?>)obj;
+
+ // Check that size of map is what was expected
+ if (map.size() != expectedMaxSize) {
+ throw new RuntimeException("Size of '" + field +
+ "' is " + map.size() +
+ ", which differs from expected " + expectedMaxSize);
+ }
+
+ // Check that the map allocated only necessary amount of memory
+ IdentityHashMap<Object, Object> tmp = new IdentityHashMap<>(map);
+ if (internalArraySize(map) != internalArraySize(tmp)) {
+ throw new RuntimeException("Final capacity of '" + field +
+ "' is " + internalArraySize(map) +
+ ", which exceeds necessary minimum " + internalArraySize(tmp));
+ }
+
+ // Check that map was initially properly sized
+ tmp = new IdentityHashMap<>(expectedMaxSize);
+ tmp.put(new Object(), new Object()); // trigger storage init
+ if (internalArraySize(map) != internalArraySize(tmp)) {
+ throw new RuntimeException("Requested number of elements in '" + field +
+ "' was " + expectedMaxSize +
+ ", which resulted in final capacity " + internalArraySize(tmp) +
+ ", which differs from necessary minimum " + internalArraySize(map));
+ }
+ } catch (ReflectiveOperationException roe) {
+ throw new RuntimeException(roe);
+ }
+ }
+
+ /**
+ * Returns size of the internal storage.
+ */
+ private static int internalArraySize(Object container)
+ throws ReflectiveOperationException {
+ Field field;
+ if (ArrayList.class.equals(container.getClass())) {
+ field = ArrayList.class.getDeclaredField("elementData");
+ } else if (HashMap.class.equals(container.getClass())) {
+ field = HashMap.class.getDeclaredField("table");
+ } else if (IdentityHashMap.class.equals(container.getClass())) {
+ field = IdentityHashMap.class.getDeclaredField("table");
+ } else {
+ throw new RuntimeException("Unexpected class " +
+ container.getClass());
+ }
+ field.setAccessible(true);
+ return ((Object[])field.get(container)).length;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/invoke/anon/ConstantPoolPatch/OptimalMapSize.java Fri May 29 19:20:22 2015 +0300
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 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 8080535
+ * @summary Static storages should be initialized with optimal capacity
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalMapSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+public class OptimalMapSize {
+ public static void main(String[] args) throws Throwable {
+ OptimalCapacity.ofIdentityHashMap(
+ Class.forName("sun.invoke.anon.ConstantPoolPatch"),
+ "CONSTANT_VALUE_CLASS_TAG", 6);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java Fri May 29 19:20:22 2015 +0300
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, 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 8080535
+ * @summary Expected size of Character.UnicodeBlock.map is not optimal
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalListSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+public class OptimalListSize {
+ public static void main(String[] args) throws Throwable {
+ OptimalCapacity.ofArrayList(
+ Class.forName("sun.security.ssl.ExtensionType"),
+ "knownExtensions", 13);
+ }
+}