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