1 /* 2 * Copyright (c) 2018, Red Hat, Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package test.java.util.HashMap; 25 26 import org.testng.annotations.Test; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodHandles; 30 import java.lang.invoke.MethodType; 31 import java.lang.invoke.VarHandle; 32 import java.util.HashMap; 33 import java.util.LinkedHashMap; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.concurrent.ThreadLocalRandom; 37 import java.util.function.Supplier; 38 import java.util.stream.IntStream; 39 40 import static java.util.stream.Collectors.toMap; 41 import static org.testng.Assert.assertEquals; 42 import static org.testng.Assert.assertNull; 43 44 /* 45 * @test 46 * @bug 8210280 47 * @modules java.base/java.util:open 48 * @summary White box tests for HashMap internals around table resize 49 * @run testng WhiteBoxResizeTest 50 * @key randomness 51 */ 52 public class WhiteBoxResizeTest { 53 final ThreadLocalRandom rnd = ThreadLocalRandom.current(); 54 final MethodHandle TABLE_SIZE_FOR; 55 final VarHandle THRESHOLD; 56 final VarHandle TABLE; 57 WhiteBoxResizeTest()58 public WhiteBoxResizeTest() throws ReflectiveOperationException { 59 Class<?> mClass = HashMap.class; 60 String nodeClassName = mClass.getName() + "$Node"; 61 Class<?> nodeArrayClass = Class.forName("[L" + nodeClassName + ";"); 62 MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(mClass, MethodHandles.lookup()); 63 TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass); 64 this.TABLE_SIZE_FOR = lookup.findStatic( 65 mClass, "tableSizeFor", 66 MethodType.methodType(int.class, int.class)); 67 this.THRESHOLD = lookup.findVarHandle(mClass, "threshold", int.class); 68 } 69 tableSizeFor(int n)70 int tableSizeFor(int n) { 71 try { 72 return (int) TABLE_SIZE_FOR.invoke(n); 73 } catch (Throwable t) { throw new AssertionError(t); } 74 } 75 table(HashMap map)76 Object[] table(HashMap map) { 77 try { 78 return (Object[]) TABLE.get(map); 79 } catch (Throwable t) { throw new AssertionError(t); } 80 } 81 capacity(HashMap map)82 int capacity(HashMap map) { 83 return table(map).length; 84 } 85 86 @Test testTableSizeFor()87 public void testTableSizeFor() { 88 assertEquals(tableSizeFor(0), 1); 89 assertEquals(tableSizeFor(1), 1); 90 assertEquals(tableSizeFor(2), 2); 91 assertEquals(tableSizeFor(3), 4); 92 assertEquals(tableSizeFor(15), 16); 93 assertEquals(tableSizeFor(16), 16); 94 assertEquals(tableSizeFor(17), 32); 95 int maxSize = 1 << 30; 96 assertEquals(tableSizeFor(maxSize - 1), maxSize); 97 assertEquals(tableSizeFor(maxSize), maxSize); 98 assertEquals(tableSizeFor(maxSize + 1), maxSize); 99 assertEquals(tableSizeFor(Integer.MAX_VALUE), maxSize); 100 } 101 102 @Test capacityTestDefaultConstructor()103 public void capacityTestDefaultConstructor() { 104 capacityTestDefaultConstructor(new HashMap<>()); 105 capacityTestDefaultConstructor(new LinkedHashMap<>()); 106 } 107 capacityTestDefaultConstructor(HashMap<Integer, Integer> map)108 void capacityTestDefaultConstructor(HashMap<Integer, Integer> map) { 109 assertNull(table(map)); 110 111 map.put(1, 1); 112 assertEquals(capacity(map), 16); // default initial capacity 113 114 map.putAll(IntStream.range(0, 64).boxed().collect(toMap(i -> i, i -> i))); 115 assertEquals(capacity(map), 128); 116 } 117 118 @Test capacityTestInitialCapacity()119 public void capacityTestInitialCapacity() { 120 int initialCapacity = rnd.nextInt(2, 128); 121 List<Supplier<HashMap<Integer, Integer>>> suppliers = List.of( 122 () -> new HashMap<>(initialCapacity), 123 () -> new HashMap<>(initialCapacity, 0.75f), 124 () -> new LinkedHashMap<>(initialCapacity), 125 () -> new LinkedHashMap<>(initialCapacity, 0.75f)); 126 127 for (Supplier<HashMap<Integer, Integer>> supplier : suppliers) { 128 HashMap<Integer, Integer> map = supplier.get(); 129 assertNull(table(map)); 130 131 map.put(1, 1); 132 assertEquals(capacity(map), tableSizeFor(initialCapacity)); 133 } 134 } 135 } 136