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