1 /* 2 * Copyright (c) 2017, 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 import jdk.experimental.value.*; 30 31 import static jdk.test.lib.Asserts.*; 32 import jdk.test.lib.Utils; 33 import sun.hotspot.WhiteBox; 34 35 /* 36 * @test ValueOops 37 * @summary Test embedding oops into Value types 38 * @library /testlibrary /test/lib / 39 * @build sun.hotspot.WhiteBox 40 * runtime.valhalla.valuetypes.ValueOops 41 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 42 * sun.hotspot.WhiteBox$WhiteBoxPermission 43 * @run main/othervm -Xint -noverify -XX:+UseSerialGC -Xmx128m 44 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 45 * runtime.valhalla.valuetypes.ValueOops 46 * @run main/othervm -Xint -noverify -XX:+UseG1GC -Xmx128m 47 * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 48 * runtime.valhalla.valuetypes.ValueOops 49 */ 50 public class ValueOops { 51 52 /* 53 * Remaining work: 54 * -Xint -noverify -XX:+UseParallelGC -Xmx128m runtime.valhalla.valuetypes.ValueOops 55 * Generated layout permutations 56 */ 57 58 // Extra debug: -XX:+VerifyOops -XX:+VerifyStack -XX:+VerifyLastFrame -XX:+VerifyBeforeGC -XX:+VerifyAfterGC -XX:+VerifyDuringGC -XX:VerifySubSet=threads,heap 59 // Even more debugging: -XX:+TraceNewOopMapGeneration -Xlog:gc*=info 60 61 static final int NOF_PEOPLE = 1000; // Exercise arrays of this size 62 63 static int MIN_ACTIVE_GC_COUNT = 10; // Run active workload for this number of GC passes 64 65 static int MED_ACTIVE_GC_COUNT = 4; // Medium life span in terms of GC passes 66 67 static final String TEST_STRING1 = "Test String 1"; 68 static final String TEST_STRING2 = "Test String 2"; 69 70 public static void main(String[] args) { 71 if (args.length > 0) { 72 MIN_ACTIVE_GC_COUNT = Integer.parseInt(args[0]); 73 } 74 testClassLoad(); 75 testBytecodes(); 76 testVvt(); 77 testMvt(); 78 79 testOopMaps(); 80 81 // Check we survive GC... 82 testOverGc(); // Exercise root scan / oopMap 83 testActiveGc(); // Brute force 84 } 85 86 /** 87 * Test ClassFileParser can load values with reference fields 88 */ 89 public static void testClassLoad() { 90 // VVT 91 String s = Person.class.toString(); 92 new Bar(); 93 new BarWithValue(); 94 s = BarValue.class.toString(); 95 s = ObjectWithObjectValue.class.toString(); 96 s = ObjectWithObjectValues.class.toString(); 97 98 // MVT 99 Class<?> vccClass = PersonVcc.class; 100 ValueType<?> vt = ValueType.forClass(vccClass); 101 Class<?> boxClass = vt.boxClass(); 102 Class<?> dvtClass = vt.valueClass(); 103 Class<?> arrayClass = vt.arrayValueClass(); 104 s = dvtClass.toString(); 105 } 106 107 /** 108 * Test value type opcodes are okay with reference fields in values 109 * I.e. ValueKlass::value_store() 110 */ 111 public static void testBytecodes() { 112 try { 113 // Craft Value Type class how you will, using MVT class for simplicity just here 114 ValueType<?> vt = ValueType.forClass(PersonVcc.class); 115 Class<?> vtClass = vt.valueClass(); 116 Class<?> arrayClass = vt.arrayValueClass(); 117 Class<?> boxClass = vt.boxClass(); 118 MethodHandles.Lookup lookup = MethodHandles.lookup(); 119 120 // Exercise with null refs... 121 122 // anewarray 123 Object array = MethodHandleBuilder.loadCode( 124 lookup, 125 "anewarrayPerson", 126 MethodType.methodType(Object.class, Integer.TYPE), 127 CODE->{ 128 CODE 129 .iload(0) 130 .anewarray(vtClass) 131 .astore(0) 132 .aload(0) 133 .areturn(); 134 }).invoke(NOF_PEOPLE); 135 136 // vaload 137 // vstore 138 // vload 139 // vastore 140 // vbox 141 int arraySlot = 0; 142 int indexSlot = 1; 143 int valueSlot = 2; 144 Object obj = MethodHandleBuilder.loadCode( 145 lookup, 146 "valoadBoxPerson", 147 MethodType.methodType(Object.class, arrayClass, Integer.TYPE), 148 CODE->{ 149 CODE 150 .aload(arraySlot) 151 .iload(indexSlot) 152 .vaload() 153 .vstore(valueSlot) 154 .aload(arraySlot) 155 .iload(indexSlot) 156 .vload(valueSlot) 157 .vastore() 158 .vload(valueSlot) 159 .vbox(boxClass) 160 .areturn(); 161 }).invoke(array, 7); 162 validateDefaultPersonVcc(obj); 163 164 // vreturn 165 MethodHandle loadValueFromArray = MethodHandleBuilder.loadCode( 166 lookup, 167 "valoadVreturnPerson", 168 MethodType.methodType(vtClass, arrayClass, Integer.TYPE), 169 CODE->{ 170 CODE 171 .aload(arraySlot) 172 .iload(indexSlot) 173 .vaload() 174 .vreturn(); 175 }); 176 MethodHandle box = MethodHandleBuilder.loadCode( 177 lookup, 178 "boxPersonVcc", 179 MethodType.methodType(boxClass, vtClass), 180 CODE->{ 181 CODE 182 .vload(0) 183 .vbox(boxClass) 184 .areturn(); 185 }); 186 MethodHandle loadValueFromArrayBoxed = 187 MethodHandles.filterReturnValue(loadValueFromArray, box); 188 obj = loadValueFromArrayBoxed.invoke(array, 0); 189 validateDefaultPersonVcc(obj); 190 191 // vunbox 192 MethodHandle unbox = MethodHandleBuilder.loadCode( 193 lookup, 194 "unboxPersonVcc", 195 MethodType.methodType(vtClass, boxClass), 196 CODE->{ 197 CODE 198 .aload(0) 199 .vunbox(vtClass) 200 .vreturn(); 201 }); 202 MethodHandle unboxBox = MethodHandles.filterReturnValue(unbox, box); 203 obj = unboxBox.invoke(createDefaultPersonVcc()); 204 validateDefaultPersonVcc(obj); 205 206 /* 207 vgetfield 208 qputfield 209 qgetfield 210 211 going to need VVT for VT fields and vgetfield 212 check test coverage in testVvt() 213 */ 214 215 // Exercise with live refs... 216 Thread.holdsLock("Debug here"); 217 // vunbox 218 // vastore 219 // vaload 220 // vstore 221 // vload 222 // vbox 223 int index = 3; 224 obj = MethodHandleBuilder.loadCode( 225 lookup, 226 "unboxStoreLoadPersonVcc", 227 MethodType.methodType(boxClass, arrayClass, Integer.TYPE, boxClass), 228 CODE->{ 229 CODE 230 .aload(arraySlot) 231 .iload(indexSlot) 232 .aload(valueSlot) 233 .vunbox(vtClass) 234 .vastore() 235 .aload(arraySlot) 236 .iload(indexSlot) 237 .vaload() 238 .vstore(valueSlot) 239 .vload(valueSlot) 240 .vbox(boxClass) 241 .areturn(); 242 }).invoke(array, index, createIndexedPersonVcc(index)); 243 validateIndexedPersonVcc(obj, index); 244 245 // Check the neighbours 246 validateDefaultPersonVcc(loadValueFromArrayBoxed.invoke(array, index - 1)); 247 validateDefaultPersonVcc(loadValueFromArrayBoxed.invoke(array, index + 1)); 248 249 // vreturn 250 validateIndexedPersonVcc(unboxBox.invoke((PersonVcc)obj), index); 251 } 252 catch (Throwable t) { fail("testBytecodes", t); } 253 } 254 255 static class Couple { 256 public Person onePerson; 257 public Person otherPerson; 258 } 259 260 static final __ByValue class Composition { 261 public final Person onePerson; 262 public final Person otherPerson; 263 264 private Composition(Person onePerson, Person otherPerson) { 265 this.onePerson = onePerson; 266 this.otherPerson = otherPerson; 267 } 268 269 public static Composition create(Person onePerson, Person otherPerson) { 270 return __Make Composition(onePerson, otherPerson); 271 } 272 } 273 274 /** 275 * Check value type operations with "Valhalla Value Types" (VVT) 276 */ 277 public static void testVvt() { 278 // Exercise creation, vgetfield, vreturn with null refs 279 validateDefaultPerson(createDefaultPerson()); 280 281 // anewarray, vaload, vastore 282 int index = 7; 283 Person[] array = new Person[NOF_PEOPLE]; 284 validateDefaultPerson(array[index]); 285 286 // Now with refs... 287 validateIndexedPerson(createIndexedPerson(index), index); 288 array[index] = createIndexedPerson(index); 289 validateIndexedPerson(array[index], index); 290 291 // Check the neighbours 292 validateDefaultPerson(array[index - 1]); 293 validateDefaultPerson(array[index + 1]); 294 295 // getfield/putfield 296 Couple couple = new Couple(); 297 validateDefaultPerson(couple.onePerson); 298 validateDefaultPerson(couple.otherPerson); 299 300 couple.onePerson = createIndexedPerson(index); 301 validateIndexedPerson(couple.onePerson, index); 302 303 Composition composition = Composition.create(couple.onePerson, couple.onePerson); 304 validateIndexedPerson(composition.onePerson, index); 305 validateIndexedPerson(composition.otherPerson, index); 306 } 307 308 /** 309 * Check value type operations with "Minimal Value Types" (MVT) 310 */ 311 public static void testMvt() { 312 try { 313 // MVT... 314 ValueType<?> vt = ValueType.forClass(PersonVcc.class); 315 Class<?> vtClass = vt.valueClass(); 316 Class<?> arrayClass = vt.arrayValueClass(); 317 318 Object obj = vt.defaultValueConstant().invoke(); 319 validateDefaultPersonVcc(obj); 320 321 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()) 322 .invoke(createDefaultPersonVcc()); 323 validateDefaultPersonVcc(obj); 324 325 int index = 11; 326 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()) 327 .invoke(createIndexedPersonVcc(index)); 328 validateIndexedPersonVcc(obj, index); 329 330 testMvtArray("testMvt.array.1", 1); 331 } 332 catch (Throwable t) { 333 fail("testMvtfailed", t); 334 } 335 } 336 337 /** 338 * MVT array operations... 339 */ 340 public static void testMvtPeopleArray() { 341 testMvtArray("testMvtPeopleArray", NOF_PEOPLE); 342 } 343 344 public static void testMvtArray(String testName, int arrayLength) { 345 try { 346 Class<?> vcc = PersonVcc.class; 347 ValueType<?> vt = ValueType.forClass(vcc); 348 Class<?> dvtClass = vt.valueClass(); 349 Class<?> arrayClass = vt.arrayValueClass(); 350 351 MethodHandle arrayElemGet = MethodHandles.arrayElementGetter(arrayClass); 352 MethodHandle arrayElemSet = MethodHandles.arrayElementSetter(arrayClass); 353 354 MethodHandles.Lookup lookup = MethodHandles.lookup(); 355 MethodHandle getId = lookup.findGetter(dvtClass, "id", Integer.TYPE); 356 MethodHandle getFirstName = lookup.findGetter(dvtClass, "firstName", String.class); 357 MethodHandle getLastName = lookup.findGetter(dvtClass, "lastName", String.class); 358 359 MethodHandle getIdFromArray = MethodHandles.filterReturnValue(arrayElemGet, getId); 360 MethodHandle getFnFromArray = MethodHandles.filterReturnValue(arrayElemGet, getFirstName); 361 MethodHandle getLnFromArray = MethodHandles.filterReturnValue(arrayElemGet, getLastName); 362 363 Object people = vt.newArray().invoke(arrayLength); 364 for (int i = 0; i < arrayLength; i++) { 365 arrayElemSet.invoke(people, i, createIndexedPersonVcc(i)); 366 } 367 368 for (int i = 0; i < arrayLength; i++) { 369 validateIndexedPersonVcc(arrayElemGet.invoke(people, i), i); 370 371 int id = (int) getIdFromArray.invoke(people, i); 372 assertTrue(id == i, "Invalid field: Id"); 373 String fn = (String) getFnFromArray.invoke(people, i); 374 assertTrue(fn.equals(firstName(i)), "Invalid field: firstName"); 375 String ln = (String) getLnFromArray.invoke(people, i); 376 assertTrue(ln.equals(lastName(i)), "Invalid field: lastName"); 377 } 378 } 379 catch (Throwable t) { 380 fail(testName + " failed", t); 381 } 382 } 383 384 /** 385 * Check oop map generation for klass layout and frame... 386 */ 387 public static void testOopMaps() { 388 Object[] objects = WhiteBox.getWhiteBox().getObjectsViaKlassOopMaps(new Couple()); 389 assertTrue(objects.length == 4, "Expected 4 oops"); 390 for (int i = 0; i < objects.length; i++) { 391 assertTrue(objects[i] == null, "not-null"); 392 } 393 394 String fn1 = "Sam"; 395 String ln1 = "Smith"; 396 String fn2 = "Jane"; 397 String ln2 = "Jones"; 398 Couple couple = new Couple(); 399 couple.onePerson = Person.create(0, fn1, ln1); 400 couple.otherPerson = Person.create(1, fn2, ln2); 401 objects = WhiteBox.getWhiteBox().getObjectsViaKlassOopMaps(couple); 402 assertTrue(objects.length == 4, "Expected 4 oops"); 403 assertTrue(objects[0] == fn1, "Bad oop fn1"); 404 assertTrue(objects[1] == ln1, "Bad oop ln1"); 405 assertTrue(objects[2] == fn2, "Bad oop fn2"); 406 assertTrue(objects[3] == ln2, "Bad oop ln2"); 407 408 objects = WhiteBox.getWhiteBox().getObjectsViaOopIterator(couple); 409 assertTrue(objects.length == 4, "Expected 4 oops"); 410 assertTrue(objects[0] == fn1, "Bad oop fn1"); 411 assertTrue(objects[1] == ln1, "Bad oop ln1"); 412 assertTrue(objects[2] == fn2, "Bad oop fn2"); 413 assertTrue(objects[3] == ln2, "Bad oop ln2"); 414 415 // Array.. 416 objects = WhiteBox.getWhiteBox().getObjectsViaOopIterator(createPeople()); 417 assertTrue(objects.length == NOF_PEOPLE * 2, "Unexpected length: " + objects.length); 418 int o = 0; 419 for (int i = 0; i < NOF_PEOPLE; i++) { 420 assertTrue(objects[o++].equals(firstName(i)), "Bad firstName"); 421 assertTrue(objects[o++].equals(lastName(i)), "Bad lastName"); 422 } 423 424 // Sanity check, FixMe need more test cases 425 objects = testFrameOops(couple); 426 assertTrue(objects.length == 5, "Number of frame oops incorrect"); 427 assertTrue(objects[0] == couple, "Bad oop 0"); 428 assertTrue(objects[1] == fn1, "Bad oop 1"); 429 assertTrue(objects[2] == ln1, "Bad oop 2"); 430 assertTrue(objects[3] == TEST_STRING1, "Bad oop 3"); 431 assertTrue(objects[4] == TEST_STRING2, "Bad oop 4"); 432 } 433 434 // Expecting Couple couple, Person couple.onePerson, and Person (created here) 435 public static Object[] testFrameOops(Couple couple) { 436 int someId = 89898; 437 Person person = couple.onePerson; 438 assertTrue(person.getId() == 0, "Bad Person"); 439 Person anotherPerson = Person.create(someId, TEST_STRING1, TEST_STRING2); 440 assertTrue(anotherPerson.getId() == someId, "Bad Person"); 441 return WhiteBox.getWhiteBox().getObjectsViaFrameOopIterator(1); 442 } 443 444 /** 445 * Check forcing GC for combination of VT on stack/LVT etc works 446 */ 447 public static void testOverGc() { 448 try { 449 Class<?> vccClass = PersonVcc.class; 450 ValueType<?> vt = ValueType.forClass(vccClass); 451 Class<?> vtClass = vt.valueClass(); 452 Class<?> arrayClass = vt.arrayValueClass(); 453 454 MethodHandles.Lookup lookup = MethodHandles.lookup(); 455 doGc(); 456 457 // VT on stack and lvt, null refs, see if GC flies 458 MethodHandle moveValueThroughStackAndLvt = MethodHandleBuilder.loadCode( 459 lookup, 460 "gcOverPerson", 461 MethodType.methodType(vccClass, vccClass), 462 CODE->{ 463 CODE 464 .aload(0) 465 .vunbox(vtClass) 466 .invokestatic(ValueOops.class, "doGc", "()V", false) // Stack 467 .vstore(0) 468 .invokestatic(ValueOops.class, "doGc", "()V", false) // LVT 469 .vload(0) 470 .iconst_1() // push a litte further down 471 .invokestatic(ValueOops.class, "doGc", "()V", false) // Stack,LVT 472 .pop() 473 .vbox(vccClass) 474 .areturn(); 475 }); 476 Object obj = moveValueThroughStackAndLvt.invoke(createDefaultPersonVcc()); 477 validateDefaultPersonVcc(obj); 478 doGc(); 479 obj = null; 480 doGc(); 481 482 int index = 4711; 483 obj = moveValueThroughStackAndLvt.invoke(createIndexedPersonVcc(index)); 484 validateIndexedPersonVcc(obj, index); 485 doGc(); 486 obj = null; 487 doGc(); 488 } 489 catch (Throwable t) { fail("testOverGc", t); } 490 } 491 492 static void submitNewWork(ForkJoinPool fjPool, int size) { 493 for (int i = 0; i < size; i++) { 494 fjPool.execute(ValueOops::testMvtPeopleArray); 495 for (int j = 0; j < 100; j++) { 496 fjPool.execute(ValueOops::testBytecodes); 497 fjPool.execute(ValueOops::testVvt); 498 fjPool.execute(ValueOops::testMvt); 499 } 500 } 501 } 502 503 static void sleepNoThrow(long ms) { 504 try { 505 Thread.sleep(ms); 506 } 507 catch (Throwable t) {} 508 } 509 510 /** 511 * Run some workloads with differ object/value life times... 512 */ 513 public static void testActiveGc() { 514 try { 515 int nofThreads = 7; 516 int workSize = nofThreads * 10; 517 518 Object longLivedObjects = createLongLived(); 519 Object longLivedPeople = createPeople(); 520 Object longLivedPeopleVcc = createPeopleVcc(); 521 522 Object medLivedObjects = createLongLived(); 523 Object medLivedPeople = createPeople(); 524 Object medLivedPeopleVcc = createPeopleVcc(); 525 526 doGc(); 527 528 ForkJoinPool fjPool = new ForkJoinPool(nofThreads, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); 529 530 // submit work until we see some GC 531 Reference ref = createRef(); 532 submitNewWork(fjPool, workSize); 533 while (ref.get() != null) { 534 if (fjPool.hasQueuedSubmissions()) { 535 sleepNoThrow(1L); 536 } 537 else { 538 workSize *= 2; // Grow the submission size 539 submitNewWork(fjPool, workSize); 540 } 541 } 542 543 // Keep working and actively GC, until MIN_ACTIVE_GC_COUNT 544 int nofActiveGc = 1; 545 ref = createRef(); 546 while (nofActiveGc < MIN_ACTIVE_GC_COUNT) { 547 if (ref.get() == null) { 548 nofActiveGc++; 549 ref = createRef(); 550 if (nofActiveGc % MED_ACTIVE_GC_COUNT == 0) { 551 validateLongLived(medLivedObjects); 552 validatePeople(medLivedPeople); 553 validatePeopleVcc(medLivedPeopleVcc); 554 555 medLivedObjects = createLongLived(); 556 medLivedPeople = createPeople(); 557 medLivedPeopleVcc = createPeopleVcc(); 558 } 559 } 560 else if (fjPool.hasQueuedSubmissions()) { 561 sleepNoThrow((long) Utils.getRandomInstance().nextInt(1000)); 562 doGc(); 563 } 564 else { 565 submitNewWork(fjPool, workSize); 566 } 567 } 568 fjPool.shutdown(); 569 570 validateLongLived(medLivedObjects); 571 validatePeople(medLivedPeople); 572 validatePeopleVcc(medLivedPeopleVcc); 573 medLivedObjects = null; 574 medLivedPeople = null; 575 medLivedPeopleVcc = null; 576 577 validateLongLived(longLivedObjects); 578 validatePeople(longLivedPeople); 579 validatePeopleVcc(longLivedPeopleVcc); 580 581 longLivedObjects = null; 582 longLivedPeople = null; 583 longLivedPeopleVcc = null; 584 585 doGc(); 586 } 587 catch (Throwable t) { fail("testMvtActiveGc", t); } 588 } 589 590 static final ReferenceQueue<Object> REFQ = new ReferenceQueue<>(); 591 592 public static void doGc() { 593 // Create Reference, wait until it clears... 594 Reference ref = createRef(); 595 while (ref.get() != null) { 596 System.gc(); 597 } 598 } 599 600 static Reference createRef() { 601 return new WeakReference<Object>(new Object(), REFQ); 602 } 603 604 static void validatePersonVcc(Object obj, int id, String fn, String ln, boolean equals) { 605 assertTrue(obj.getClass() == PersonVcc.class, "Expected VCC class"); 606 PersonVcc person = (PersonVcc) obj; 607 assertTrue(person.id == id); 608 if (equals) { 609 assertTrue(fn.equals(person.getFirstName()), "Invalid field firstName"); 610 assertTrue(ln.equals(person.getLastName()), "Invalid field lastName"); 611 } 612 else { 613 assertTrue(person.getFirstName() == fn, "Invalid field firstName"); 614 assertTrue(person.getLastName() == ln, "Invalid field lastName"); 615 } 616 } 617 618 static PersonVcc createIndexedPersonVcc(int i) { 619 return PersonVcc.create(i, firstName(i), lastName(i)); 620 } 621 622 static void validateIndexedPersonVcc(Object obj, int i) { 623 validatePersonVcc(obj, i, firstName(i), lastName(i), true); 624 } 625 626 static PersonVcc createDefaultPersonVcc() { 627 return PersonVcc.create(0, null, null); 628 } 629 630 static void validateDefaultPersonVcc(Object obj) { 631 validatePersonVcc(obj, 0, null, null, false); 632 } 633 634 635 static void validatePerson(Person person, int id, String fn, String ln, boolean equals) { 636 assertTrue(person.id == id); 637 if (equals) { 638 assertTrue(fn.equals(person.getFirstName()), "Invalid field firstName"); 639 assertTrue(ln.equals(person.getLastName()), "Invalid field lastName"); 640 } 641 else { 642 assertTrue(person.getFirstName() == fn, "Invalid field firstName"); 643 assertTrue(person.getLastName() == ln, "Invalid field lastName"); 644 } 645 } 646 647 static Person createIndexedPerson(int i) { 648 return Person.create(i, firstName(i), lastName(i)); 649 } 650 651 static void validateIndexedPerson(Person person, int i) { 652 validatePerson(person, i, firstName(i), lastName(i), true); 653 } 654 655 static Person createDefaultPerson() { 656 return Person.create(0, null, null); 657 } 658 659 static void validateDefaultPerson(Person person) { 660 validatePerson(person, 0, null, null, false); 661 } 662 663 static String firstName(int i) { 664 return "FirstName-" + i; 665 } 666 667 static String lastName(int i) { 668 return "LastName-" + i; 669 } 670 671 static Object createLongLived() throws Throwable { 672 Object[] population = new Object[2]; 673 population[0] = createPeople(); 674 population[1] = createPeopleVcc(); 675 return population; 676 } 677 678 static void validateLongLived(Object pop) throws Throwable { 679 Object[] population = (Object[]) pop; 680 validatePeople(population[0]); 681 validatePeopleVcc(population[1]); 682 } 683 684 static Object createPeopleVcc() throws Throwable { 685 int arrayLength = NOF_PEOPLE; 686 Class<?> vccClass = PersonVcc.class; 687 ValueType<?> vt = ValueType.forClass(vccClass); 688 MethodHandle arrayElemSet = MethodHandles.arrayElementSetter(vt.arrayValueClass()); 689 690 Object people = vt.newArray().invoke(arrayLength); 691 for (int i = 0; i < arrayLength; i++) { 692 arrayElemSet.invoke(people, i, createIndexedPersonVcc(i)); 693 } 694 return people; 695 } 696 697 static void validatePeopleVcc(Object people) throws Throwable { 698 MethodHandle arrayElemGet = MethodHandles.arrayElementGetter( 699 ValueType.forClass((Class<?>)PersonVcc.class).arrayValueClass()); 700 701 int arrayLength = java.lang.reflect.Array.getLength(people); 702 assertTrue(arrayLength == NOF_PEOPLE); 703 for (int i = 0; i < arrayLength; i++) { 704 validateIndexedPersonVcc(arrayElemGet.invoke(people, i), i); 705 } 706 } 707 708 static Object createPeople() { 709 int arrayLength = NOF_PEOPLE; 710 Person[] people = new Person[arrayLength]; 711 for (int i = 0; i < arrayLength; i++) { 712 people[i] = createIndexedPerson(i); 713 } 714 return people; 715 } 716 717 static void validatePeople(Object array) { 718 Person[] people = (Person[]) array; 719 int arrayLength = people.length; 720 assertTrue(arrayLength == NOF_PEOPLE); 721 for (int i = 0; i < arrayLength; i++) { 722 validateIndexedPerson(people[i], i); 723 } 724 } 725 726 // Various field layouts... 727 728 static final __ByValue class ObjectValue { 729 final Object object; 730 731 private ObjectValue(Object object) { 732 this.object = object; 733 } 734 } 735 736 static class ObjectWithObjectValue { 737 ObjectValue value1; 738 Object ref1; 739 } 740 741 static class ObjectWithObjectValues { 742 ObjectValue value1; 743 ObjectValue value2; 744 Object ref1; 745 } 746 747 static class Foo { 748 int id; 749 String name; 750 String description; 751 long timestamp; 752 String notes; 753 } 754 755 static class Bar extends Foo { 756 long extendedId; 757 String moreNotes; 758 int count; 759 String otherStuff; 760 } 761 762 static final __ByValue class FooValue { 763 final int id; 764 final String name; 765 final String description; 766 final long timestamp; 767 final String notes; 768 769 private FooValue(int id, String name, String description, long timestamp, String notes) { 770 this.id = id; 771 this.name = name; 772 this.description = description; 773 this.timestamp = timestamp; 774 this.notes = notes; 775 } 776 } 777 778 static class BarWithValue { 779 FooValue foo; 780 long extendedId; 781 String moreNotes; 782 int count; 783 String otherStuff; 784 } 785 786 static final __ByValue class BarValue { 787 final FooValue foo; 788 final long extendedId; 789 final String moreNotes; 790 final int count; 791 final String otherStuff; 792 793 private BarValue(FooValue foo, long extendedId, String moreNotes, int count, String otherStuff) { 794 this.foo = foo; 795 this.extendedId = extendedId; 796 this.moreNotes = moreNotes; 797 this.count = count; 798 this.otherStuff = otherStuff; 799 } 800 } 801 802 /* 803 TODO: Current repo state doesn't pick up the common test/lib Asserts 804 remove this implementation when fixed 805 */ 806 public static void fail(String msg, Throwable thr) { // Missing Asserts.fail(String, Throwable) 807 throw new RuntimeException(msg, thr); 808 } 809 } 810