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