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.MethodHandleBuilder; 30 import jdk.incubator.mvt.ValueType; 31 32 import static jdk.test.lib.Asserts.*; 33 import jdk.test.lib.Utils; 34 35 /** 36 * @test ValueOopsMvt 37 * @summary Test embedding oops into Minimal Value Types 38 * @modules java.base/jdk.experimental.bytecode 39 * java.base/jdk.experimental.value 40 * jdk.incubator.mvt 41 * @library /test/lib 42 * @compile PersonVcc.java 43 * @compile ValueOopsMvt.java 44 * @run main/othervm -Xint -XX:+UseSerialGC -Xmx128m -XX:+EnableMVT 45 * runtime.valhalla.valuetypes.ValueOopsMvt 46 * @run main/othervm -Xint -XX:+UseG1GC -Xmx128m -XX:+EnableMVT 47 * -XX:-ValueArrayFlatten 48 * runtime.valhalla.valuetypes.ValueOopsMvt 49 * @run main/othervm -Xint -XX:+UseG1GC -Xmx128m -XX:+EnableMVT 50 * runtime.valhalla.valuetypes.ValueOopsMvt 100 51 * @run main/othervm -Xint -XX:+UseParallelGC -Xmx128m -XX:+EnableMVT 52 * runtime.valhalla.valuetypes.ValueOopsMvt 53 * @run main/othervm -Xcomp -XX:+UseSerialGC -Xmx128m -XX:+EnableMVT 54 * runtime.valhalla.valuetypes.ValueOopsMvt 55 * @run main/othervm -Xcomp -XX:+UseG1GC -Xmx128m -XX:+EnableMVT 56 * runtime.valhalla.valuetypes.ValueOopsMvt 100 57 * @run main/othervm -Xcomp -XX:+UseParallelGC -Xmx128m -XX:+EnableMVT 58 * runtime.valhalla.valuetypes.ValueOopsMvt 59 */ 60 public class ValueOopsMvt { 61 62 // Extra debug: -XX:+VerifyOops -XX:+VerifyStack -XX:+VerifyLastFrame -XX:+VerifyBeforeGC -XX:+VerifyAfterGC -XX:+VerifyDuringGC -XX:VerifySubSet=threads,heap 63 // Even more debugging: -XX:+TraceNewOopMapGeneration -Xlog:gc*=info 64 65 66 /* 67 * TODO: Crashes with -Xcomp -XX:+UseG1GC -Xmx128m -XX:+EnableMVT -XX:-ValueArrayFlatten runtime.valhalla.valuetypes.ValueOopsMvt 68 */ 69 70 static final int NOF_PEOPLE = 1000; // Exercise arrays of this size 71 72 static int MIN_ACTIVE_GC_COUNT = 10; // Run active workload for this number of GC passes 73 74 static int MED_ACTIVE_GC_COUNT = 4; // Medium life span in terms of GC passes 75 76 static final String TEST_STRING1 = "Test String 1"; 77 static final String TEST_STRING2 = "Test String 2"; 78 79 static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 80 81 public static void main(String[] args) { 82 if (args.length > 0) { 83 MIN_ACTIVE_GC_COUNT = Integer.parseInt(args[0]); 84 } 85 testClassLoad(); 86 testBytecodes(); 87 testMvt(); 88 89 // Check we survive GC... 90 testOverGc(); // Exercise root scan / oopMap 91 testActiveGc(); // Brute force 92 } 93 94 /** 95 * Test ClassFileParser can load values with reference fields 96 */ 97 public static void testClassLoad() { 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 dvtClass.toString(); 105 } 106 107 108 /* 109 Following tests are broken down into different use cases, and used in 110 multi-threaded stress tests. 111 112 Keeping the use cases separated helps isolate problems when debugging. 113 114 Since we are testing the VM here, no the ValueType API is mostly ignored 115 and the test exercises specific bytecode 116 */ 117 118 /* 119 Method Handle generation is mixed into the invokation code as an attempt 120 to increase readability. 121 */ 122 123 /** 124 * Test Values with Oops with specific bytecodes for various use cases 125 * 126 * Value type specific bytecodes... 127 * 128 * vload 129 * vstore 130 * vaload 131 * vastore 132 * vreturn 133 * vdefault 134 * vwithfield 135 * vbox 136 * vunbox 137 * 138 * Bytecode accepting value types (QTypes) 139 * 140 * anewarray 141 * multianewarray 142 * getfield 143 */ 144 public static void testBytecodes() { 145 try { 146 testBytecodesStackVDefault(); 147 testBytecodesStackVUnbox(); 148 testBytecodesStackAndSlots(); 149 testBytecodesStackAndSlotsDeep(); 150 testBytecodesVBox(); 151 testBytecodesVReturn(); 152 testBytecodesGetField(); 153 testBytecodesVwithfield(); 154 testBytecodesValueArray(); 155 testBytecodesField(); 156 } catch (Throwable t) { 157 throw new RuntimeException(t); 158 } 159 } 160 161 static MethodHandle stacksVDefaultTest; 162 163 // vdefault on stack and pop 164 public static void testBytecodesStackVDefault() throws Throwable { 165 if (stacksVDefaultTest == null) { // Gen MH once 166 stacksVDefaultTest = MethodHandleBuilder.loadCode(LOOKUP, 167 "stacksVDefaultTest", MethodType.methodType(Void.TYPE), 168 CODE->{ 169 CODE 170 .vdefault(ValueType.forClass(PersonVcc.class).valueClass()) 171 .pop() 172 .return_(); 173 }); 174 } 175 stacksVDefaultTest.invokeExact(); 176 } 177 178 static MethodHandle stackVUnboxTest; 179 180 // vunbox on stack and pop 181 public static void testBytecodesStackVUnbox() throws Throwable { 182 if (stackVUnboxTest == null) { 183 stackVUnboxTest = MethodHandleBuilder.loadCode(LOOKUP, 184 "stackVUnboxTest", MethodType.methodType(Void.TYPE, PersonVcc.class), 185 CODE->{ 186 CODE 187 .aload(0) 188 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 189 .pop() 190 .return_(); 191 }); 192 } 193 stackVUnboxTest.invokeExact(createIndexedPersonVcc(7341)); 194 } 195 196 static MethodHandle stackAndSlotsTest; 197 198 // load/store with stack and slots 199 public static void testBytecodesStackAndSlots() throws Throwable { 200 if (stackAndSlotsTest == null) { 201 stackAndSlotsTest = MethodHandleBuilder.loadCode(LOOKUP, 202 "stackAndSlotsTest", MethodType.methodType(Void.TYPE, PersonVcc.class), 203 CODE->{ 204 CODE 205 .aload(0) 206 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 207 .vstore(1) 208 .vload(1) 209 .vstore(2) 210 .return_(); 211 }); 212 } 213 stackAndSlotsTest.invokeExact(createIndexedPersonVcc(7342)); 214 } 215 216 static MethodHandle stackAndSlotsDeepTest; 217 218 // load/store with stack and slots, and call deeper 219 public static void testBytecodesStackAndSlotsDeep() throws Throwable { 220 if (stackAndSlotsDeepTest == null) { 221 stackAndSlotsDeepTest = MethodHandleBuilder.loadCode(LOOKUP, 222 "stackAndSlotsDeepTest", MethodType.methodType(Void.TYPE, PersonVcc.class), 223 CODE->{ 224 CODE 225 .aload(0) 226 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 227 .vstore(1) 228 .vload(1) 229 .vstore(2) 230 .vload(2) 231 .invokestatic(ValueOopsMvt.class, "testBytecodesStackAndSlots", "()V", false) 232 .pop() 233 .return_(); 234 }); 235 } 236 stackAndSlotsDeepTest.invokeExact(createIndexedPersonVcc(7343)); 237 } 238 239 static MethodHandle vboxTest; 240 241 // vbox/vunbox, value on stack 242 public static void testBytecodesVBox() throws Throwable { 243 if (vboxTest == null) { 244 vboxTest = MethodHandleBuilder.loadCode(LOOKUP, 245 "unboxBox", MethodType.methodType(PersonVcc.class, PersonVcc.class), 246 CODE->{ 247 CODE 248 .aload(0) 249 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 250 .vbox(PersonVcc.class) 251 .areturn(); 252 }); 253 } 254 int index = 7344; 255 PersonVcc person = (PersonVcc) vboxTest.invokeExact(createIndexedPersonVcc(index)); 256 validateIndexedPersonVcc(person, index); 257 } 258 259 static MethodHandle vreturnTest; 260 261 // vreturn and pass value as arg 262 public static void testBytecodesVReturn() throws Throwable { 263 if (vreturnTest == null) { 264 MethodHandle vunboxVReturn = MethodHandleBuilder.loadCode(LOOKUP, 265 "vunboxVReturn", MethodType.methodType(ValueType.forClass(PersonVcc.class).valueClass(), PersonVcc.class), 266 CODE->{ 267 CODE 268 .aload(0) 269 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 270 .vreturn(); 271 }); 272 MethodHandle vboxAReturn = MethodHandleBuilder.loadCode(LOOKUP, 273 "vboxAReturn", MethodType.methodType(PersonVcc.class, ValueType.forClass(PersonVcc.class).valueClass()), 274 CODE->{ 275 CODE 276 .vload(0) 277 .vbox(PersonVcc.class) 278 .areturn(); 279 }); 280 vreturnTest = MethodHandles.filterReturnValue(vunboxVReturn, vboxAReturn); 281 } 282 int index = 7345; 283 PersonVcc person = (PersonVcc) vreturnTest.invokeExact(createIndexedPersonVcc(index)); 284 validateIndexedPersonVcc(person, index); 285 } 286 287 static MethodHandle getFieldTest; 288 289 public static void testBytecodesGetField() throws Throwable { 290 if (getFieldTest == null) { 291 getFieldTest = MethodHandleBuilder.loadCode(LOOKUP, 292 "getFieldTest", MethodType.methodType(String.class, PersonVcc.class), 293 CODE->{ 294 CODE 295 .aload(0) 296 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 297 .getfield(ValueType.forClass(PersonVcc.class).valueClass(), "lastName", "Ljava/lang/String;") 298 .areturn(); 299 }); 300 } 301 int index = 7346; 302 String lastName = (String) getFieldTest.invokeExact(createIndexedPersonVcc(index)); 303 assertEquals(lastName, lastName(index)); 304 } 305 306 static MethodHandle vwtihfieldTest; 307 308 public static void testBytecodesVwithfield() throws Throwable { 309 if (vwtihfieldTest == null) { 310 Class<?> dvtClass = ValueType.forClass(PersonVcc.class).valueClass(); 311 vwtihfieldTest = MethodHandleBuilder.loadCode(MethodHandles.privateLookupIn(dvtClass, LOOKUP), 312 "vwtihfieldTest", MethodType.methodType(PersonVcc.class, PersonVcc.class, Integer.TYPE, String.class, String.class), 313 CODE->{ 314 CODE 315 .aload(0) 316 .vunbox(dvtClass) 317 .iload(1) 318 .vwithfield(dvtClass, "id", "I") 319 .aload(2) 320 .vwithfield(dvtClass, "firstName", "Ljava/lang/String;") 321 .aload(3) 322 .vwithfield(dvtClass, "lastName", "Ljava/lang/String;") 323 .vbox(PersonVcc.class) 324 .areturn(); 325 }); 326 } 327 int index = 7347; 328 int diffIndex = 4711; 329 PersonVcc person = (PersonVcc) vwtihfieldTest.invokeExact(createIndexedPersonVcc(index), diffIndex, firstName(diffIndex), lastName(diffIndex)); 330 validateIndexedPersonVcc(person, diffIndex); 331 } 332 333 // load/store with arrays 334 public static void testBytecodesValueArray() throws Throwable { 335 testBytecodesArrayNew(); 336 testBytecodesArrayLoad(); 337 testBytecodesArrayStore(); 338 testBytecodesArrayStoreLoad(); 339 340 // multidim... 341 } 342 343 static MethodHandle anewarrayTest; 344 345 public static void testBytecodesArrayNew() throws Throwable { 346 if (anewarrayTest == null) { 347 anewarrayTest = MethodHandleBuilder.loadCode(LOOKUP, 348 "anewarrayTest", MethodType.methodType(Integer.TYPE, Integer.TYPE), 349 CODE->{ 350 CODE 351 .iload(0) 352 .anewarray(ValueType.forClass(PersonVcc.class).valueClass()) 353 .arraylength() 354 .ireturn(); 355 }); 356 } 357 int asize = (int) anewarrayTest.invokeExact(NOF_PEOPLE); 358 assertTrue(asize == NOF_PEOPLE, "Invariant"); 359 } 360 361 static MethodHandle valoadTest; 362 363 public static void testBytecodesArrayLoad() throws Throwable { 364 if (valoadTest == null) { 365 valoadTest = MethodHandleBuilder.loadCode(LOOKUP, 366 "valoadTest", MethodType.methodType(PersonVcc.class, Integer.TYPE, Integer.TYPE), 367 CODE->{ 368 CODE 369 .iload(0) 370 .anewarray(ValueType.forClass(PersonVcc.class).valueClass()) 371 .iload(1) 372 .vaload() 373 .vbox(PersonVcc.class) 374 .areturn(); 375 }); 376 } 377 PersonVcc person = (PersonVcc) valoadTest.invokeExact(NOF_PEOPLE, 7); 378 validateDefaultPersonVcc(person); 379 } 380 381 static MethodHandle varrayStoreTest; 382 383 public static void testBytecodesArrayStore() throws Throwable { 384 if (varrayStoreTest == null) { 385 varrayStoreTest = MethodHandleBuilder.loadCode(LOOKUP, 386 "varrayStoreTest", MethodType.methodType(Void.TYPE, Integer.TYPE, Integer.TYPE, PersonVcc.class), 387 CODE->{ 388 CODE 389 .iload(0) 390 .anewarray(ValueType.forClass(PersonVcc.class).valueClass()) 391 .iload(1) 392 .aload(2) 393 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 394 .vastore() 395 .return_(); 396 }); 397 } 398 int index = 11; 399 varrayStoreTest.invokeExact(NOF_PEOPLE, index, createIndexedPersonVcc(index)); 400 } 401 402 static MethodHandle varrayStoreLoadTest; 403 404 public static void testBytecodesArrayStoreLoad() throws Throwable { 405 if (varrayStoreLoadTest == null) { 406 varrayStoreLoadTest = MethodHandleBuilder.loadCode(LOOKUP, 407 "varrayStoreLoadTest", MethodType.methodType(PersonVcc.class, Integer.TYPE, Integer.TYPE, PersonVcc.class), 408 CODE->{ 409 CODE 410 .iload(0) 411 .anewarray(ValueType.forClass(PersonVcc.class).valueClass()) 412 .dup() 413 .iload(1) 414 .aload(2) 415 .vunbox(ValueType.forClass(PersonVcc.class).valueClass()) 416 .vastore() 417 .iload(1) 418 .vaload() 419 .vbox(PersonVcc.class) 420 .areturn(); 421 }); 422 } 423 int index = NOF_PEOPLE - 1; 424 PersonVcc person = (PersonVcc) varrayStoreLoadTest.invokeExact(NOF_PEOPLE, index, createIndexedPersonVcc(index)); 425 validateIndexedPersonVcc(person, index); 426 } 427 428 // load/store with Object fields 429 public static void testBytecodesField() throws Throwable { 430 // CMH: no MVT support yet 431 } 432 433 /** 434 * Check value type operations with "Minimal Value Types" (MVT) API 435 */ 436 public static void testMvt() { 437 try { 438 // MVT... 439 ValueType<?> vt = ValueType.forClass(PersonVcc.class); 440 Class<?> vtClass = vt.valueClass(); 441 Class<?> arrayClass = vt.arrayValueClass(); 442 443 Object obj = vt.defaultValueConstant().invoke(); 444 validateDefaultPersonVcc(obj); 445 446 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()) 447 .invoke(createDefaultPersonVcc()); 448 validateDefaultPersonVcc(obj); 449 450 int index = 11; 451 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()) 452 .invoke(createIndexedPersonVcc(index)); 453 validateIndexedPersonVcc(obj, index); 454 455 testMvtArray("testMvt.array.1", 1); 456 } 457 catch (Throwable t) { 458 fail("testMvtfailed", t); 459 } 460 } 461 462 /** 463 * MVT array operations... 464 */ 465 public static void testMvtPeopleArray() { 466 testMvtArray("testMvtPeopleArray", NOF_PEOPLE); 467 } 468 469 public static void testMvtArray(String testName, int arrayLength) { 470 try { 471 Class<?> vcc = PersonVcc.class; 472 ValueType<?> vt = ValueType.forClass(vcc); 473 Class<?> dvtClass = vt.valueClass(); 474 Class<?> arrayClass = vt.arrayValueClass(); 475 476 MethodHandle arrayElemGet = MethodHandles.arrayElementGetter(arrayClass); 477 MethodHandle arrayElemSet = MethodHandles.arrayElementSetter(arrayClass); 478 479 MethodHandle getId = LOOKUP.findGetter(dvtClass, "id", Integer.TYPE); 480 MethodHandle getFirstName = LOOKUP.findGetter(dvtClass, "firstName", String.class); 481 MethodHandle getLastName = LOOKUP.findGetter(dvtClass, "lastName", String.class); 482 483 MethodHandle getIdFromArray = MethodHandles.filterReturnValue(arrayElemGet, getId); 484 MethodHandle getFnFromArray = MethodHandles.filterReturnValue(arrayElemGet, getFirstName); 485 MethodHandle getLnFromArray = MethodHandles.filterReturnValue(arrayElemGet, getLastName); 486 487 Object people = vt.newArray().invoke(arrayLength); 488 for (int i = 0; i < arrayLength; i++) { 489 arrayElemSet.invoke(people, i, createIndexedPersonVcc(i)); 490 } 491 492 for (int i = 0; i < arrayLength; i++) { 493 validateIndexedPersonVcc(arrayElemGet.invoke(people, i), i); 494 495 int id = (int) getIdFromArray.invoke(people, i); 496 assertTrue(id == i, "Invalid field: Id, should be: " + i + " got " + id); 497 String fn = (String) getFnFromArray.invoke(people, i); 498 assertTrue(fn.equals(firstName(i)), "Invalid field: firstName"); 499 String ln = (String) getLnFromArray.invoke(people, i); 500 assertTrue(ln.equals(lastName(i)), "Invalid field: lastName"); 501 } 502 } 503 catch (Throwable t) { 504 fail(testName + " failed", t); 505 } 506 } 507 508 /** 509 * Check forcing GC for combination of VT on stack/LVT etc works 510 */ 511 public static void testOverGc() { 512 try { 513 Class<?> vccClass = PersonVcc.class; 514 ValueType<?> vt = ValueType.forClass(vccClass); 515 Class<?> vtClass = vt.valueClass(); 516 Class<?> arrayClass = vt.arrayValueClass(); 517 518 doGc(); 519 520 // VT on stack and lvt, null refs, see if GC flies 521 MethodHandle moveValueThroughStackAndLvt = MethodHandleBuilder.loadCode( 522 LOOKUP, 523 "gcOverPerson", 524 MethodType.methodType(vccClass, vccClass), 525 CODE->{ 526 CODE 527 .aload(0) 528 .vunbox(vtClass) 529 .invokestatic(ValueOopsMvt.class, "doGc", "()V", false) // Stack 530 .vstore(0) 531 .invokestatic(ValueOopsMvt.class, "doGc", "()V", false) // LVT 532 .vload(0) 533 .iconst_1() // push a litte further down 534 .invokestatic(ValueOopsMvt.class, "doGc", "()V", false) // Stack,LVT 535 .pop() 536 .vbox(vccClass) 537 .areturn(); 538 }); 539 Object obj = moveValueThroughStackAndLvt.invoke(createDefaultPersonVcc()); 540 validateDefaultPersonVcc(obj); 541 doGc(); 542 obj = null; 543 doGc(); 544 545 int index = 4711; 546 obj = moveValueThroughStackAndLvt.invoke(createIndexedPersonVcc(index)); 547 validateIndexedPersonVcc(obj, index); 548 doGc(); 549 obj = null; 550 doGc(); 551 } 552 catch (Throwable t) { fail("testOverGc", t); } 553 } 554 555 static void submitNewWork(ForkJoinPool fjPool, int size) { 556 for (int i = 0; i < size; i++) { 557 fjPool.execute(ValueOopsMvt::testMvtPeopleArray); 558 for (int j = 0; j < 100; j++) { 559 // JDK-8186718 random crashes in interpreter vbox and vunbox (with G1) 560 // test needs refactoring to more specific use cases for debugging. 561 fjPool.execute(ValueOopsMvt::testBytecodes); 562 fjPool.execute(ValueOopsMvt::testMvt); 563 } 564 } 565 } 566 567 static void sleepNoThrow(long ms) { 568 try { 569 Thread.sleep(ms); 570 } 571 catch (Throwable t) {} 572 } 573 574 /** 575 * Run some workloads with different object/value life times... 576 */ 577 public static void testActiveGc() { 578 try { 579 int nofThreads = 7; 580 int workSize = nofThreads * 10; 581 582 Object longLivedObjects = createLongLived(); 583 Object longLivedPeopleVcc = createPeopleVcc(); 584 585 Object medLivedObjects = createLongLived(); 586 Object medLivedPeopleVcc = createPeopleVcc(); 587 588 doGc(); 589 590 ForkJoinPool fjPool = new ForkJoinPool(nofThreads, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); 591 592 // submit work until we see some GC 593 Reference ref = createRef(); 594 submitNewWork(fjPool, workSize); 595 while (ref.get() != null) { 596 if (fjPool.hasQueuedSubmissions()) { 597 sleepNoThrow(1L); 598 } 599 else { 600 workSize *= 2; // Grow the submission size 601 submitNewWork(fjPool, workSize); 602 } 603 } 604 605 // Keep working and actively GC, until MIN_ACTIVE_GC_COUNT 606 int nofActiveGc = 1; 607 ref = createRef(); 608 while (nofActiveGc < MIN_ACTIVE_GC_COUNT) { 609 if (ref.get() == null) { 610 nofActiveGc++; 611 ref = createRef(); 612 if (nofActiveGc % MED_ACTIVE_GC_COUNT == 0) { 613 validateLongLived(medLivedObjects); 614 validatePeopleVcc(medLivedPeopleVcc); 615 616 medLivedObjects = createLongLived(); 617 medLivedPeopleVcc = createPeopleVcc(); 618 } 619 } 620 else if (fjPool.hasQueuedSubmissions()) { 621 sleepNoThrow((long) Utils.getRandomInstance().nextInt(1000)); 622 doGc(); 623 } 624 else { 625 submitNewWork(fjPool, workSize); 626 } 627 } 628 fjPool.shutdown(); 629 630 validateLongLived(medLivedObjects); 631 validatePeopleVcc(medLivedPeopleVcc); 632 medLivedObjects = null; 633 medLivedPeopleVcc = null; 634 635 validateLongLived(longLivedObjects); 636 validatePeopleVcc(longLivedPeopleVcc); 637 638 longLivedObjects = null; 639 longLivedPeopleVcc = null; 640 641 doGc(); 642 } 643 catch (Throwable t) { fail("testMvtActiveGc", t); } 644 } 645 646 static final ReferenceQueue<Object> REFQ = new ReferenceQueue<>(); 647 648 public static void doGc() { 649 // Create Reference, wait until it clears... 650 Reference ref = createRef(); 651 while (ref.get() != null) { 652 System.gc(); 653 } 654 } 655 656 static Reference createRef() { 657 return new WeakReference<Object>(new Object(), REFQ); 658 } 659 660 static void validatePersonVcc(Object obj, int id, String fn, String ln, boolean equals) { 661 assertTrue(obj.getClass() == PersonVcc.class, "Expected VCC class"); 662 PersonVcc person = (PersonVcc) obj; 663 assertTrue(person.id == id); 664 if (equals) { 665 assertTrue(fn.equals(person.getFirstName()), "Invalid field firstName"); 666 assertTrue(ln.equals(person.getLastName()), "Invalid field lastName"); 667 } 668 else { 669 assertTrue(person.getFirstName() == fn, "Invalid field firstName"); 670 assertTrue(person.getLastName() == ln, "Invalid field lastName"); 671 } 672 } 673 674 static PersonVcc createIndexedPersonVcc(int i) { 675 return PersonVcc.create(i, firstName(i), lastName(i)); 676 } 677 678 static void validateIndexedPersonVcc(Object obj, int i) { 679 validatePersonVcc(obj, i, firstName(i), lastName(i), true); 680 } 681 682 static PersonVcc createDefaultPersonVcc() { 683 return PersonVcc.create(0, null, null); 684 } 685 686 static void validateDefaultPersonVcc(Object obj) { 687 validatePersonVcc(obj, 0, null, null, false); 688 } 689 690 static String firstName(int i) { 691 return "FirstName-" + i; 692 } 693 694 static String lastName(int i) { 695 return "LastName-" + i; 696 } 697 698 static Object createLongLived() throws Throwable { 699 Object[] population = new Object[1]; 700 population[0] = createPeopleVcc(); 701 return population; 702 } 703 704 static void validateLongLived(Object pop) throws Throwable { 705 Object[] population = (Object[]) pop; 706 validatePeopleVcc(population[0]); 707 } 708 709 static Object createPeopleVcc() throws Throwable { 710 int arrayLength = NOF_PEOPLE; 711 Class<?> vccClass = PersonVcc.class; 712 ValueType<?> vt = ValueType.forClass(vccClass); 713 MethodHandle arrayElemSet = MethodHandles.arrayElementSetter(vt.arrayValueClass()); 714 715 Object people = vt.newArray().invoke(arrayLength); 716 for (int i = 0; i < arrayLength; i++) { 717 arrayElemSet.invoke(people, i, createIndexedPersonVcc(i)); 718 } 719 return people; 720 } 721 722 static void validatePeopleVcc(Object people) throws Throwable { 723 MethodHandle arrayElemGet = MethodHandles.arrayElementGetter( 724 ValueType.forClass((Class<?>)PersonVcc.class).arrayValueClass()); 725 726 int arrayLength = java.lang.reflect.Array.getLength(people); 727 assertTrue(arrayLength == NOF_PEOPLE); 728 for (int i = 0; i < arrayLength; i++) { 729 validateIndexedPersonVcc(arrayElemGet.invoke(people, i), i); 730 } 731 } 732 733 } 734