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