1 /* 2 * Copyright (c) 2024, 2025, 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 * @test id=NullMarker32 26 * @ignore 27 * @requires vm.bits == 32 28 * @library /test/lib 29 * @modules java.base/jdk.internal.vm.annotation 30 * @enablePreview 31 * @compile FieldLayoutAnalyzer.java NullMarkersTest.java 32 * @run main/othervm NullMarkersTest 0 33 */ 34 35 /* 36 * @test id=NullMarker64CompressedOops 37 * @ignore 38 * @requires vm.bits == 64 39 * @library /test/lib 40 * @modules java.base/jdk.internal.vm.annotation 41 * @enablePreview 42 * @compile FieldLayoutAnalyzer.java NullMarkersTest.java 43 * @run main/othervm NullMarkersTest 1 44 */ 45 46 /* 47 * @test id=NullMarker64NoCompressedOops 48 * @ignore 49 * @requires vm.bits == 64 50 * @library /test/lib 51 * @modules java.base/jdk.internal.vm.annotation 52 * @enablePreview 53 * @compile FieldLayoutAnalyzer.java NullMarkersTest.java 54 * @run main/othervm NullMarkersTest 2 55 */ 56 57 /* 58 * @test id=NullMarker64NoCompressedOopsNoCompressedKlassPointers 59 * @ignore 60 * @requires vm.bits == 64 61 * @library /test/lib 62 * @modules java.base/jdk.internal.vm.annotation 63 * @enablePreview 64 * @compile FieldLayoutAnalyzer.java NullMarkersTest.java 65 * @run main/othervm NullMarkersTest 3 66 */ 67 68 import java.util.ArrayList; 69 import java.util.Collections; 70 import java.util.List; 71 72 import jdk.internal.vm.annotation.NullRestricted; 73 import jdk.internal.vm.annotation.Strict; 74 75 import java.lang.reflect.Method; 76 import java.lang.reflect.Modifier; 77 import jdk.test.lib.Asserts; 78 import jdk.test.lib.process.OutputAnalyzer; 79 import jdk.test.lib.process.ProcessTools; 80 81 public class NullMarkersTest { 82 83 84 static class TestRunner { 85 public static void main(String[] args) throws Exception { 86 Class testClass = Class.forName("NullMarkersTest"); 87 Asserts.assertNotNull(testClass); 88 Method[] testMethods = testClass.getMethods(); 89 for (Method test : testMethods) { 90 if (test.getName().startsWith("test_")) { 91 Asserts.assertTrue(Modifier.isStatic(test.getModifiers())); 92 Asserts.assertTrue(test.getReturnType().equals(Void.TYPE)); 93 System.out.println("Running " + test.getName()); 94 test.invoke(null); 95 } 96 } 97 } 98 } 99 100 static value class Value0 { 101 int i = 0; 102 } 103 104 static class Container0 { 105 Value0 val; 106 } 107 108 // Simple test with a single nullable flattenable field 109 static public void test_0() { 110 Container0 c = new Container0(); 111 } 112 113 static public void check_0(FieldLayoutAnalyzer fla) { 114 FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("NullMarkersTest$Container0"); 115 FieldLayoutAnalyzer.FieldBlock f = cl.getFieldFromName("val", false); 116 Asserts.assertTrue(f.isFlat()); 117 Asserts.assertTrue(f.hasNullMarker()); 118 } 119 120 static value class Value1 { 121 short s = 0; 122 } 123 124 static class Container1 { 125 Value1 val0; 126 Value1 val1; 127 @Strict 128 @NullRestricted 129 Value1 val2 = new Value1(); 130 } 131 132 static public void test_1() { 133 Container1 c = new Container1(); 134 } 135 136 static public void check_1(FieldLayoutAnalyzer fla) { 137 FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("NullMarkersTest$Container1"); 138 FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); 139 Asserts.assertTrue(f0.isFlat()); 140 Asserts.assertTrue(f0.hasNullMarker()); 141 FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); 142 Asserts.assertTrue(f1.isFlat()); 143 Asserts.assertTrue(f1.hasNullMarker()); 144 FieldLayoutAnalyzer.FieldBlock f2 = cl.getFieldFromName("val2", false); 145 Asserts.assertTrue(f2.isFlat()); 146 Asserts.assertFalse(f2.hasNullMarker()); 147 } 148 149 static value class Value2 { 150 long l = 0; 151 } 152 153 static class Container2a { 154 Value2 vala; 155 } 156 157 static class Container2b extends Container2a { 158 Value2 valb; 159 } 160 161 static public void test_2() { 162 Container2b c = new Container2b(); 163 } 164 165 static public void check_2(FieldLayoutAnalyzer fla) { 166 FieldLayoutAnalyzer.ClassLayout cla = fla.getClassLayoutFromName("NullMarkersTest$Container2a"); 167 FieldLayoutAnalyzer.FieldBlock fa = cla.getFieldFromName("vala", false); 168 Asserts.assertTrue(fa.isFlat()); 169 Asserts.assertTrue(fa.hasNullMarker()); 170 FieldLayoutAnalyzer.ClassLayout clb = fla.getClassLayoutFromName("NullMarkersTest$Container2b"); 171 FieldLayoutAnalyzer.FieldBlock fb = clb.getFieldFromName("valb", false); 172 Asserts.assertTrue(fb.isFlat()); 173 Asserts.assertTrue(fb.hasNullMarker()); 174 } 175 176 static value class Value3 { 177 double d = 0.0d; 178 } 179 180 static class Container3a { 181 @Strict 182 @NullRestricted 183 Value3 val0 = new Value3(); 184 Value3 val1; 185 } 186 187 static class Container3b extends Container3a { 188 Value3 val2; 189 @Strict 190 @NullRestricted 191 Value3 val3 = new Value3(); 192 } 193 194 static class Container3c extends Container3b { 195 Value3 val4; 196 Value3 val5; 197 } 198 199 static public void test_3() { 200 Container3c c = new Container3c(); 201 } 202 203 static public void check_3(FieldLayoutAnalyzer fla) { 204 FieldLayoutAnalyzer.ClassLayout cla = fla.getClassLayoutFromName("NullMarkersTest$Container3a"); 205 FieldLayoutAnalyzer.FieldBlock f0 = cla.getFieldFromName("val0", false); 206 Asserts.assertTrue(f0.isFlat()); 207 Asserts.assertFalse(f0.hasNullMarker()); 208 FieldLayoutAnalyzer.FieldBlock f1 = cla.getFieldFromName("val1", false); 209 Asserts.assertTrue(f1.isFlat()); 210 Asserts.assertTrue(f1.hasNullMarker()); 211 FieldLayoutAnalyzer.ClassLayout clb = fla.getClassLayoutFromName("NullMarkersTest$Container3b"); 212 FieldLayoutAnalyzer.FieldBlock f2 = clb.getFieldFromName("val2", false); 213 Asserts.assertTrue(f2.isFlat()); 214 Asserts.assertTrue(f2.hasNullMarker()); 215 FieldLayoutAnalyzer.FieldBlock f3 = clb.getFieldFromName("val3", false); 216 Asserts.assertTrue(f3.isFlat()); 217 Asserts.assertFalse(f3.hasNullMarker()); 218 FieldLayoutAnalyzer.ClassLayout clc = fla.getClassLayoutFromName("NullMarkersTest$Container3c"); 219 FieldLayoutAnalyzer.FieldBlock f4 = clc.getFieldFromName("val4", false); 220 Asserts.assertTrue(f4.isFlat()); 221 Asserts.assertTrue(f4.hasNullMarker()); 222 FieldLayoutAnalyzer.FieldBlock f5 = clc.getFieldFromName("val5", false); 223 Asserts.assertTrue(f5.isFlat()); 224 Asserts.assertTrue(f5.hasNullMarker()); 225 } 226 227 @LooselyConsistentValue 228 static value class Value4 { 229 int i = 0; 230 byte b = 0; 231 } 232 233 static class Container4 { 234 Value4 val0; 235 Value4 val1; 236 } 237 238 static public void test_4() { 239 Container4 c = new Container4(); 240 } 241 242 static void check_4(FieldLayoutAnalyzer fla) { 243 FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("NullMarkersTest$Container4"); 244 FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); 245 Asserts.assertTrue(f0.isFlat()); 246 Asserts.assertTrue(f0.hasNullMarker()); 247 FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); 248 Asserts.assertTrue(f1.isFlat()); 249 Asserts.assertTrue(f1.hasNullMarker()); 250 } 251 252 @LooselyConsistentValue 253 static value class Value5a { 254 short s = 0; 255 byte b = 0; 256 } 257 258 @LooselyConsistentValue 259 static value class Value5b { 260 @Strict 261 @NullRestricted 262 Value5a val0 = new Value5a(); 263 @Strict 264 @NullRestricted 265 Value5a val1 = new Value5a(); 266 } 267 268 static class Container5 { 269 Value5a vala; 270 Value5b valb0; 271 Value5b valb1; 272 } 273 274 static public void test_5() { 275 Container5 c = new Container5(); 276 } 277 278 static void check_5(FieldLayoutAnalyzer fla) { 279 FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("NullMarkersTest$Container5"); 280 FieldLayoutAnalyzer.FieldBlock fa = cl.getFieldFromName("vala", false); 281 Asserts.assertTrue(fa.isFlat()); 282 Asserts.assertTrue(fa.hasNullMarker()); 283 FieldLayoutAnalyzer.FieldBlock fb0 = cl.getFieldFromName("valb0", false); 284 Asserts.assertTrue(fb0.isFlat()); 285 Asserts.assertTrue(fb0.hasNullMarker()); 286 FieldLayoutAnalyzer.FieldBlock fb1 = cl.getFieldFromName("valb1", false); 287 Asserts.assertTrue(fb1.isFlat()); 288 Asserts.assertTrue(fb1.hasNullMarker()); 289 } 290 291 static ProcessBuilder exec(String compressedOopsArg, String compressedKlassPointersArg, String... args) throws Exception { 292 List<String> argsList = new ArrayList<>(); 293 Collections.addAll(argsList, "--enable-preview"); 294 Collections.addAll(argsList, "-XX:+UnlockDiagnosticVMOptions"); 295 Collections.addAll(argsList, "-XX:+PrintFieldLayout"); 296 Collections.addAll(argsList, "-Xshare:off"); 297 if (compressedOopsArg != null) { 298 Collections.addAll(argsList, compressedOopsArg); 299 } 300 if (compressedKlassPointersArg != null) { 301 Collections.addAll(argsList, compressedKlassPointersArg); 302 } 303 Collections.addAll(argsList, "-Xmx256m"); 304 Collections.addAll(argsList, "-XX:+UseNullableValueFlattening"); 305 Collections.addAll(argsList, "-cp", System.getProperty("java.class.path") + System.getProperty("path.separator") + "."); 306 Collections.addAll(argsList, args); 307 return ProcessTools.createTestJavaProcessBuilder(argsList); 308 } 309 310 public static void main(String[] args) throws Exception { 311 String compressedOopsArg; 312 String compressedKlassPointersArg; 313 314 switch(args[0]) { 315 case "0": compressedOopsArg = null; 316 compressedKlassPointersArg = null; 317 break; 318 case "1": compressedOopsArg = "-XX:+UseCompressedOops"; 319 compressedKlassPointersArg = "-XX:+UseCompressedClassPointers"; 320 break; 321 case "2": compressedOopsArg = "-XX:-UseCompressedOops"; 322 compressedKlassPointersArg = "-XX:+UseCompressedClassPointers"; 323 break; 324 case "3": compressedOopsArg = "-XX:-UseCompressedOops"; 325 compressedKlassPointersArg = "-XX:-UseCompressedClassPointers"; 326 break; 327 default: throw new RuntimeException("Unrecognized configuration"); 328 } 329 330 // Generate test classes 331 NullMarkersTest fat = new NullMarkersTest(); 332 333 // Execute the test runner in charge of loading all test classes 334 ProcessBuilder pb = exec(compressedOopsArg, compressedKlassPointersArg, "NullMarkersTest$TestRunner"); 335 OutputAnalyzer out = new OutputAnalyzer(pb.start()); 336 337 if (out.getExitValue() != 0) { 338 System.out.print(out.getOutput()); 339 } 340 Asserts.assertEquals(out.getExitValue(), 0, "Something went wrong while running the tests"); 341 342 // Get and parse the test output 343 FieldLayoutAnalyzer.LogOutput lo = new FieldLayoutAnalyzer.LogOutput(out.asLines()); 344 FieldLayoutAnalyzer fla = FieldLayoutAnalyzer.createFieldLayoutAnalyzer(lo); 345 346 // Running tests verification method (check that tests produced the right configuration) 347 Class testClass = NullMarkersTest.class; 348 Method[] testMethods = testClass.getMethods(); 349 for (Method test : testMethods) { 350 if (test.getName().startsWith("check_")) { 351 Asserts.assertTrue(Modifier.isStatic(test.getModifiers())); 352 Asserts.assertTrue(test.getReturnType().equals(Void.TYPE)); 353 test.invoke(null, fla); 354 } 355 } 356 357 // Verify that all layouts are correct 358 fla.check(); 359 } 360 }