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