1 /* 2 * Copyright (c) 2011, 2015, 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.core.test; 24 25 import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks; 26 import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; 27 import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; 28 import static org.hamcrest.core.IsInstanceOf.instanceOf; 29 import static org.junit.Assert.assertThat; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 import org.junit.Assert; 35 import org.junit.Test; 36 37 import org.graalvm.compiler.api.directives.GraalDirectives; 38 import org.graalvm.compiler.debug.Debug; 39 import org.graalvm.compiler.debug.Debug.Scope; 40 import org.graalvm.compiler.graph.Node; 41 import org.graalvm.compiler.graph.iterators.NodeIterable; 42 import org.graalvm.compiler.nodes.ReturnNode; 43 import org.graalvm.compiler.nodes.StartNode; 44 import org.graalvm.compiler.nodes.StructuredGraph; 45 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 46 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 47 import org.graalvm.compiler.nodes.cfg.Block; 48 import org.graalvm.compiler.nodes.memory.FloatingReadNode; 49 import org.graalvm.compiler.nodes.memory.WriteNode; 50 import org.graalvm.compiler.nodes.spi.LoweringTool; 51 import org.graalvm.compiler.options.OptionValue; 52 import org.graalvm.compiler.options.OptionValue.OverrideScope; 53 import org.graalvm.compiler.phases.OptimisticOptimizations; 54 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 55 import org.graalvm.compiler.phases.common.FloatingReadPhase; 56 import org.graalvm.compiler.phases.common.GuardLoweringPhase; 57 import org.graalvm.compiler.phases.common.LoweringPhase; 58 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; 59 import org.graalvm.compiler.phases.common.inlining.InliningPhase; 60 import org.graalvm.compiler.phases.schedule.SchedulePhase; 61 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 62 import org.graalvm.compiler.phases.tiers.HighTierContext; 63 import org.graalvm.compiler.phases.tiers.MidTierContext; 64 65 /** 66 * In these test the FrameStates are explicitly cleared out, so that the scheduling of 67 * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the 68 * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the 69 * right thing. 70 * 71 * The scheduling shouldn't depend on FrameStates, which is tested by this class. 72 */ 73 public class MemoryScheduleTest extends GraphScheduleTest { 74 75 private enum TestMode { 76 WITH_FRAMESTATES, 77 WITHOUT_FRAMESTATES, 78 INLINED_WITHOUT_FRAMESTATES 79 } 80 81 public static class Container { 82 83 public int a; 84 public int b; 85 public int c; 86 87 public Object obj; 88 } 89 90 private static final Container container = new Container(); 91 private static final List<Container> containerList = new ArrayList<>(); 92 93 /** 94 * In this test the read should be scheduled before the write. 95 */ 96 public static int testSimpleSnippet() { 97 try { 98 return container.a; 99 } finally { 100 container.a = 15; 101 } 102 } 103 104 @Test 105 public void testSimple() { 106 for (TestMode mode : TestMode.values()) { 107 ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode); 108 StructuredGraph graph = schedule.getCFG().graph; 109 assertReadAndWriteInSameBlock(schedule, true); 110 assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first()); 111 } 112 } 113 114 /** 115 * In this case the read should be scheduled in the first block. 116 */ 117 public static int testSplit1Snippet(int a) { 118 try { 119 return container.a; 120 } finally { 121 if (a < 0) { 122 container.a = 15; 123 } else { 124 container.b = 15; 125 } 126 } 127 } 128 129 @Test 130 public void testSplit1() { 131 for (TestMode mode : TestMode.values()) { 132 ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode); 133 assertReadWithinStartBlock(schedule, true); 134 assertReadWithinAllReturnBlocks(schedule, false); 135 } 136 } 137 138 /** 139 * Here the read should float to the end. 140 */ 141 public static int testSplit2Snippet(int a) { 142 try { 143 return container.a; 144 } finally { 145 if (a < 0) { 146 container.c = 15; 147 } else { 148 container.b = 15; 149 } 150 container.obj = null; 151 } 152 } 153 154 @Test 155 public void testSplit2() { 156 ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); 157 assertReadWithinStartBlock(schedule, false); 158 assertReadWithinAllReturnBlocks(schedule, true); 159 } 160 161 /** 162 * Here the read should not float to the end. 163 */ 164 public static int testLoop1Snippet(int a, int b) { 165 try { 166 return container.a; 167 } finally { 168 for (int i = 0; i < a; i++) { 169 if (b < 0) { 170 container.b = 10; 171 } else { 172 container.a = 15; 173 } 174 } 175 } 176 } 177 178 @Test 179 public void testLoop1() { 180 ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); 181 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 182 assertReadWithinStartBlock(schedule, true); 183 assertReadWithinAllReturnBlocks(schedule, false); 184 } 185 186 /** 187 * Here the read should float to the end. 188 */ 189 public static int testLoop2Snippet(int a, int b) { 190 try { 191 return container.a; 192 } finally { 193 for (int i = 0; i < a; i++) { 194 if (b < 0) { 195 container.b = 10; 196 } else { 197 container.c = 15; 198 } 199 } 200 } 201 } 202 203 @Test 204 public void testLoop2() { 205 ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); 206 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 207 assertReadWithinStartBlock(schedule, false); 208 assertReadWithinAllReturnBlocks(schedule, true); 209 } 210 211 /** 212 * Here the read should float out of the loop. 213 */ 214 public static int testLoop3Snippet(int a) { 215 int j = 0; 216 for (int i = 0; i < a; i++) { 217 if (i - container.a == 0) { 218 break; 219 } 220 j++; 221 } 222 return j; 223 } 224 225 @Test 226 public void testLoop3() { 227 ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES); 228 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 229 assertReadWithinStartBlock(schedule, true); 230 assertReadWithinAllReturnBlocks(schedule, false); 231 } 232 233 public String testStringReplaceSnippet(String input) { 234 return input.replace('a', 'b'); 235 } 236 237 @Test 238 public void testStringReplace() { 239 getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); 240 test("testStringReplaceSnippet", "acbaaa"); 241 } 242 243 /** 244 * Here the read should float out of the loop. 245 */ 246 public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) { 247 int ret = 0; 248 int bb = b; 249 for (int i = 0; i < a; i++) { 250 ret = obj.hash; 251 if (a > 10) { 252 bb++; 253 } else { 254 bb--; 255 } 256 ret = ret / 10; 257 } 258 return ret + bb; 259 } 260 261 @Test 262 public void testLoop5() { 263 ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); 264 assertDeepEquals(10, schedule.getCFG().getBlocks().length); 265 assertReadWithinStartBlock(schedule, false); 266 assertReadWithinAllReturnBlocks(schedule, false); 267 } 268 269 /** 270 * Here the read should not float out of the loop. 271 */ 272 public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) { 273 int ret = 0; 274 int bb = b; 275 for (int i = 0; i < a; i++) { 276 ret = obj.hash; 277 if (a > 10) { 278 bb++; 279 } else { 280 bb--; 281 for (int j = 0; j < b; ++j) { 282 obj.hash = 3; 283 } 284 } 285 ret = ret / 10; 286 } 287 return ret + bb; 288 } 289 290 @Test 291 public void testLoop6() { 292 ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES); 293 assertDeepEquals(13, schedule.getCFG().getBlocks().length); 294 assertReadWithinStartBlock(schedule, false); 295 assertReadWithinAllReturnBlocks(schedule, false); 296 } 297 298 /** 299 * Here the read should not float out of the loop. 300 */ 301 public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) { 302 int ret = 0; 303 int bb = b; 304 for (int i = 0; i < a; i++) { 305 ret = obj.hash; 306 if (a > 10) { 307 bb++; 308 } else { 309 bb--; 310 for (int k = 0; k < a; ++k) { 311 if (k % 2 == 1) { 312 for (int j = 0; j < b; ++j) { 313 obj.hash = 3; 314 } 315 } 316 } 317 } 318 ret = ret / 10; 319 } 320 return ret + bb; 321 } 322 323 @Test 324 public void testLoop7() { 325 ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); 326 assertDeepEquals(18, schedule.getCFG().getBlocks().length); 327 assertReadWithinStartBlock(schedule, false); 328 assertReadWithinAllReturnBlocks(schedule, false); 329 } 330 331 /** 332 * Here the read should not float to the end. 333 */ 334 public static int testLoop8Snippet(int a, int b) { 335 int result = container.a; 336 for (int i = 0; i < a; i++) { 337 if (b < 0) { 338 container.b = 10; 339 break; 340 } else { 341 for (int j = 0; j < b; j++) { 342 container.a = 0; 343 } 344 } 345 } 346 GraalDirectives.controlFlowAnchor(); 347 return result; 348 } 349 350 @Test 351 public void testLoop8() { 352 ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES); 353 assertDeepEquals(10, schedule.getCFG().getBlocks().length); 354 assertReadWithinStartBlock(schedule, true); 355 assertReadWithinAllReturnBlocks(schedule, false); 356 } 357 358 /** 359 * Here the read should float after the loop. 360 */ 361 public static int testLoop9Snippet(int a, int b) { 362 container.a = b; 363 for (int i = 0; i < a; i++) { 364 container.a = i; 365 } 366 GraalDirectives.controlFlowAnchor(); 367 return container.a; 368 } 369 370 @Test 371 public void testLoop9() { 372 ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES); 373 StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); 374 assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1)); 375 ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); 376 assertThat(ret.result(), instanceOf(FloatingReadNode.class)); 377 Block readBlock = schedule.getNodeToBlockMap().get(ret.result()); 378 Assert.assertEquals(0, readBlock.getLoopDepth()); 379 } 380 381 /** 382 * Here the read should float to the end (into the same block as the return). 383 */ 384 public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) { 385 System.arraycopy(a, 0, b, 0, len); 386 return intValue.intValue(); 387 } 388 389 @Test 390 public void testArrayCopy() { 391 ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); 392 StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); 393 assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); 394 ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); 395 assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode); 396 assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); 397 assertReadWithinAllReturnBlocks(schedule, true); 398 } 399 400 /** 401 * Here the read should not float to the end. 402 */ 403 public static int testIfRead1Snippet(int a) { 404 int res = container.a; 405 if (a < 0) { 406 container.a = 10; 407 } 408 return res; 409 } 410 411 @Test 412 public void testIfRead1() { 413 ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES); 414 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 415 assertReadWithinStartBlock(schedule, true); 416 assertReadAndWriteInSameBlock(schedule, false); 417 } 418 419 /** 420 * Here the read should float in the else block. 421 */ 422 public static int testIfRead2Snippet(int a) { 423 int res = 0; 424 if (a < 0) { 425 container.a = 10; 426 } else { 427 res = container.a; 428 } 429 return res; 430 } 431 432 @Test 433 public void testIfRead2() { 434 ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES); 435 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 436 assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); 437 assertReadWithinStartBlock(schedule, false); 438 assertReadWithinAllReturnBlocks(schedule, false); 439 assertReadAndWriteInSameBlock(schedule, false); 440 } 441 442 /** 443 * Here the read should float to the end, right before the write. 444 */ 445 public static int testIfRead3Snippet(int a) { 446 if (a < 0) { 447 container.a = 10; 448 } 449 int res = container.a; 450 container.a = 20; 451 return res; 452 } 453 454 @Test 455 public void testIfRead3() { 456 ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); 457 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 458 assertReadWithinStartBlock(schedule, false); 459 assertReadWithinAllReturnBlocks(schedule, true); 460 } 461 462 /** 463 * Here the read should be just in the if branch (with the write). 464 */ 465 public static int testIfRead4Snippet(int a) { 466 if (a > 0) { 467 int res = container.a; 468 container.a = 0x20; 469 return res; 470 } else { 471 return 0x10; 472 } 473 } 474 475 @Test 476 public void testIfRead4() { 477 ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES); 478 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 479 assertReadWithinStartBlock(schedule, false); 480 assertReadWithinAllReturnBlocks(schedule, false); 481 assertReadAndWriteInSameBlock(schedule, true); 482 } 483 484 /** 485 * Here the read should float to the end. 486 */ 487 public static int testIfRead5Snippet(int a) { 488 if (a < 0) { 489 container.a = 10; 490 } 491 return container.a; 492 } 493 494 @Test 495 public void testIfRead5() { 496 ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES); 497 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 498 assertReadWithinStartBlock(schedule, false); 499 assertReadWithinAllReturnBlocks(schedule, true); 500 assertReadAndWriteInSameBlock(schedule, false); 501 } 502 503 public static int testAntiDependencySnippet(int a) { 504 /* 505 * This read must not be scheduled after the following write. 506 */ 507 int res = container.a; 508 container.a = 10; 509 510 /* 511 * Add some more basic blocks. 512 */ 513 if (a < 0) { 514 container.b = 20; 515 } 516 container.c = 30; 517 return res; 518 } 519 520 @Test 521 public void testAntiDependency() { 522 ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES); 523 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 524 assertReadBeforeAllWritesInStartBlock(schedule); 525 } 526 527 /** 528 * testing scheduling within a block. 529 */ 530 public static int testBlockScheduleSnippet() { 531 int res = 0; 532 container.a = 0x00; 533 container.a = 0x10; 534 container.a = 0x20; 535 container.a = 0x30; 536 container.a = 0x40; 537 res = container.a; 538 container.a = 0x50; 539 container.a = 0x60; 540 container.a = 0x70; 541 return res; 542 } 543 544 @Test 545 public void testBlockSchedule() { 546 ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES); 547 StructuredGraph graph = schedule.getCFG().graph; 548 NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class); 549 550 assertDeepEquals(1, schedule.getCFG().getBlocks().length); 551 assertDeepEquals(8, writeNodes.count()); 552 assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count()); 553 554 FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); 555 556 WriteNode[] writes = new WriteNode[8]; 557 int i = 0; 558 for (WriteNode n : writeNodes) { 559 writes[i] = n; 560 i++; 561 } 562 assertOrderedAfterSchedule(schedule, writes[4], read); 563 assertOrderedAfterSchedule(schedule, read, writes[5]); 564 for (int j = 0; j < 7; j++) { 565 assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]); 566 } 567 } 568 569 /** 570 * read should move inside the loop (out of loop is disabled). 571 */ 572 public static int testBlockSchedule2Snippet(int value) { 573 int res = 0; 574 575 container.a = value; 576 for (int i = 0; i < 100; i++) { 577 if (i == 10) { 578 return container.a; 579 } 580 res += i; 581 } 582 return res; 583 } 584 585 @Test 586 public void testBlockSchedule2() { 587 ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST); 588 assertReadWithinStartBlock(schedule, false); 589 assertReadWithinAllReturnBlocks(schedule, false); 590 assertReadAndWriteInSameBlock(schedule, false); 591 } 592 593 public static void testProxySnippet() { 594 while (container.a < container.b) { 595 List<Container> list = new ArrayList<>(containerList); 596 while (container.c < list.size()) { 597 if (container.obj != null) { 598 return; 599 } 600 container.c++; 601 } 602 container.a = 0; 603 container.b--; 604 } 605 container.b++; 606 } 607 608 @Test 609 public void testProxy() { 610 ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES); 611 assertReadWithinStartBlock(schedule, false); 612 assertReadWithinAllReturnBlocks(schedule, false); 613 } 614 615 private int hash = 0; 616 private final char[] value = new char[3]; 617 618 public int testStringHashCodeSnippet() { 619 int h = hash; 620 if (h == 0 && value.length > 0) { 621 char[] val = value; 622 623 for (int i = 0; i < value.length; i++) { 624 h = 31 * h + val[i]; 625 } 626 hash = h; 627 } 628 return h; 629 } 630 631 @Test 632 public void testStringHashCode() { 633 ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES); 634 assertReadWithinStartBlock(schedule, true); 635 assertReadWithinAllReturnBlocks(schedule, false); 636 637 hash = 0x1337; 638 value[0] = 'a'; 639 value[1] = 'b'; 640 value[2] = 'c'; 641 test("testStringHashCodeSnippet"); 642 } 643 644 public static int testLoop4Snippet(int count) { 645 int[] a = new int[count]; 646 647 for (int i = 0; i < a.length; i++) { 648 a[i] = i; 649 } 650 651 int i = 0; 652 int iwrap = count - 1; 653 int sum = 0; 654 655 while (i < count) { 656 sum += (a[i] + a[iwrap]) / 2; 657 iwrap = i; 658 i++; 659 } 660 return sum; 661 } 662 663 @Test 664 public void testLoop4() { 665 ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES); 666 assertReadWithinStartBlock(schedule, false); 667 assertReadWithinAllReturnBlocks(schedule, false); 668 } 669 670 private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) { 671 StructuredGraph graph = schedule.getCFG().graph; 672 assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty()); 673 674 int withRead = 0; 675 int returnBlocks = 0; 676 for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) { 677 Block block = schedule.getCFG().getNodeToBlock().get(returnNode); 678 for (Node node : schedule.getBlockToNodesMap().get(block)) { 679 if (node instanceof FloatingReadNode) { 680 withRead++; 681 break; 682 } 683 } 684 returnBlocks++; 685 } 686 assertDeepEquals(withRead == returnBlocks, withinReturnBlock); 687 } 688 689 private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) { 690 boolean readEncountered = false; 691 for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { 692 if (node instanceof FloatingReadNode) { 693 readEncountered = true; 694 } 695 } 696 assertDeepEquals(withinStartBlock, readEncountered); 697 } 698 699 private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) { 700 StructuredGraph graph = schedule.getCFG().graph; 701 FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); 702 WriteNode write = graph.getNodes().filter(WriteNode.class).first(); 703 assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write))); 704 } 705 706 private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) { 707 boolean writeNodeFound = false; 708 boolean readNodeFound = false; 709 for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) { 710 if (node instanceof FloatingReadNode) { 711 assertTrue(!writeNodeFound); 712 readNodeFound = true; 713 } else if (node instanceof WriteNode) { 714 writeNodeFound = true; 715 } 716 } 717 assertTrue(readNodeFound); 718 } 719 720 private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) { 721 return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS); 722 } 723 724 @SuppressWarnings("try") 725 private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) { 726 final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); 727 try (Scope d = Debug.scope("FloatingReadTest", graph)) { 728 try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) { 729 HighTierContext context = getDefaultHighTierContext(); 730 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); 731 canonicalizer.apply(graph, context); 732 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { 733 new InliningPhase(canonicalizer).apply(graph, context); 734 } 735 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); 736 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { 737 graph.clearAllStateAfter(); 738 } 739 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates"); 740 741 new FloatingReadPhase().apply(graph); 742 new RemoveValueProxyPhase().apply(graph); 743 744 MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); 745 new GuardLoweringPhase().apply(graph, midContext); 746 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); 747 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext); 748 749 SchedulePhase schedule = new SchedulePhase(schedulingStrategy); 750 schedule.apply(graph); 751 assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count()); 752 return graph.getLastSchedule(); 753 } 754 } catch (Throwable e) { 755 throw Debug.handle(e); 756 } 757 } 758 }