1 /* 2 * Copyright (c) 2017, 2024, Oracle and/or its affiliates. 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 25 import java.lang.management.MemoryPoolMXBean; 26 27 import com.sun.jdi.NativeMethodException; 28 29 import jdk.internal.value.ValueClass; 30 import jdk.internal.vm.annotation.ImplicitlyConstructible; 31 import jdk.internal.vm.annotation.LooselyConsistentValue; 32 import jdk.internal.vm.annotation.NullRestricted; 33 import jdk.test.lib.Asserts; 34 import jdk.test.whitebox.WhiteBox; 35 36 37 /** 38 * @test InlineTypeDensity 39 * @summary Heap density test for InlineTypes 40 * @library /test/lib 41 * @modules java.base/jdk.internal.vm.annotation 42 * java.base/jdk.internal.value 43 * @enablePreview 44 * @compile InlineTypeDensity.java 45 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 46 * @run main/othervm -XX:FlatArrayElementMaxSize=-1 -XX:+UseCompressedOops 47 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions 48 * -XX:+WhiteBoxAPI InlineTypeDensity 49 * @run main/othervm -XX:FlatArrayElementMaxSize=-1 -XX:-UseCompressedOops 50 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions 51 * -XX:+WhiteBoxAPI InlineTypeDensity 52 * @run main/othervm -XX:FlatArrayElementMaxSize=-1 53 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions 54 * -XX:+WhiteBoxAPI InlineTypeDensity 55 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:FlatArrayElementMaxSize=-1 56 * -Xbootclasspath/a:. -XX:ForceNonTearable=* 57 * -XX:+WhiteBoxAPI InlineTypeDensity 58 */ 59 60 public class InlineTypeDensity { 61 62 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 63 private static final boolean VM_FLAG_FORCENONTEARABLE = WHITE_BOX.getStringVMFlag("ForceNonTearable").equals("*"); 64 65 public InlineTypeDensity() { 66 if (WHITE_BOX.getIntxVMFlag("FlatArrayElementMaxSize") != -1) { 67 throw new IllegalStateException("FlatArrayElementMaxSize should be -1"); 68 } 69 } 70 71 interface LocalDate { 72 public int getYear(); 73 public short getMonth(); 74 public short getDay(); 75 } 76 77 interface LocalTime { 78 public byte getHour(); 79 public byte getMinute(); 80 public byte getSecond(); 81 public int getNano(); 82 } 83 84 interface LocalDateTime extends LocalDate, LocalTime {} 85 86 @ImplicitlyConstructible 87 @LooselyConsistentValue 88 static value class LocalDateValue implements LocalDate { 89 final int year; 90 final short month; 91 final short day; 92 93 public LocalDateValue(int year, short month, short day) { 94 this.year = year; 95 this.month = month; 96 this.day = day; 97 } 98 99 public int getYear() { return year; } 100 public short getMonth() { return month; } 101 public short getDay() { return day; } 102 103 } 104 105 @ImplicitlyConstructible 106 @LooselyConsistentValue 107 static value class LocalTimeValue implements LocalTime { 108 final byte hour; 109 final byte minute; 110 final byte second; 111 final int nano; 112 113 public LocalTimeValue(byte hour, byte minute, byte second, int nano) { 114 this.hour = hour; 115 this.minute = minute; 116 this.second = second; 117 this.nano = nano; 118 } 119 120 public byte getHour() { return hour; } 121 public byte getMinute() { return minute; } 122 public byte getSecond() { return second; } 123 public int getNano() { return nano; } 124 125 } 126 127 @ImplicitlyConstructible 128 @LooselyConsistentValue 129 static value class LocalDateTimeValue implements LocalDateTime { 130 @NullRestricted 131 LocalDateValue date; 132 @NullRestricted 133 LocalTimeValue time; 134 135 public LocalDateTimeValue(LocalDateValue date, LocalTimeValue time) { 136 this.date = date; 137 this.time = time; 138 } 139 140 public int getYear() { return date.year; } 141 public short getMonth() { return date.month; } 142 public short getDay() { return date.day; } 143 144 public byte getHour() { return time.hour; } 145 public byte getMinute() { return time.minute; } 146 public byte getSecond() { return time.second; } 147 public int getNano() { return time.nano; } 148 149 } 150 151 static final class LocalDateClass implements LocalDate { 152 final int year; 153 final short month; 154 final short day; 155 156 LocalDateClass(int year, short month, short day) { 157 this.year = year; 158 this.month = month; 159 this.day = day; 160 } 161 162 public int getYear() { return year; } 163 public short getMonth() { return month; } 164 public short getDay() { return day; } 165 } 166 167 static final class LocalTimeClass implements LocalTime { 168 final byte hour; 169 final byte minute; 170 final byte second; 171 final int nano; 172 173 LocalTimeClass(byte hour, byte minute, byte second, int nano) { 174 this.hour = hour; 175 this.minute = minute; 176 this.second = second; 177 this.nano = nano; 178 } 179 180 public byte getHour() { return hour; } 181 public byte getMinute() { return minute; } 182 public byte getSecond() { return second; } 183 public int getNano() { return nano; } 184 } 185 186 static final class LocalDateTimeClass implements LocalDateTime { 187 final LocalDateClass date; 188 final LocalTimeClass time; 189 190 LocalDateTimeClass(LocalDateClass date, LocalTimeClass time) { 191 this.date = date; 192 this.time = time; 193 } 194 195 public LocalDateClass getDate() { return date; } 196 public LocalTimeClass getTime() { return time; } 197 198 public int getYear() { return date.year; } 199 public short getMonth() { return date.month; } 200 public short getDay() { return date.day; } 201 202 public byte getHour() { return time.hour; } 203 public byte getMinute() { return time.minute; } 204 public byte getSecond() { return time.second; } 205 public int getNano() { return time.nano; } 206 } 207 208 public void ensureArraySizeWin() { 209 int arrayLength = 1000; 210 System.out.println("ensureArraySizeWin for length " + arrayLength); 211 LocalDateTimeClass[] objectArray = new LocalDateTimeClass[arrayLength]; 212 for (int i = 0; i < arrayLength; i++) { 213 objectArray[i] = new LocalDateTimeClass(new LocalDateClass(0, (short)0, (short)0), 214 new LocalTimeClass((byte)0, (byte)0, (byte)0, 0)); 215 } 216 217 long objectArraySize = WHITE_BOX.getObjectSize(objectArray); 218 System.out.println("Empty object array size: " + objectArraySize); 219 objectArraySize += (arrayLength * 220 (WHITE_BOX.getObjectSize(objectArray[0]) + 221 WHITE_BOX.getObjectSize(objectArray[0].getDate()) + 222 WHITE_BOX.getObjectSize(objectArray[0].getTime()))); 223 224 LocalDateTimeValue[] flatArray = new LocalDateTimeValue[arrayLength]; 225 // CMH: add "isFlatValueArray" to WhiteBox API, to ensure we are correctly account size 226 227 long flatArraySize = WHITE_BOX.getObjectSize(flatArray); 228 System.out.println("Object array and elements: " + objectArraySize + " versus Flat Array: " + flatArraySize); 229 Asserts.assertLessThan(flatArraySize, objectArraySize, "Flat array accounts for more heap than object array + elements !"); 230 } 231 232 @ImplicitlyConstructible 233 @LooselyConsistentValue 234 static value class MyByte { byte v = 0; } 235 @ImplicitlyConstructible 236 @LooselyConsistentValue 237 static value class MyShort { short v = 0; } 238 @ImplicitlyConstructible 239 @LooselyConsistentValue 240 static value class MyInt { int v = 0; } 241 @ImplicitlyConstructible 242 @LooselyConsistentValue 243 static value class MyLong { long v = 0; } 244 245 void assertArraySameSize(Object a, Object b, int nofElements) { 246 long aSize = WHITE_BOX.getObjectSize(a); 247 long bSize = WHITE_BOX.getObjectSize(b); 248 Asserts.assertEquals(aSize, bSize, 249 a + "(" + aSize + " bytes) not equivalent size " + 250 b + "(" + bSize + " bytes)" + 251 (nofElements >= 0 ? " (array of " + nofElements + " elements)" : "")); 252 } 253 254 void testByteArraySizesSame(int[] testSizes) { 255 for (int testSize : testSizes) { 256 byte[] ba = new byte[testSize]; 257 MyByte[] mba = (MyByte[])ValueClass.newNullRestrictedArray(MyByte.class, testSize); 258 assertArraySameSize(ba, mba, testSize); 259 } 260 } 261 262 void testShortArraySizesSame(int[] testSizes) { 263 for (int testSize : testSizes) { 264 short[] sa = new short[testSize]; 265 MyShort[] msa = (MyShort[])ValueClass.newNullRestrictedArray(MyShort.class, testSize); 266 assertArraySameSize(sa, msa, testSize); 267 } 268 } 269 270 void testIntArraySizesSame(int[] testSizes) { 271 for (int testSize : testSizes) { 272 int[] ia = new int[testSize]; 273 MyInt[] mia = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, testSize); 274 assertArraySameSize(ia, mia, testSize); 275 } 276 } 277 278 void testLongArraySizesSame(int[] testSizes) { 279 for (int testSize : testSizes) { 280 long[] la = new long[testSize]; 281 MyLong[] mla = (MyLong[])ValueClass.newNullRestrictedArray(MyLong.class, testSize); 282 assertArraySameSize(la, mla, testSize); 283 } 284 } 285 286 public void testPrimitiveArraySizesSame() { 287 int[] testSizes = new int[] { 0, 1, 2, 3, 4, 7, 10, 257 }; 288 testByteArraySizesSame(testSizes); 289 testShortArraySizesSame(testSizes); 290 testIntArraySizesSame(testSizes); 291 testLongArraySizesSame(testSizes); 292 } 293 294 @ImplicitlyConstructible 295 @LooselyConsistentValue 296 static value class bbValue { byte b = 0; byte b2 = 0;} 297 @ImplicitlyConstructible 298 @LooselyConsistentValue 299 static value class bsValue { byte b = 0; short s = 0;} 300 @ImplicitlyConstructible 301 @LooselyConsistentValue 302 static value class siValue { short s = 0; int i = 0;} 303 @ImplicitlyConstructible 304 @LooselyConsistentValue 305 static value class ssiValue { short s = 0; short s2 = 0; int i = 0;} 306 @ImplicitlyConstructible 307 @LooselyConsistentValue 308 static value class blValue { byte b = 0; long l = 0; } 309 310 // Expect aligned array addressing to nearest pow2 311 void testAlignedSize() { 312 int testSize = 10; 313 assertArraySameSize(new short[testSize], ValueClass.newNullRestrictedArray(bbValue.class, testSize), testSize); 314 assertArraySameSize(new long[testSize], ValueClass.newNullRestrictedArray(siValue.class, testSize), testSize); 315 assertArraySameSize(new long[testSize], ValueClass.newNullRestrictedArray(ssiValue.class, testSize), testSize); 316 assertArraySameSize(new long[testSize*2], ValueClass.newNullRestrictedArray(blValue.class, testSize), testSize); 317 assertArraySameSize(new int[testSize], ValueClass.newNullRestrictedArray(bsValue.class, testSize), testSize); 318 } 319 320 public void test() { 321 ensureArraySizeWin(); 322 testPrimitiveArraySizesSame(); 323 if (!VM_FLAG_FORCENONTEARABLE) { 324 testAlignedSize(); 325 } 326 } 327 328 public static void main(String[] args) { 329 new InlineTypeDensity().test(); 330 } 331 332 }