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