1 /* 2 * Copyright (c) 2018, 2019, 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 package runtime.valhalla.valuetypes; 25 26 import java.lang.invoke.*; 27 import java.lang.ref.*; 28 import java.util.concurrent.*; 29 30 import static jdk.test.lib.Asserts.*; 31 import jdk.test.lib.Utils; 32 import sun.hotspot.WhiteBox; 33 34 import jdk.experimental.value.MethodHandleBuilder; 35 36 /** 37 * @test ValueOops_int_Serial 38 * @requires vm.gc.Serial 39 * @summary Test embedding oops into Value types 40 * @modules java.base/jdk.experimental.bytecode 41 * java.base/jdk.experimental.value 42 * @library /test/lib 43 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 44 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 45 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 46 * sun.hotspot.WhiteBox$WhiteBoxPermission 47 * @run main/othervm -Xint -XX:+UseSerialGC -Xmx128m 48 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 49 * runtime.valhalla.valuetypes.ValueOops 50 */ 51 52 /** 53 * @test ValueOops_int_G1 54 * @requires vm.gc.G1 55 * @summary Test embedding oops into Value types 56 * @modules java.base/jdk.experimental.bytecode 57 * java.base/jdk.experimental.value 58 * @library /test/lib 59 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 60 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 61 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 62 * sun.hotspot.WhiteBox$WhiteBoxPermission 63 * @run main/othervm -Xint -XX:+UseG1GC -Xmx128m 64 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 65 * runtime.valhalla.valuetypes.ValueOops 100 66 */ 67 68 /** 69 * @test ValueOops_int_Parallel 70 * @requires vm.gc.Parallel 71 * @summary Test embedding oops into Value types 72 * @modules java.base/jdk.experimental.bytecode 73 * java.base/jdk.experimental.value 74 * @library /test/lib 75 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 76 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 77 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 78 * sun.hotspot.WhiteBox$WhiteBoxPermission 79 * @run main/othervm -Xint -XX:+UseParallelGC -Xmx128m 80 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 81 * runtime.valhalla.valuetypes.ValueOops 82 */ 83 84 /** 85 * @test ValueOops_int_Z 86 * @requires vm.gc.Z 87 * @summary Test embedding oops into Value types 88 * @modules java.base/jdk.experimental.bytecode 89 * java.base/jdk.experimental.value 90 * @library /test/lib 91 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 92 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 93 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 94 * sun.hotspot.WhiteBox$WhiteBoxPermission 95 * @run main/othervm -Xint -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx128m 96 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 97 * runtime.valhalla.valuetypes.ValueOops 98 */ 99 100 /** 101 * @test ValueOops_comp_serial 102 * @requires vm.gc.Serial 103 * @summary Test embedding oops into Value types 104 * @modules java.base/jdk.experimental.bytecode 105 * java.base/jdk.experimental.value 106 * @library /test/lib 107 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 108 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 109 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 110 * sun.hotspot.WhiteBox$WhiteBoxPermission 111 * @run main/othervm -Xcomp -XX:+UseSerialGC -Xmx128m 112 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 113 * runtime.valhalla.valuetypes.ValueOops 114 */ 115 116 /** 117 * @test ValueOops_comp_G1 118 * @requires vm.gc.G1 119 * @summary Test embedding oops into Value types 120 * @modules java.base/jdk.experimental.bytecode 121 * java.base/jdk.experimental.value 122 * @library /test/lib 123 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 124 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 125 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 126 * sun.hotspot.WhiteBox$WhiteBoxPermission 127 * @run main/othervm -Xcomp -XX:+UseG1GC -Xmx128m 128 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 129 * runtime.valhalla.valuetypes.ValueOops 100 130 */ 131 132 /** 133 * @test ValueOops_comp_Parallel 134 * @requires vm.gc.Parallel 135 * @summary Test embedding oops into Value types 136 * @modules java.base/jdk.experimental.bytecode 137 * java.base/jdk.experimental.value 138 * @library /test/lib 139 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator Person.java 140 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator ValueOops.java 141 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 142 * sun.hotspot.WhiteBox$WhiteBoxPermission 143 * @run main/othervm -Xcomp -XX:+UseParallelGC -Xmx128m 144 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 145 * runtime.valhalla.valuetypes.ValueOops 146 */ 147 public class ValueOops { 148 149 // Xcomp with ZGC missing until C1 and C2 barrier code is in place (JDK-8231498) 150 151 // Extra debug: -XX:+VerifyOops -XX:+VerifyStack -XX:+VerifyLastFrame -XX:+VerifyBeforeGC -XX:+VerifyAfterGC -XX:+VerifyDuringGC -XX:VerifySubSet=threads,heap 152 // Even more debugging: -XX:+TraceNewOopMapGeneration -Xlog:gc*=info 153 154 static final int NOF_PEOPLE = 1000; // Exercise arrays of this size 155 156 static int MIN_ACTIVE_GC_COUNT = 10; // Run active workload for this number of GC passes 157 158 static int MED_ACTIVE_GC_COUNT = 4; // Medium life span in terms of GC passes 159 160 static final String TEST_STRING1 = "Test String 1"; 161 static final String TEST_STRING2 = "Test String 2"; 162 163 static boolean USE_COMPILER = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompiler"); 164 165 static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 166 167 public static void main(String[] args) { 168 if (args.length > 0) { 169 MIN_ACTIVE_GC_COUNT = Integer.parseInt(args[0]); 170 } 171 testClassLoad(); 172 testValues(); 173 174 if (!USE_COMPILER) { 175 testOopMaps(); 176 } 177 178 // Check we survive GC... 179 testOverGc(); // Exercise root scan / oopMap 180 testActiveGc(); // Brute force 181 } 182 183 /** 184 * Test ClassFileParser can load inline types with reference fields 185 */ 186 public static void testClassLoad() { 187 String s = Person.class.toString(); 188 new Bar(); 189 new BarWithValue(); 190 s = BarValue.class.toString(); 191 s = ObjectWithObjectValue.class.toString(); 192 s = ObjectWithObjectValues.class.toString(); 193 } 194 195 196 static class Couple { 197 public Person onePerson; 198 public Person otherPerson; 199 } 200 201 static final inline class Composition { 202 public final Person onePerson; 203 public final Person otherPerson; 204 205 private Composition() { 206 onePerson = Person.create(0, null, null); 207 otherPerson = Person.create(0, null, null); 208 } 209 210 public static Composition create(Person onePerson, Person otherPerson) { 211 Composition comp = Composition.default; 212 comp = __WithField(comp.onePerson, onePerson); 213 comp = __WithField(comp.otherPerson, otherPerson); 214 return comp; 215 } 216 } 217 218 /** 219 * Check inline type operations with "Valhalla Inline Types" (VVT) 220 */ 221 public static void testValues() { 222 // Exercise creation, getfield, vreturn with null refs 223 validateDefaultPerson(createDefaultPerson()); 224 225 // anewarray, aaload, aastore 226 int index = 7; 227 Person[] array = new Person[NOF_PEOPLE]; 228 validateDefaultPerson(array[index]); 229 230 // Now with refs... 231 validateIndexedPerson(createIndexedPerson(index), index); 232 array[index] = createIndexedPerson(index); 233 validateIndexedPerson(array[index], index); 234 235 // Check the neighbours 236 validateDefaultPerson(array[index - 1]); 237 validateDefaultPerson(array[index + 1]); 238 239 // getfield/putfield 240 Couple couple = new Couple(); 241 validateDefaultPerson(couple.onePerson); 242 validateDefaultPerson(couple.otherPerson); 243 244 couple.onePerson = createIndexedPerson(index); 245 validateIndexedPerson(couple.onePerson, index); 246 247 Composition composition = Composition.create(couple.onePerson, couple.onePerson); 248 validateIndexedPerson(composition.onePerson, index); 249 validateIndexedPerson(composition.otherPerson, index); 250 } 251 252 /** 253 * Check oop map generation for klass layout and frame... 254 */ 255 public static void testOopMaps() { 256 Object[] objects = WhiteBox.getWhiteBox().getObjectsViaKlassOopMaps(new Couple()); 257 assertTrue(objects.length == 4, "Expected 4 oops"); 258 for (int i = 0; i < objects.length; i++) { 259 assertTrue(objects[i] == null, "not-null"); 260 } 261 262 String fn1 = "Sam"; 263 String ln1 = "Smith"; 264 String fn2 = "Jane"; 265 String ln2 = "Jones"; 266 Couple couple = new Couple(); 267 couple.onePerson = Person.create(0, fn1, ln1); 268 couple.otherPerson = Person.create(1, fn2, ln2); 269 objects = WhiteBox.getWhiteBox().getObjectsViaKlassOopMaps(couple); 270 assertTrue(objects.length == 4, "Expected 4 oops"); 271 assertTrue(objects[0] == fn1, "Bad oop fn1"); 272 assertTrue(objects[1] == ln1, "Bad oop ln1"); 273 assertTrue(objects[2] == fn2, "Bad oop fn2"); 274 assertTrue(objects[3] == ln2, "Bad oop ln2"); 275 276 objects = WhiteBox.getWhiteBox().getObjectsViaOopIterator(couple); 277 assertTrue(objects.length == 4, "Expected 4 oops"); 278 assertTrue(objects[0] == fn1, "Bad oop fn1"); 279 assertTrue(objects[1] == ln1, "Bad oop ln1"); 280 assertTrue(objects[2] == fn2, "Bad oop fn2"); 281 assertTrue(objects[3] == ln2, "Bad oop ln2"); 282 283 // Array.. 284 objects = WhiteBox.getWhiteBox().getObjectsViaOopIterator(createPeople()); 285 assertTrue(objects.length == NOF_PEOPLE * 2, "Unexpected length: " + objects.length); 286 int o = 0; 287 for (int i = 0; i < NOF_PEOPLE; i++) { 288 assertTrue(objects[o++].equals(firstName(i)), "Bad firstName"); 289 assertTrue(objects[o++].equals(lastName(i)), "Bad lastName"); 290 } 291 292 // Sanity check, FixMe need more test cases 293 objects = testFrameOops(couple); 294 //assertTrue(objects.length == 5, "Number of frame oops incorrect = " + objects.length); 295 //assertTrue(objects[0] == couple, "Bad oop 0"); 296 //assertTrue(objects[1] == fn1, "Bad oop 1"); 297 //assertTrue(objects[2] == ln1, "Bad oop 2"); 298 //assertTrue(objects[3] == TEST_STRING1, "Bad oop 3"); 299 //assertTrue(objects[4] == TEST_STRING2, "Bad oop 4"); 300 301 //testFrameOopsVBytecodes(); 302 } 303 304 static final String GET_OOP_MAP_NAME = "getOopMap"; 305 static final String GET_OOP_MAP_DESC = "()[Ljava/lang/Object;"; 306 307 public static Object[] getOopMap() { 308 Object[] oopMap = WhiteBox.getWhiteBox().getObjectsViaFrameOopIterator(2); 309 /* Remove this frame (class mirror for this method), and above class mirror */ 310 Object[] trimmedOopMap = new Object[oopMap.length - 2]; 311 System.arraycopy(oopMap, 2, trimmedOopMap, 0, trimmedOopMap.length); 312 return trimmedOopMap; 313 } 314 315 // Expecting Couple couple, Person couple.onePerson, and Person (created here) 316 public static Object[] testFrameOops(Couple couple) { 317 int someId = 89898; 318 Person person = couple.onePerson; 319 assertTrue(person.getId() == 0, "Bad Person"); 320 Person anotherPerson = Person.create(someId, TEST_STRING1, TEST_STRING2); 321 assertTrue(anotherPerson.getId() == someId, "Bad Person"); 322 return getOopMap(); 323 } 324 325 // Debug... 326 static void dumpOopMap(Object[] oopMap) { 327 System.out.println("Oop Map len: " + oopMap.length); 328 for (int i = 0; i < oopMap.length; i++) { 329 System.out.println("[" + i + "] = " + oopMap[i]); 330 } 331 } 332 333 /** 334 * Just some check sanity checks with defaultvalue, withfield, astore and aload 335 * 336 * Changes to javac slot usage may well break this test 337 */ 338 public static void testFrameOopsVBytecodes() { 339 int nofOopMaps = 4; 340 Object[][] oopMaps = new Object[nofOopMaps][]; 341 String[] inputArgs = new String[] { "aName", "aDescription", "someNotes" }; 342 343 FooValue.testFrameOopsDefault(oopMaps); 344 345 // Test-D0 Slots=R Stack=Q(RRR)RV 346 assertTrue(oopMaps[0].length == 5 && 347 oopMaps[0][1] == null && 348 oopMaps[0][2] == null && 349 oopMaps[0][3] == null, "Test-D0 incorrect"); 350 351 // Test-D1 Slots=R Stack=RV 352 assertTrue(oopMaps[1].length == 2, "Test-D1 incorrect"); 353 354 // Test-D2 Slots=RQ(RRR) Stack=RV 355 assertTrue(oopMaps[2].length == 5 && 356 oopMaps[2][1] == null && 357 oopMaps[2][2] == null && 358 oopMaps[2][3] == null, "Test-D2 incorrect"); 359 360 // Test-D3 Slots=R Stack=Q(RRR)RV 361 assertTrue(oopMaps[3].length == 6 && 362 oopMaps[3][1] == null && 363 oopMaps[3][2] == null && 364 oopMaps[3][3] == null && 365 oopMaps[3][4] == null, "Test-D3 incorrect"); 366 367 // With ref fields... 368 String name = "TestName"; 369 String desc = "TestDesc"; 370 String note = "TestNotes"; 371 FooValue.testFrameOopsRefs(name, desc, note, oopMaps); 372 373 // Test-R0 Slots=RR Stack=Q(RRR)RV 374 assertTrue(oopMaps[0].length == 6 && 375 oopMaps[0][2] == name && 376 oopMaps[0][3] == desc && 377 oopMaps[0][4] == note, "Test-R0 incorrect"); 378 379 /** 380 * TODO: vwithfield from method handle cooked from anonymous class within the inline class 381 * even with "MethodHandles.privateLookupIn()" will fail final putfield rules 382 */ 383 } 384 385 /** 386 * Check forcing GC for combination of VT on stack/LVT etc works 387 */ 388 public static void testOverGc() { 389 try { 390 Class<?> vtClass = Person.class; 391 392 System.out.println("vtClass="+vtClass); 393 394 doGc(); 395 396 // VT on stack and lvt, null refs, see if GC flies 397 MethodHandle moveValueThroughStackAndLvt = MethodHandleBuilder.loadCode( 398 LOOKUP, 399 "gcOverPerson", 400 MethodType.methodType(vtClass, vtClass), 401 CODE->{ 402 CODE 403 .aload(0) 404 .invokestatic(ValueOops.class, "doGc", "()V", false) // Stack 405 .astore(0) 406 .invokestatic(ValueOops.class, "doGc", "()V", false) // LVT 407 .aload(0) 408 .astore(1024) // LVT wide index 409 .aload(1024) 410 .iconst_1() // push a litte further down 411 .invokestatic(ValueOops.class, "doGc", "()V", false) // Stack,LVT 412 .pop() 413 .areturn(); 414 }); 415 Person person = (Person) moveValueThroughStackAndLvt.invokeExact(createDefaultPerson()); 416 validateDefaultPerson(person); 417 doGc(); 418 419 int index = 4711; 420 person = (Person) moveValueThroughStackAndLvt.invokeExact(createIndexedPerson(index)); 421 validateIndexedPerson(person, index); 422 doGc(); 423 person = createDefaultPerson(); 424 doGc(); 425 } 426 catch (Throwable t) { fail("testOverGc", t); } 427 } 428 429 static void submitNewWork(ForkJoinPool fjPool, int size) { 430 for (int i = 0; i < size; i++) { 431 for (int j = 0; j < 100; j++) { 432 fjPool.execute(ValueOops::testValues); 433 } 434 } 435 } 436 437 static void sleepNoThrow(long ms) { 438 try { 439 Thread.sleep(ms); 440 } 441 catch (Throwable t) {} 442 } 443 444 /** 445 * Run some workloads with different object/value life times... 446 */ 447 public static void testActiveGc() { 448 try { 449 int nofThreads = 7; 450 int workSize = nofThreads * 10; 451 452 Object longLivedObjects = createLongLived(); 453 Object longLivedPeople = createPeople(); 454 455 Object medLivedObjects = createLongLived(); 456 Object medLivedPeople = createPeople(); 457 458 doGc(); 459 460 ForkJoinPool fjPool = new ForkJoinPool(nofThreads, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); 461 462 // submit work until we see some GC 463 Reference ref = createRef(); 464 submitNewWork(fjPool, workSize); 465 while (ref.get() != null) { 466 if (fjPool.hasQueuedSubmissions()) { 467 sleepNoThrow(1L); 468 } 469 else { 470 workSize *= 2; // Grow the submission size 471 submitNewWork(fjPool, workSize); 472 } 473 } 474 475 // Keep working and actively GC, until MIN_ACTIVE_GC_COUNT 476 int nofActiveGc = 1; 477 ref = createRef(); 478 while (nofActiveGc < MIN_ACTIVE_GC_COUNT) { 479 if (ref.get() == null) { 480 nofActiveGc++; 481 ref = createRef(); 482 if (nofActiveGc % MED_ACTIVE_GC_COUNT == 0) { 483 validateLongLived(medLivedObjects); 484 validatePeople(medLivedPeople); 485 486 medLivedObjects = createLongLived(); 487 medLivedPeople = createPeople(); 488 } 489 } 490 else if (fjPool.hasQueuedSubmissions()) { 491 sleepNoThrow((long) Utils.getRandomInstance().nextInt(1000)); 492 doGc(); 493 } 494 else { 495 submitNewWork(fjPool, workSize); 496 } 497 } 498 fjPool.shutdown(); 499 500 validateLongLived(medLivedObjects); 501 validatePeople(medLivedPeople); 502 medLivedObjects = null; 503 medLivedPeople = null; 504 505 validateLongLived(longLivedObjects); 506 validatePeople(longLivedPeople); 507 508 longLivedObjects = null; 509 longLivedPeople = null; 510 511 doGc(); 512 } 513 catch (Throwable t) { fail("testActiveGc", t); } 514 } 515 516 static final ReferenceQueue<Object> REFQ = new ReferenceQueue<>(); 517 518 public static void doGc() { 519 // Create Reference, wait until it clears... 520 Reference ref = createRef(); 521 while (ref.get() != null) { 522 System.gc(); 523 } 524 } 525 526 static Reference createRef() { 527 return new WeakReference<Object>(new Object(), REFQ); 528 } 529 530 static void validatePerson(Person person, int id, String fn, String ln, boolean equals) { 531 assertTrue(person.id == id); 532 if (equals) { 533 assertTrue(fn.equals(person.getFirstName()), "Invalid field firstName"); 534 assertTrue(ln.equals(person.getLastName()), "Invalid field lastName"); 535 } 536 else { 537 assertTrue(person.getFirstName() == fn, "Invalid field firstName"); 538 assertTrue(person.getLastName() == ln, "Invalid field lastName"); 539 } 540 } 541 542 static Person createIndexedPerson(int i) { 543 return Person.create(i, firstName(i), lastName(i)); 544 } 545 546 static void validateIndexedPerson(Person person, int i) { 547 validatePerson(person, i, firstName(i), lastName(i), true); 548 } 549 550 static Person createDefaultPerson() { 551 return Person.create(0, null, null); 552 } 553 554 static void validateDefaultPerson(Person person) { 555 validatePerson(person, 0, null, null, false); 556 } 557 558 static String firstName(int i) { 559 return "FirstName-" + i; 560 } 561 562 static String lastName(int i) { 563 return "LastName-" + i; 564 } 565 566 static Object createLongLived() throws Throwable { 567 Object[] population = new Object[1]; 568 population[0] = createPeople(); 569 return population; 570 } 571 572 static void validateLongLived(Object pop) throws Throwable { 573 Object[] population = (Object[]) pop; 574 validatePeople(population[0]); 575 } 576 577 static Object createPeople() { 578 int arrayLength = NOF_PEOPLE; 579 Person[] people = new Person[arrayLength]; 580 for (int i = 0; i < arrayLength; i++) { 581 people[i] = createIndexedPerson(i); 582 } 583 return people; 584 } 585 586 static void validatePeople(Object array) { 587 Person[] people = (Person[]) array; 588 int arrayLength = people.length; 589 assertTrue(arrayLength == NOF_PEOPLE); 590 for (int i = 0; i < arrayLength; i++) { 591 validateIndexedPerson(people[i], i); 592 } 593 } 594 595 // Various field layouts...sanity testing, see MVTCombo testing for full-set 596 597 static final inline class ObjectValue { 598 final Object object; 599 600 private ObjectValue(Object obj) { 601 object = obj; 602 } 603 } 604 605 static class ObjectWithObjectValue { 606 ObjectValue value1; 607 Object ref1; 608 } 609 610 static class ObjectWithObjectValues { 611 ObjectValue value1; 612 ObjectValue value2; 613 Object ref1; 614 } 615 616 static class Foo { 617 int id; 618 String name; 619 String description; 620 long timestamp; 621 String notes; 622 } 623 624 static class Bar extends Foo { 625 long extendedId; 626 String moreNotes; 627 int count; 628 String otherStuff; 629 } 630 631 public static final inline class FooValue { 632 public final int id; 633 public final String name; 634 public final String description; 635 public final long timestamp; 636 public final String notes; 637 638 private FooValue() { 639 id = 0; 640 name = null; 641 description = null; 642 timestamp = 0L; 643 notes = null; 644 } 645 646 public static FooValue create(int id, String name, String description, long timestamp, String notes) { 647 FooValue f = FooValue.default; 648 f = __WithField(f.id, id); 649 f = __WithField(f.name, name); 650 f = __WithField(f.description, description); 651 f = __WithField(f.timestamp, timestamp); 652 f = __WithField(f.notes, notes); 653 return f; 654 } 655 656 public static void testFrameOopsDefault(Object[][] oopMaps) { 657 MethodType mt = MethodType.methodType(Void.TYPE, oopMaps.getClass()); 658 int oopMapsSlot = 0; 659 int vtSlot = 1; 660 661 // Slots 1=oopMaps 662 // OopMap Q=RRR (.name .description .someNotes) 663 try { 664 MethodHandleBuilder.loadCode( 665 LOOKUP, "exerciseVBytecodeExprStackWithDefault", mt, 666 CODE->{ 667 CODE 668 .defaultvalue(FooValue.class) 669 .aload(oopMapsSlot) 670 .iconst_0() // Test-D0 Slots=R Stack=Q(RRR)RV 671 .invokestatic(ValueOops.class, GET_OOP_MAP_NAME, GET_OOP_MAP_DESC, false) 672 .aastore() 673 .pop() 674 .aload(oopMapsSlot) 675 .iconst_1() // Test-D1 Slots=R Stack=RV 676 .invokestatic(ValueOops.class, GET_OOP_MAP_NAME, GET_OOP_MAP_DESC, false) 677 .aastore() 678 .defaultvalue(FooValue.class) 679 .astore(vtSlot) 680 .aload(oopMapsSlot) 681 .iconst_2() // Test-D2 Slots=RQ(RRR) Stack=RV 682 .invokestatic(ValueOops.class, GET_OOP_MAP_NAME, GET_OOP_MAP_DESC, false) 683 .aastore() 684 .aload(vtSlot) 685 .aconst_null() 686 .astore(vtSlot) // Storing null over the Q slot won't remove the ref, but should be single null ref 687 .aload(oopMapsSlot) 688 .iconst_3() // Test-D3 Slots=R Stack=Q(RRR)RV 689 .invokestatic(ValueOops.class, GET_OOP_MAP_NAME, GET_OOP_MAP_DESC, false) 690 .aastore() 691 .pop() 692 .return_(); 693 }).invoke(oopMaps); 694 } catch (Throwable t) { fail("exerciseVBytecodeExprStackWithDefault", t); } 695 } 696 697 public static void testFrameOopsRefs(String name, String description, String notes, Object[][] oopMaps) { 698 FooValue f = create(4711, name, description, 9876543231L, notes); 699 FooValue[] fa = new FooValue[] { f }; 700 MethodType mt = MethodType.methodType(Void.TYPE, fa.getClass(), oopMaps.getClass()); 701 int fooArraySlot = 0; 702 int oopMapsSlot = 1; 703 try { 704 MethodHandleBuilder.loadCode(LOOKUP, "exerciseVBytecodeExprStackWithRefs", mt, 705 CODE->{ 706 CODE 707 .aload(fooArraySlot) 708 .iconst_0() 709 .aaload() 710 .aload(oopMapsSlot) 711 .iconst_0() // Test-R0 Slots=RR Stack=Q(RRR)RV 712 .invokestatic(ValueOops.class, GET_OOP_MAP_NAME, GET_OOP_MAP_DESC, false) 713 .aastore() 714 .pop() 715 .return_(); 716 }).invoke(fa, oopMaps); 717 } catch (Throwable t) { fail("exerciseVBytecodeExprStackWithRefs", t); } 718 } 719 } 720 721 static class BarWithValue { 722 FooValue foo; 723 long extendedId; 724 String moreNotes; 725 int count; 726 String otherStuff; 727 } 728 729 static final inline class BarValue { 730 final FooValue foo; 731 final long extendedId; 732 final String moreNotes; 733 final int count; 734 final String otherStuff; 735 736 private BarValue(FooValue f, long extId, String mNotes, int c, String other) { 737 foo = f; 738 extendedId = extId; 739 moreNotes = mNotes; 740 count = c; 741 otherStuff = other; 742 } 743 } 744 745 } 746