1 /* 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.hotspot.test; 26 27 import java.util.List; 28 29 import jdk.internal.vm.compiler.collections.EconomicMap; 30 import org.graalvm.compiler.debug.DebugCloseable; 31 import org.graalvm.compiler.debug.DebugContext; 32 import org.graalvm.compiler.debug.DebugContext.Scope; 33 import org.graalvm.compiler.debug.DebugDumpScope; 34 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 35 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier; 36 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier; 37 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; 38 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; 39 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; 40 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; 41 import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; 42 import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase; 43 import org.graalvm.compiler.nodes.AbstractBeginNode; 44 import org.graalvm.compiler.nodes.AbstractMergeNode; 45 import org.graalvm.compiler.nodes.FieldLocationIdentity; 46 import org.graalvm.compiler.nodes.FixedNode; 47 import org.graalvm.compiler.nodes.FixedWithNextNode; 48 import org.graalvm.compiler.nodes.LoopBeginNode; 49 import org.graalvm.compiler.nodes.LoopExitNode; 50 import org.graalvm.compiler.nodes.StructuredGraph; 51 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 52 import org.graalvm.compiler.nodes.memory.WriteNode; 53 import org.graalvm.compiler.nodes.spi.LoweringTool; 54 import org.graalvm.compiler.phases.OptimisticOptimizations; 55 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 56 import org.graalvm.compiler.phases.common.GuardLoweringPhase; 57 import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; 58 import org.graalvm.compiler.phases.common.LoweringPhase; 59 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; 60 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; 61 import org.graalvm.compiler.phases.tiers.HighTierContext; 62 import org.graalvm.compiler.phases.tiers.MidTierContext; 63 import jdk.internal.vm.compiler.word.LocationIdentity; 64 import org.junit.Assert; 65 import org.junit.Test; 66 67 import jdk.vm.ci.meta.ResolvedJavaField; 68 69 /** 70 * The following tests validate the write barrier verification phase. For every tested snippet, an 71 * array of write barrier indices and the total write barrier number are passed as parameters. The 72 * indices denote the barriers that will be manually removed. The write barrier verification phase 73 * runs after the write barrier removal and depending on the result an assertion might be generated. 74 * The tests anticipate the presence or not of an assertion generated by the verification phase. 75 */ 76 public class WriteBarrierVerificationTest extends HotSpotGraalCompilerTest { 77 78 public static int barrierIndex; 79 80 private final GraalHotSpotVMConfig config = runtime().getVMConfig(); 81 82 public static class Container { 83 84 public Container a; 85 public Container b; 86 } 87 88 private static native void safepoint(); 89 90 public static void test1Snippet(Container main) { 91 Container temp1 = new Container(); 92 Container temp2 = new Container(); 93 barrierIndex = 0; 94 safepoint(); 95 barrierIndex = 1; 96 main.a = temp1; 97 safepoint(); 98 barrierIndex = 2; 99 main.b = temp2; 100 safepoint(); 101 } 102 103 @Test(expected = AssertionError.class) 104 public void test1() { 105 test("test1Snippet", 2, new int[]{1}); 106 } 107 108 @Test(expected = AssertionError.class) 109 public void test2() { 110 test("test1Snippet", 2, new int[]{2}); 111 } 112 113 public static void test2Snippet(Container main) { 114 Container temp1 = new Container(); 115 Container temp2 = new Container(); 116 barrierIndex = 0; 117 safepoint(); 118 barrierIndex = 1; 119 main.a = temp1; 120 barrierIndex = 2; 121 main.b = temp2; 122 safepoint(); 123 } 124 125 @Test(expected = AssertionError.class) 126 public void test3() { 127 test("test2Snippet", 2, new int[]{1}); 128 } 129 130 @Test 131 public void test4() { 132 test("test2Snippet", 2, new int[]{2}); 133 } 134 135 public static void test3Snippet(Container main, boolean test) { 136 Container temp1 = new Container(); 137 Container temp2 = new Container(); 138 barrierIndex = 0; 139 safepoint(); 140 for (int i = 0; i < 10; i++) { 141 if (test) { 142 barrierIndex = 1; 143 main.a = temp1; 144 barrierIndex = 2; 145 main.b = temp2; 146 } else { 147 barrierIndex = 3; 148 main.a = temp1; 149 barrierIndex = 4; 150 main.b = temp2; 151 } 152 } 153 } 154 155 @Test(expected = AssertionError.class) 156 public void test5() { 157 test("test3Snippet", 4, new int[]{1, 2}); 158 } 159 160 @Test(expected = AssertionError.class) 161 public void test6() { 162 test("test3Snippet", 4, new int[]{3, 4}); 163 } 164 165 @Test(expected = AssertionError.class) 166 public void test7() { 167 test("test3Snippet", 4, new int[]{1}); 168 } 169 170 @Test 171 public void test8() { 172 test("test3Snippet", 4, new int[]{2}); 173 } 174 175 @Test(expected = AssertionError.class) 176 public void test9() { 177 test("test3Snippet", 4, new int[]{3}); 178 } 179 180 @Test 181 public void test10() { 182 test("test3Snippet", 4, new int[]{4}); 183 } 184 185 public static void test4Snippet(Container main, boolean test) { 186 Container temp1 = new Container(); 187 Container temp2 = new Container(); 188 safepoint(); 189 barrierIndex = 1; 190 main.a = temp1; 191 for (int i = 0; i < 10; i++) { 192 if (test) { 193 barrierIndex = 2; 194 main.a = temp1; 195 barrierIndex = 3; 196 main.b = temp2; 197 } else { 198 barrierIndex = 4; 199 main.a = temp2; 200 barrierIndex = 5; 201 main.b = temp1; 202 } 203 } 204 } 205 206 @Test(expected = AssertionError.class) 207 public void test11() { 208 test("test4Snippet", 5, new int[]{2, 3}); 209 } 210 211 @Test(expected = AssertionError.class) 212 public void test12() { 213 test("test4Snippet", 5, new int[]{4, 5}); 214 } 215 216 @Test(expected = AssertionError.class) 217 public void test13() { 218 test("test4Snippet", 5, new int[]{1}); 219 } 220 221 public static void test5Snippet(Container main) { 222 Container temp1 = new Container(); 223 Container temp2 = new Container(); 224 safepoint(); 225 barrierIndex = 1; 226 main.a = temp1; 227 if (main.a == main.b) { 228 barrierIndex = 2; 229 main.a = temp1; 230 barrierIndex = 3; 231 main.b = temp2; 232 } else { 233 barrierIndex = 4; 234 main.a = temp2; 235 barrierIndex = 5; 236 main.b = temp1; 237 } 238 safepoint(); 239 } 240 241 @Test(expected = AssertionError.class) 242 public void test14() { 243 test("test5Snippet", 5, new int[]{1}); 244 } 245 246 @Test 247 public void test15() { 248 test("test5Snippet", 5, new int[]{2}); 249 } 250 251 @Test 252 public void test16() { 253 test("test5Snippet", 5, new int[]{4}); 254 } 255 256 @Test 257 public void test17() { 258 test("test5Snippet", 5, new int[]{3}); 259 } 260 261 @Test 262 public void test18() { 263 test("test5Snippet", 5, new int[]{5}); 264 } 265 266 @Test 267 public void test19() { 268 test("test5Snippet", 5, new int[]{2, 3}); 269 } 270 271 @Test 272 public void test20() { 273 test("test5Snippet", 5, new int[]{4, 5}); 274 } 275 276 public static void test6Snippet(Container main, boolean test) { 277 Container temp1 = new Container(); 278 Container temp2 = new Container(); 279 safepoint(); 280 barrierIndex = 1; 281 main.a = temp1; 282 if (test) { 283 barrierIndex = 2; 284 main.a = temp1; 285 barrierIndex = 3; 286 main.b = temp1.a.a; 287 } else { 288 barrierIndex = 4; 289 main.a = temp2; 290 barrierIndex = 5; 291 main.b = temp2.a.a; 292 } 293 safepoint(); 294 } 295 296 @Test(expected = AssertionError.class) 297 public void test21() { 298 test("test6Snippet", 5, new int[]{1}); 299 } 300 301 @Test(expected = AssertionError.class) 302 public void test22() { 303 test("test6Snippet", 5, new int[]{1, 2}); 304 } 305 306 @Test 307 public void test23() { 308 test("test6Snippet", 5, new int[]{3}); 309 } 310 311 @Test 312 public void test24() { 313 test("test6Snippet", 5, new int[]{4}); 314 } 315 316 public static void test7Snippet(Container main, boolean test) { 317 Container temp1 = new Container(); 318 Container temp2 = new Container(); 319 safepoint(); 320 barrierIndex = 1; 321 main.a = temp1; 322 if (test) { 323 barrierIndex = 2; 324 main.a = temp1; 325 } 326 barrierIndex = 3; 327 main.b = temp2; 328 safepoint(); 329 } 330 331 @Test 332 public void test25() { 333 test("test7Snippet", 3, new int[]{2}); 334 } 335 336 @Test 337 public void test26() { 338 test("test7Snippet", 3, new int[]{3}); 339 } 340 341 @Test 342 public void test27() { 343 test("test7Snippet", 3, new int[]{2, 3}); 344 } 345 346 @Test(expected = AssertionError.class) 347 public void test28() { 348 test("test7Snippet", 3, new int[]{1}); 349 } 350 351 public static void test8Snippet(Container main, boolean test) { 352 Container temp1 = new Container(); 353 Container temp2 = new Container(); 354 safepoint(); 355 if (test) { 356 barrierIndex = 1; 357 main.a = temp1; 358 } 359 barrierIndex = 2; 360 main.b = temp2; 361 safepoint(); 362 } 363 364 @Test(expected = AssertionError.class) 365 public void test29() { 366 test("test8Snippet", 2, new int[]{1}); 367 } 368 369 @Test(expected = AssertionError.class) 370 public void test30() { 371 test("test8Snippet", 2, new int[]{2}); 372 } 373 374 @Test(expected = AssertionError.class) 375 public void test31() { 376 test("test8Snippet", 2, new int[]{1, 2}); 377 } 378 379 public static void test9Snippet(Container main1, Container main2, boolean test) { 380 Container temp1 = new Container(); 381 Container temp2 = new Container(); 382 safepoint(); 383 if (test) { 384 barrierIndex = 1; 385 main1.a = temp1; 386 } else { 387 barrierIndex = 2; 388 main2.a = temp1; 389 } 390 barrierIndex = 3; 391 main1.b = temp2; 392 barrierIndex = 4; 393 main2.b = temp2; 394 safepoint(); 395 } 396 397 @Test(expected = AssertionError.class) 398 public void test32() { 399 test("test9Snippet", 4, new int[]{1}); 400 } 401 402 @Test(expected = AssertionError.class) 403 public void test33() { 404 test("test9Snippet", 4, new int[]{2}); 405 } 406 407 @Test(expected = AssertionError.class) 408 public void test34() { 409 test("test9Snippet", 4, new int[]{3}); 410 } 411 412 @Test(expected = AssertionError.class) 413 public void test35() { 414 test("test9Snippet", 4, new int[]{4}); 415 } 416 417 @Test(expected = AssertionError.class) 418 public void test36() { 419 test("test9Snippet", 4, new int[]{1, 2}); 420 } 421 422 @Test(expected = AssertionError.class) 423 public void test37() { 424 test("test9Snippet", 4, new int[]{3, 4}); 425 } 426 427 public static void test10Snippet(Container main1, Container main2, boolean test) { 428 Container temp1 = new Container(); 429 Container temp2 = new Container(); 430 safepoint(); 431 if (test) { 432 barrierIndex = 1; 433 main1.a = temp1; 434 barrierIndex = 2; 435 main2.a = temp2; 436 } else { 437 barrierIndex = 3; 438 main2.a = temp1; 439 } 440 barrierIndex = 4; 441 main1.b = temp2; 442 barrierIndex = 5; 443 main2.b = temp2; 444 safepoint(); 445 } 446 447 @Test(expected = AssertionError.class) 448 public void test38() { 449 test("test10Snippet", 5, new int[]{1}); 450 } 451 452 @Test(expected = AssertionError.class) 453 public void test39() { 454 test("test10Snippet", 5, new int[]{2}); 455 } 456 457 @Test(expected = AssertionError.class) 458 public void test40() { 459 test("test10Snippet", 5, new int[]{3}); 460 } 461 462 @Test(expected = AssertionError.class) 463 public void test41() { 464 test("test10Snippet", 5, new int[]{4}); 465 } 466 467 @Test 468 public void test42() { 469 test("test10Snippet", 5, new int[]{5}); 470 } 471 472 @Test(expected = AssertionError.class) 473 public void test43() { 474 test("test10Snippet", 5, new int[]{1, 2}); 475 } 476 477 @Test(expected = AssertionError.class) 478 public void test44() { 479 test("test10Snippet", 5, new int[]{1, 2, 3}); 480 } 481 482 @Test(expected = AssertionError.class) 483 public void test45() { 484 test("test10Snippet", 5, new int[]{3, 4}); 485 } 486 487 public static void test11Snippet(Container main1, Container main2, Container main3, boolean test) { 488 Container temp1 = new Container(); 489 Container temp2 = new Container(); 490 safepoint(); 491 if (test) { 492 barrierIndex = 1; 493 main1.a = temp1; 494 barrierIndex = 2; 495 main3.a = temp1; 496 if (!test) { 497 barrierIndex = 3; 498 main2.a = temp2; 499 } else { 500 barrierIndex = 4; 501 main1.a = temp2; 502 barrierIndex = 5; 503 main3.a = temp2; 504 } 505 } else { 506 barrierIndex = 6; 507 main1.b = temp2; 508 for (int i = 0; i < 10; i++) { 509 barrierIndex = 7; 510 main3.a = temp1; 511 } 512 barrierIndex = 8; 513 main3.b = temp2; 514 } 515 barrierIndex = 9; 516 main1.b = temp2; 517 barrierIndex = 10; 518 main2.b = temp2; 519 barrierIndex = 11; 520 main3.b = temp2; 521 safepoint(); 522 } 523 524 @Test(expected = AssertionError.class) 525 public void test46() { 526 test("test11Snippet", 11, new int[]{1}); 527 } 528 529 @Test(expected = AssertionError.class) 530 public void test47() { 531 test("test11Snippet", 11, new int[]{2}); 532 } 533 534 @Test(expected = AssertionError.class) 535 public void test48() { 536 test("test11Snippet", 11, new int[]{3}); 537 } 538 539 @Test(expected = AssertionError.class) 540 public void test49() { 541 test("test11Snippet", 11, new int[]{6}); 542 } 543 544 @Test(expected = AssertionError.class) 545 public void test50() { 546 test("test11Snippet", 11, new int[]{7}); 547 } 548 549 @Test(expected = AssertionError.class) 550 public void test51() { 551 test("test11Snippet", 11, new int[]{8}); 552 } 553 554 @Test(expected = AssertionError.class) 555 public void test52() { 556 test("test11Snippet", 11, new int[]{9}); 557 } 558 559 @Test(expected = AssertionError.class) 560 public void test53() { 561 test("test11Snippet", 11, new int[]{10}); 562 } 563 564 @Test 565 public void test54() { 566 test("test11Snippet", 11, new int[]{4}); 567 } 568 569 @Test 570 public void test55() { 571 test("test11Snippet", 11, new int[]{5}); 572 } 573 574 @Test 575 public void test56() { 576 test("test11Snippet", 11, new int[]{11}); 577 } 578 579 public static void test12Snippet(Container main, Container main1, boolean test) { 580 Container temp1 = new Container(); 581 Container temp2 = new Container(); 582 barrierIndex = 0; 583 safepoint(); 584 barrierIndex = 7; 585 main1.a = temp1; 586 for (int i = 0; i < 10; i++) { 587 if (test) { 588 barrierIndex = 1; 589 main.a = temp1; 590 barrierIndex = 2; 591 main.b = temp2; 592 } else { 593 barrierIndex = 3; 594 main.a = temp1; 595 barrierIndex = 4; 596 main.b = temp2; 597 } 598 } 599 barrierIndex = 5; 600 main.a = temp1; 601 barrierIndex = 6; 602 main.b = temp1; 603 barrierIndex = 8; 604 main1.b = temp1; 605 safepoint(); 606 } 607 608 @Test(expected = AssertionError.class) 609 public void test57() { 610 test("test12Snippet", 8, new int[]{5}); 611 } 612 613 @Test 614 public void test58() { 615 test("test12Snippet", 8, new int[]{6}); 616 } 617 618 @Test(expected = AssertionError.class) 619 public void test59() { 620 test("test12Snippet", 8, new int[]{7}); 621 } 622 623 @Test(expected = AssertionError.class) 624 public void test60() { 625 test("test12Snippet", 8, new int[]{8}); 626 } 627 628 public static void test13Snippet(Object[] a, Object[] b) { 629 System.arraycopy(a, 0, b, 0, a.length); 630 } 631 632 private interface GraphPredicate { 633 int apply(StructuredGraph graph); 634 } 635 636 private void test(final String snippet, final int expectedBarriers, final int... removedBarrierIndices) { 637 GraphPredicate noCheck = noArg -> expectedBarriers; 638 testPredicate(snippet, noCheck, removedBarrierIndices); 639 } 640 641 @SuppressWarnings("try") 642 private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) { 643 DebugContext debug = getDebugContext(); 644 try (DebugCloseable d = debug.disableIntercept(); DebugContext.Scope s = debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) { 645 final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES, debug); 646 HighTierContext highTierContext = getDefaultHighTierContext(); 647 createInliningPhase().apply(graph, highTierContext); 648 649 MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); 650 651 new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext); 652 new GuardLoweringPhase().apply(graph, midTierContext); 653 new LoopSafepointInsertionPhase().apply(graph); 654 new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, highTierContext); 655 656 new WriteBarrierAdditionPhase(config).apply(graph); 657 658 int barriers = 0; 659 // First, the total number of expected barriers is checked. 660 if (config.useG1GC) { 661 barriers = graph.getNodes().filter(G1PreWriteBarrier.class).count() + graph.getNodes().filter(G1PostWriteBarrier.class).count() + 662 graph.getNodes().filter(G1ArrayRangePreWriteBarrier.class).count() + graph.getNodes().filter(G1ArrayRangePostWriteBarrier.class).count(); 663 Assert.assertTrue(expectedBarriers.apply(graph) * 2 == barriers); 664 } else { 665 barriers = graph.getNodes().filter(SerialWriteBarrier.class).count() + graph.getNodes().filter(SerialArrayRangeWriteBarrier.class).count(); 666 Assert.assertTrue(expectedBarriers.apply(graph) == barriers); 667 } 668 ResolvedJavaField barrierIndexField = getMetaAccess().lookupJavaField(WriteBarrierVerificationTest.class.getDeclaredField("barrierIndex")); 669 LocationIdentity barrierIdentity = new FieldLocationIdentity(barrierIndexField); 670 // Iterate over all write nodes and remove barriers according to input indices. 671 NodeIteratorClosure<Boolean> closure = new NodeIteratorClosure<Boolean>() { 672 673 @Override 674 protected Boolean processNode(FixedNode node, Boolean currentState) { 675 if (node instanceof WriteNode) { 676 WriteNode write = (WriteNode) node; 677 LocationIdentity obj = write.getLocationIdentity(); 678 if (obj.equals(barrierIdentity)) { 679 /* 680 * A "barrierIndex" variable was found and is checked against the input 681 * barrier array. 682 */ 683 if (eliminateBarrier(write.value().asJavaConstant().asInt(), removedBarrierIndices)) { 684 return true; 685 } 686 } 687 } else if (node instanceof SerialWriteBarrier || node instanceof G1PostWriteBarrier) { 688 // Remove flagged write barriers. 689 if (currentState) { 690 graph.removeFixed(((FixedWithNextNode) node)); 691 return false; 692 } 693 } 694 return currentState; 695 } 696 697 private boolean eliminateBarrier(int index, int[] map) { 698 for (int i = 0; i < map.length; i++) { 699 if (map[i] == index) { 700 return true; 701 } 702 } 703 return false; 704 } 705 706 @Override 707 protected EconomicMap<LoopExitNode, Boolean> processLoop(LoopBeginNode loop, Boolean initialState) { 708 return ReentrantNodeIterator.processLoop(this, loop, initialState).exitStates; 709 } 710 711 @Override 712 protected Boolean merge(AbstractMergeNode merge, List<Boolean> states) { 713 return false; 714 } 715 716 @Override 717 protected Boolean afterSplit(AbstractBeginNode node, Boolean oldState) { 718 return false; 719 } 720 }; 721 722 try (Scope disabled = debug.disable()) { 723 ReentrantNodeIterator.apply(closure, graph.start(), false); 724 new WriteBarrierVerificationPhase(config).apply(graph); 725 } catch (AssertionError error) { 726 /* 727 * Catch assertion, test for expected one and re-throw in order to validate unit 728 * test. 729 */ 730 Assert.assertTrue(error.getMessage().contains("Write barrier must be present")); 731 throw error; 732 } 733 } catch (Throwable e) { 734 throw debug.handle(e); 735 } 736 } 737 }