1 /* 2 * Copyright (c) 2011, 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.core.test; 24 25 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintCompilation; 26 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; 27 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; 28 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION; 29 30 import java.lang.annotation.ElementType; 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.lang.annotation.Target; 34 import java.lang.reflect.InvocationTargetException; 35 import java.lang.reflect.Method; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.Collections; 39 import java.util.EnumMap; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.ListIterator; 43 import java.util.Map; 44 import java.util.Set; 45 import java.util.function.Supplier; 46 47 import org.junit.After; 48 import org.junit.Assert; 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.internal.AssumptionViolatedException; 52 53 import org.graalvm.compiler.api.directives.GraalDirectives; 54 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 55 import org.graalvm.compiler.api.test.Graal; 56 import org.graalvm.compiler.code.CompilationResult; 57 import org.graalvm.compiler.core.GraalCompiler; 58 import org.graalvm.compiler.core.GraalCompiler.Request; 59 import org.graalvm.compiler.core.common.CompilationIdentifier; 60 import org.graalvm.compiler.core.common.type.StampFactory; 61 import org.graalvm.compiler.core.target.Backend; 62 import org.graalvm.compiler.debug.Debug; 63 import org.graalvm.compiler.debug.Debug.Scope; 64 import org.graalvm.compiler.debug.DebugDumpScope; 65 import org.graalvm.compiler.debug.GraalError; 66 import org.graalvm.compiler.debug.TTY; 67 import org.graalvm.compiler.graph.Node; 68 import org.graalvm.compiler.graph.NodeClass; 69 import org.graalvm.compiler.graph.NodeMap; 70 import org.graalvm.compiler.java.BytecodeParser; 71 import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure; 72 import org.graalvm.compiler.java.GraphBuilderPhase; 73 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 74 import org.graalvm.compiler.lir.phases.LIRSuites; 75 import org.graalvm.compiler.nodeinfo.NodeInfo; 76 import org.graalvm.compiler.nodeinfo.NodeSize; 77 import org.graalvm.compiler.nodeinfo.Verbosity; 78 import org.graalvm.compiler.nodes.BreakpointNode; 79 import org.graalvm.compiler.nodes.ConstantNode; 80 import org.graalvm.compiler.nodes.FixedWithNextNode; 81 import org.graalvm.compiler.nodes.FrameState; 82 import org.graalvm.compiler.nodes.FullInfopointNode; 83 import org.graalvm.compiler.nodes.InvokeNode; 84 import org.graalvm.compiler.nodes.InvokeWithExceptionNode; 85 import org.graalvm.compiler.nodes.ProxyNode; 86 import org.graalvm.compiler.nodes.ReturnNode; 87 import org.graalvm.compiler.nodes.StructuredGraph; 88 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 89 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 90 import org.graalvm.compiler.nodes.ValueNode; 91 import org.graalvm.compiler.nodes.cfg.Block; 92 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 93 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; 94 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 95 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 96 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 97 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 98 import org.graalvm.compiler.nodes.spi.LoweringProvider; 99 import org.graalvm.compiler.nodes.spi.Replacements; 100 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 101 import org.graalvm.compiler.options.DerivedOptionValue; 102 import org.graalvm.compiler.phases.BasePhase; 103 import org.graalvm.compiler.phases.OptimisticOptimizations; 104 import org.graalvm.compiler.phases.Phase; 105 import org.graalvm.compiler.phases.PhaseSuite; 106 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 107 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; 108 import org.graalvm.compiler.phases.schedule.SchedulePhase; 109 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 110 import org.graalvm.compiler.phases.tiers.HighTierContext; 111 import org.graalvm.compiler.phases.tiers.Suites; 112 import org.graalvm.compiler.phases.tiers.TargetProvider; 113 import org.graalvm.compiler.phases.util.Providers; 114 import org.graalvm.compiler.runtime.RuntimeProvider; 115 import org.graalvm.compiler.test.GraalTest; 116 117 import jdk.vm.ci.code.Architecture; 118 import jdk.vm.ci.code.CodeCacheProvider; 119 import jdk.vm.ci.code.InstalledCode; 120 import jdk.vm.ci.code.TargetDescription; 121 import jdk.vm.ci.meta.ConstantReflectionProvider; 122 import jdk.vm.ci.meta.DeoptimizationReason; 123 import jdk.vm.ci.meta.JavaKind; 124 import jdk.vm.ci.meta.JavaType; 125 import jdk.vm.ci.meta.MetaAccessProvider; 126 import jdk.vm.ci.meta.ProfilingInfo; 127 import jdk.vm.ci.meta.ResolvedJavaMethod; 128 import jdk.vm.ci.meta.ResolvedJavaType; 129 import jdk.vm.ci.meta.SpeculationLog; 130 131 /** 132 * Base class for Graal compiler unit tests. 133 * <p> 134 * White box tests for Graal compiler transformations use this pattern: 135 * <ol> 136 * <li>Create a graph by {@linkplain #parseEager(String, AllowAssumptions) parsing} a method.</li> 137 * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li> 138 * <li>Apply a transformation to the graph.</li> 139 * <li>Assert that the transformed graph is equal to an expected graph.</li> 140 * </ol> 141 * <p> 142 * See {@link InvokeHintsTest} as an example of a white box test. 143 * <p> 144 * Black box tests use the {@link #test(String, Object...)} or 145 * {@link #testN(int, String, Object...)} to execute some method in the interpreter and compare its 146 * result against that produced by a Graal compiled version of the method. 147 * <p> 148 * These tests will be run by the {@code mx unittest} command. 149 */ 150 public abstract class GraalCompilerTest extends GraalTest { 151 152 private final Providers providers; 153 private final Backend backend; 154 private final DerivedOptionValue<Suites> suites; 155 private final DerivedOptionValue<LIRSuites> lirSuites; 156 157 /** 158 * Denotes a test method that must be inlined by the {@link BytecodeParser}. 159 */ 160 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) 161 @Retention(RetentionPolicy.RUNTIME) 162 public @interface BytecodeParserForceInline { 163 } 164 165 /** 166 * Denotes a test method that must never be inlined by the {@link BytecodeParser}. 167 */ 168 @Retention(RetentionPolicy.RUNTIME) 169 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) 170 public @interface BytecodeParserNeverInline { 171 /** 172 * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead 173 * of {@link InvokeNode}. 174 */ 175 boolean invokeWithException() default false; 176 } 177 178 /** 179 * Can be overridden by unit tests to verify properties of the graph. 180 * 181 * @param graph the graph at the end of HighTier 182 */ 183 protected boolean checkHighTierGraph(StructuredGraph graph) { 184 return true; 185 } 186 187 /** 188 * Can be overridden by unit tests to verify properties of the graph. 189 * 190 * @param graph the graph at the end of MidTier 191 */ 192 protected boolean checkMidTierGraph(StructuredGraph graph) { 193 return true; 194 } 195 196 /** 197 * Can be overridden by unit tests to verify properties of the graph. 198 * 199 * @param graph the graph at the end of LowTier 200 */ 201 protected boolean checkLowTierGraph(StructuredGraph graph) { 202 return true; 203 } 204 205 protected static void breakpoint() { 206 } 207 208 @SuppressWarnings("unused") 209 protected static void breakpoint(int arg0) { 210 } 211 212 protected static void shouldBeOptimizedAway() { 213 } 214 215 protected Suites createSuites() { 216 Suites ret = backend.getSuites().getDefaultSuites().copy(); 217 ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true); 218 if (iter == null) { 219 /* 220 * in the economy configuration, we don't have the ConvertDeoptimizeToGuard phase, so we 221 * just select the first CanonicalizerPhase in HighTier 222 */ 223 iter = ret.getHighTier().findPhase(CanonicalizerPhase.class); 224 } 225 iter.add(new Phase() { 226 227 @Override 228 protected void run(StructuredGraph graph) { 229 ComputeLoopFrequenciesClosure.compute(graph); 230 } 231 232 @Override 233 public float codeSizeIncrease() { 234 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; 235 } 236 237 @Override 238 protected CharSequence getName() { 239 return "ComputeLoopFrequenciesPhase"; 240 } 241 }); 242 ret.getHighTier().appendPhase(new Phase() { 243 244 @Override 245 protected void run(StructuredGraph graph) { 246 assert checkHighTierGraph(graph) : "failed HighTier graph check"; 247 } 248 249 @Override 250 public float codeSizeIncrease() { 251 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; 252 } 253 254 @Override 255 protected CharSequence getName() { 256 return "CheckGraphPhase"; 257 } 258 }); 259 ret.getMidTier().appendPhase(new Phase() { 260 261 @Override 262 protected void run(StructuredGraph graph) { 263 assert checkMidTierGraph(graph) : "failed MidTier graph check"; 264 } 265 266 @Override 267 public float codeSizeIncrease() { 268 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; 269 } 270 271 @Override 272 protected CharSequence getName() { 273 return "CheckGraphPhase"; 274 } 275 }); 276 ret.getLowTier().appendPhase(new Phase() { 277 278 @Override 279 protected void run(StructuredGraph graph) { 280 assert checkLowTierGraph(graph) : "failed LowTier graph check"; 281 } 282 283 @Override 284 public float codeSizeIncrease() { 285 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR; 286 } 287 288 @Override 289 protected CharSequence getName() { 290 return "CheckGraphPhase"; 291 } 292 }); 293 return ret; 294 } 295 296 protected LIRSuites createLIRSuites() { 297 LIRSuites ret = backend.getSuites().getDefaultLIRSuites().copy(); 298 return ret; 299 } 300 301 public GraalCompilerTest() { 302 this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); 303 this.providers = getBackend().getProviders(); 304 this.suites = new DerivedOptionValue<>(this::createSuites); 305 this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); 306 } 307 308 /** 309 * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} ) 310 * whether the desired backend is available. 311 * 312 * @param arch the name of the desired backend architecture 313 */ 314 public GraalCompilerTest(Class<? extends Architecture> arch) { 315 RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class); 316 Backend b = runtime.getBackend(arch); 317 if (b != null) { 318 this.backend = b; 319 } else { 320 // Fall back to the default/host backend 321 this.backend = runtime.getHostBackend(); 322 } 323 this.providers = backend.getProviders(); 324 this.suites = new DerivedOptionValue<>(this::createSuites); 325 this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); 326 } 327 328 /** 329 * Set up a test for a non-default backend. 330 * 331 * @param backend the desired backend 332 */ 333 public GraalCompilerTest(Backend backend) { 334 this.backend = backend; 335 this.providers = backend.getProviders(); 336 this.suites = new DerivedOptionValue<>(this::createSuites); 337 this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites); 338 } 339 340 private Scope debugScope; 341 342 @Before 343 public void beforeTest() { 344 assert debugScope == null; 345 debugScope = Debug.scope(getClass()); 346 } 347 348 @After 349 public void afterTest() { 350 if (debugScope != null) { 351 debugScope.close(); 352 } 353 debugScope = null; 354 } 355 356 protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { 357 assertEquals(expected, graph, false, true); 358 } 359 360 protected int countUnusedConstants(StructuredGraph graph) { 361 int total = 0; 362 for (ConstantNode node : getConstantNodes(graph)) { 363 if (node.hasNoUsages()) { 364 total++; 365 } 366 } 367 return total; 368 } 369 370 protected int getNodeCountExcludingUnusedConstants(StructuredGraph graph) { 371 return graph.getNodeCount() - countUnusedConstants(graph); 372 } 373 374 protected void assertEquals(StructuredGraph expected, StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { 375 String expectedString = getCanonicalGraphString(expected, excludeVirtual, checkConstants); 376 String actualString = getCanonicalGraphString(graph, excludeVirtual, checkConstants); 377 String mismatchString = compareGraphStrings(expected, expectedString, graph, actualString); 378 379 if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) { 380 Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "Node count not matching - expected"); 381 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Node count not matching - actual"); 382 Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); 383 } 384 if (!expectedString.equals(actualString)) { 385 Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "mismatching graphs - expected"); 386 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "mismatching graphs - actual"); 387 Assert.fail(mismatchString); 388 } 389 } 390 391 private static String compareGraphStrings(StructuredGraph expectedGraph, String expectedString, StructuredGraph actualGraph, String actualString) { 392 if (!expectedString.equals(actualString)) { 393 String[] expectedLines = expectedString.split("\n"); 394 String[] actualLines = actualString.split("\n"); 395 int diffIndex = -1; 396 int limit = Math.min(actualLines.length, expectedLines.length); 397 String marker = " <<<"; 398 for (int i = 0; i < limit; i++) { 399 if (!expectedLines[i].equals(actualLines[i])) { 400 diffIndex = i; 401 break; 402 } 403 } 404 if (diffIndex == -1) { 405 // Prefix is the same so add some space after the prefix 406 diffIndex = limit; 407 if (actualLines.length == limit) { 408 actualLines = Arrays.copyOf(actualLines, limit + 1); 409 actualLines[diffIndex] = ""; 410 } else { 411 assert expectedLines.length == limit; 412 expectedLines = Arrays.copyOf(expectedLines, limit + 1); 413 expectedLines[diffIndex] = ""; 414 } 415 } 416 // Place a marker next to the first line that differs 417 expectedLines[diffIndex] = expectedLines[diffIndex] + marker; 418 actualLines[diffIndex] = actualLines[diffIndex] + marker; 419 String ediff = String.join("\n", expectedLines); 420 String adiff = String.join("\n", actualLines); 421 return "mismatch in graphs:\n========= expected (" + expectedGraph + ") =========\n" + ediff + "\n\n========= actual (" + actualGraph + ") =========\n" + adiff; 422 } else { 423 return "mismatch in graphs"; 424 } 425 } 426 427 protected void assertOptimizedAway(StructuredGraph g) { 428 Assert.assertEquals(0, g.getNodes().filter(NotOptimizedNode.class).count()); 429 } 430 431 protected void assertConstantReturn(StructuredGraph graph, int value) { 432 String graphString = getCanonicalGraphString(graph, false, true); 433 Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.TYPE).count(), 1); 434 ValueNode result = graph.getNodes(ReturnNode.TYPE).first().result(); 435 Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant()); 436 Assert.assertEquals("unexpected ReturnNode result kind: " + graphString, result.asJavaConstant().getJavaKind(), JavaKind.Int); 437 Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asJavaConstant().asInt(), value); 438 } 439 440 protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { 441 SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); 442 schedule.apply(graph); 443 ScheduleResult scheduleResult = graph.getLastSchedule(); 444 445 NodeMap<Integer> canonicalId = graph.createNodeMap(); 446 int nextId = 0; 447 448 List<String> constantsLines = new ArrayList<>(); 449 450 StringBuilder result = new StringBuilder(); 451 for (Block block : scheduleResult.getCFG().getBlocks()) { 452 result.append("Block " + block + " "); 453 if (block == scheduleResult.getCFG().getStartBlock()) { 454 result.append("* "); 455 } 456 result.append("-> "); 457 for (Block succ : block.getSuccessors()) { 458 result.append(succ + " "); 459 } 460 result.append("\n"); 461 for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { 462 if (node instanceof ValueNode && node.isAlive()) { 463 if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) { 464 if (node instanceof ConstantNode) { 465 String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); 466 String str = name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); 467 constantsLines.add(str); 468 } else { 469 int id; 470 if (canonicalId.get(node) != null) { 471 id = canonicalId.get(node); 472 } else { 473 id = nextId++; 474 canonicalId.set(node, id); 475 } 476 String name = node.getClass().getSimpleName(); 477 String str = " " + id + "|" + name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); 478 result.append(str); 479 } 480 } 481 } 482 } 483 } 484 485 StringBuilder constantsLinesResult = new StringBuilder(); 486 constantsLinesResult.append(constantsLines.size() + " constants:\n"); 487 Collections.sort(constantsLines); 488 for (String s : constantsLines) { 489 constantsLinesResult.append(s); 490 constantsLinesResult.append("\n"); 491 } 492 493 return constantsLines.toString() + result.toString(); 494 } 495 496 /** 497 * @return usage count excluding {@link FrameState} usages 498 */ 499 private static int filteredUsageCount(Node node) { 500 return node.usages().filter(n -> !(n instanceof FrameState)).count(); 501 } 502 503 /** 504 * @param graph 505 * @return a scheduled textual dump of {@code graph} . 506 */ 507 protected static String getScheduledGraphString(StructuredGraph graph) { 508 SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); 509 schedule.apply(graph); 510 ScheduleResult scheduleResult = graph.getLastSchedule(); 511 512 StringBuilder result = new StringBuilder(); 513 Block[] blocks = scheduleResult.getCFG().getBlocks(); 514 for (Block block : blocks) { 515 result.append("Block " + block + " "); 516 if (block == scheduleResult.getCFG().getStartBlock()) { 517 result.append("* "); 518 } 519 result.append("-> "); 520 for (Block succ : block.getSuccessors()) { 521 result.append(succ + " "); 522 } 523 result.append("\n"); 524 for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { 525 result.append(String.format("%1S\n", node)); 526 } 527 } 528 return result.toString(); 529 } 530 531 protected Backend getBackend() { 532 return backend; 533 } 534 535 protected Suites getSuites() { 536 return suites.getValue(); 537 } 538 539 protected LIRSuites getLIRSuites() { 540 return lirSuites.getValue(); 541 } 542 543 protected final Providers getProviders() { 544 return providers; 545 } 546 547 protected HighTierContext getDefaultHighTierContext() { 548 return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); 549 } 550 551 protected SnippetReflectionProvider getSnippetReflection() { 552 return Graal.getRequiredCapability(SnippetReflectionProvider.class); 553 } 554 555 protected TargetDescription getTarget() { 556 return getTargetProvider().getTarget(); 557 } 558 559 protected TargetProvider getTargetProvider() { 560 return getBackend(); 561 } 562 563 protected CodeCacheProvider getCodeCache() { 564 return getProviders().getCodeCache(); 565 } 566 567 protected ConstantReflectionProvider getConstantReflection() { 568 return getProviders().getConstantReflection(); 569 } 570 571 protected MetaAccessProvider getMetaAccess() { 572 return getProviders().getMetaAccess(); 573 } 574 575 protected LoweringProvider getLowerer() { 576 return getProviders().getLowerer(); 577 } 578 579 protected CompilationIdentifier getCompilationId(ResolvedJavaMethod method) { 580 return getBackend().getCompilationIdentifier(method); 581 } 582 583 protected CompilationIdentifier getOrCreateCompilationId(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { 584 if (graph != null) { 585 return graph.compilationId(); 586 } 587 return getCompilationId(installedCodeOwner); 588 } 589 590 protected void testN(int n, final String name, final Object... args) { 591 final List<Throwable> errors = new ArrayList<>(n); 592 Thread[] threads = new Thread[n]; 593 for (int i = 0; i < n; i++) { 594 Thread t = new Thread(i + ":" + name) { 595 596 @Override 597 public void run() { 598 try { 599 test(name, args); 600 } catch (Throwable e) { 601 errors.add(e); 602 } 603 } 604 }; 605 threads[i] = t; 606 t.start(); 607 } 608 for (int i = 0; i < n; i++) { 609 try { 610 threads[i].join(); 611 } catch (InterruptedException e) { 612 errors.add(e); 613 } 614 } 615 if (!errors.isEmpty()) { 616 throw new MultiCauseAssertionError(errors.size() + " failures", errors.toArray(new Throwable[errors.size()])); 617 } 618 } 619 620 protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 621 return invoke(method, receiver, args); 622 } 623 624 protected static class Result { 625 626 public final Object returnValue; 627 public final Throwable exception; 628 629 public Result(Object returnValue, Throwable exception) { 630 this.returnValue = returnValue; 631 this.exception = exception; 632 } 633 634 @Override 635 public String toString() { 636 return exception == null ? returnValue == null ? "null" : returnValue.toString() : "!" + exception; 637 } 638 } 639 640 /** 641 * Called before a test is executed. 642 */ 643 protected void before(@SuppressWarnings("unused") ResolvedJavaMethod method) { 644 } 645 646 /** 647 * Called after a test is executed. 648 */ 649 protected void after() { 650 } 651 652 protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) { 653 before(method); 654 try { 655 // This gives us both the expected return value as well as ensuring that the method to 656 // be compiled is fully resolved 657 return new Result(referenceInvoke(method, receiver, args), null); 658 } catch (InvocationTargetException e) { 659 return new Result(null, e.getTargetException()); 660 } catch (Exception e) { 661 throw new RuntimeException(e); 662 } finally { 663 after(); 664 } 665 } 666 667 protected Result executeActual(ResolvedJavaMethod method, Object receiver, Object... args) { 668 before(method); 669 Object[] executeArgs = argsWithReceiver(receiver, args); 670 671 checkArgs(method, executeArgs); 672 673 InstalledCode compiledMethod = getCode(method); 674 try { 675 return new Result(compiledMethod.executeVarargs(executeArgs), null); 676 } catch (Throwable e) { 677 return new Result(null, e); 678 } finally { 679 after(); 680 } 681 } 682 683 protected void checkArgs(ResolvedJavaMethod method, Object[] args) { 684 JavaType[] sig = method.toParameterTypes(); 685 Assert.assertEquals(sig.length, args.length); 686 for (int i = 0; i < args.length; i++) { 687 JavaType javaType = sig[i]; 688 JavaKind kind = javaType.getJavaKind(); 689 Object arg = args[i]; 690 if (kind == JavaKind.Object) { 691 if (arg != null && javaType instanceof ResolvedJavaType) { 692 ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType; 693 Assert.assertTrue(resolvedJavaType + " from " + getMetaAccess().lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(getMetaAccess().lookupJavaType(arg.getClass()))); 694 } 695 } else { 696 Assert.assertNotNull(arg); 697 Assert.assertEquals(kind.toBoxedJavaClass(), arg.getClass()); 698 } 699 } 700 } 701 702 /** 703 * Prepends a non-null receiver argument to a given list or args. 704 * 705 * @param receiver the receiver argument to prepend if it is non-null 706 */ 707 protected Object[] argsWithReceiver(Object receiver, Object... args) { 708 Object[] executeArgs; 709 if (receiver == null) { 710 executeArgs = args; 711 } else { 712 executeArgs = new Object[args.length + 1]; 713 executeArgs[0] = receiver; 714 for (int i = 0; i < args.length; i++) { 715 executeArgs[i + 1] = args[i]; 716 } 717 } 718 return applyArgSuppliers(executeArgs); 719 } 720 721 protected void test(String name, Object... args) { 722 try { 723 ResolvedJavaMethod method = getResolvedJavaMethod(name); 724 Object receiver = method.isStatic() ? null : this; 725 test(method, receiver, args); 726 } catch (AssumptionViolatedException e) { 727 // Suppress so that subsequent calls to this method within the 728 // same Junit @Test annotated method can proceed. 729 } 730 } 731 732 /** 733 * Type denoting a lambda that supplies a fresh value each time it is called. This is useful 734 * when supplying an argument to {@link GraalCompilerTest#test(String, Object...)} where the 735 * test modifies the state of the argument (e.g., updates a field). 736 */ 737 @FunctionalInterface 738 public interface ArgSupplier extends Supplier<Object> { 739 } 740 741 /** 742 * Convenience method for using an {@link ArgSupplier} lambda in a varargs list. 743 */ 744 public static Object supply(ArgSupplier supplier) { 745 return supplier; 746 } 747 748 protected void test(ResolvedJavaMethod method, Object receiver, Object... args) { 749 Result expect = executeExpected(method, receiver, args); 750 if (getCodeCache() == null) { 751 return; 752 } 753 testAgainstExpected(method, expect, receiver, args); 754 } 755 756 /** 757 * Process a given set of arguments, converting any {@link ArgSupplier} argument to the argument 758 * it supplies. 759 */ 760 protected Object[] applyArgSuppliers(Object... args) { 761 Object[] res = args; 762 for (int i = 0; i < args.length; i++) { 763 if (args[i] instanceof ArgSupplier) { 764 if (res == args) { 765 res = args.clone(); 766 } 767 res[i] = ((ArgSupplier) args[i]).get(); 768 } 769 } 770 return res; 771 } 772 773 protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Object receiver, Object... args) { 774 testAgainstExpected(method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args); 775 } 776 777 protected Result executeActualCheckDeopt(ResolvedJavaMethod method, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) { 778 Map<DeoptimizationReason, Integer> deoptCounts = new EnumMap<>(DeoptimizationReason.class); 779 ProfilingInfo profile = method.getProfilingInfo(); 780 for (DeoptimizationReason reason : shouldNotDeopt) { 781 deoptCounts.put(reason, profile.getDeoptimizationCount(reason)); 782 } 783 Result actual = executeActual(method, receiver, args); 784 profile = method.getProfilingInfo(); // profile can change after execution 785 for (DeoptimizationReason reason : shouldNotDeopt) { 786 Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason)); 787 } 788 return actual; 789 } 790 791 protected void assertEquals(Result expect, Result actual) { 792 if (expect.exception != null) { 793 Assert.assertTrue("expected " + expect.exception, actual.exception != null); 794 Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass()); 795 Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage()); 796 } else { 797 if (actual.exception != null) { 798 throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception); 799 } 800 assertDeepEquals(expect.returnValue, actual.returnValue); 801 } 802 } 803 804 protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) { 805 Result actual = executeActualCheckDeopt(method, shouldNotDeopt, receiver, args); 806 assertEquals(expect, actual); 807 } 808 809 private Map<ResolvedJavaMethod, InstalledCode> cache = new HashMap<>(); 810 811 /** 812 * Gets installed code for a given method, compiling it first if necessary. The graph is parsed 813 * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions) eagerly}. 814 */ 815 protected InstalledCode getCode(ResolvedJavaMethod method) { 816 return getCode(method, null); 817 } 818 819 /** 820 * Gets installed code for a given method, compiling it first if necessary. 821 * 822 * @param installedCodeOwner the method the compiled code will be associated with when installed 823 * @param graph the graph to be compiled. If null, a graph will be obtained from 824 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}. 825 */ 826 protected InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { 827 return getCode(installedCodeOwner, graph, false); 828 } 829 830 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph0, boolean forceCompile) { 831 return getCode(installedCodeOwner, graph0, forceCompile, false); 832 } 833 834 /** 835 * Gets installed code for a given method and graph, compiling it first if necessary. 836 * 837 * @param installedCodeOwner the method the compiled code will be associated with when installed 838 * @param graph the graph to be compiled. If null, a graph will be obtained from 839 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}. 840 * @param forceCompile specifies whether to ignore any previous code cached for the (method, 841 * key) pair 842 * @param installDefault specifies whether to install as the default implementation 843 */ 844 @SuppressWarnings("try") 845 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installDefault) { 846 if (!forceCompile) { 847 InstalledCode cached = cache.get(installedCodeOwner); 848 if (cached != null) { 849 if (cached.isValid()) { 850 return cached; 851 } 852 } 853 } 854 855 final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph); 856 857 InstalledCode installedCode = null; 858 try (AllocSpy spy = AllocSpy.open(installedCodeOwner); Scope ds = Debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) { 859 final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed(); 860 if (printCompilation) { 861 TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s ...", id, installedCodeOwner.getDeclaringClass().getName(), installedCodeOwner.getName(), installedCodeOwner.getSignature())); 862 } 863 long start = System.currentTimeMillis(); 864 CompilationResult compResult = compile(installedCodeOwner, graph, id); 865 if (printCompilation) { 866 TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); 867 } 868 869 try (Scope s = Debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult)) { 870 if (installDefault) { 871 installedCode = addDefaultMethod(installedCodeOwner, compResult); 872 } else { 873 installedCode = addMethod(installedCodeOwner, compResult); 874 } 875 if (installedCode == null) { 876 throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)")); 877 } 878 } catch (Throwable e) { 879 throw Debug.handle(e); 880 } 881 } catch (Throwable e) { 882 throw Debug.handle(e); 883 } 884 885 if (!forceCompile) { 886 cache.put(installedCodeOwner, installedCode); 887 } 888 return installedCode; 889 } 890 891 /** 892 * Used to produce a graph for a method about to be compiled by 893 * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method 894 * is null. 895 * 896 * The default implementation in {@link GraalCompilerTest} is to call 897 * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions)}. 898 */ 899 protected final StructuredGraph parseForCompile(ResolvedJavaMethod method) { 900 return parseEager(method, AllowAssumptions.YES); 901 } 902 903 protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId) { 904 return parseEager(method, AllowAssumptions.YES, compilationId); 905 } 906 907 /** 908 * Compiles a given method. 909 * 910 * @param installedCodeOwner the method the compiled code will be associated with when installed 911 * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will 912 * be obtained from {@code installedCodeOwner} via 913 * {@link #parseForCompile(ResolvedJavaMethod)}. 914 */ 915 protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) { 916 return compile(installedCodeOwner, graph, getOrCreateCompilationId(installedCodeOwner, graph)); 917 } 918 919 protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) { 920 return compile(installedCodeOwner, graph, new CompilationResult(), compilationId); 921 } 922 923 /** 924 * Compiles a given method. 925 * 926 * @param installedCodeOwner the method the compiled code will be associated with when installed 927 * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will 928 * be obtained from {@code installedCodeOwner} via 929 * {@link #parseForCompile(ResolvedJavaMethod)}. 930 * @param compilationResult 931 * @param compilationId 932 */ 933 @SuppressWarnings("try") 934 protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationResult compilationResult, CompilationIdentifier compilationId) { 935 StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, compilationId) : graph; 936 lastCompiledGraph = graphToCompile; 937 try (Scope s = Debug.scope("Compile", graphToCompile)) { 938 Request<CompilationResult> request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, 939 graphToCompile.getProfilingInfo(), getSuites(), getLIRSuites(), compilationResult, CompilationResultBuilderFactory.Default); 940 return GraalCompiler.compile(request); 941 } catch (Throwable e) { 942 throw Debug.handle(e); 943 } 944 } 945 946 protected StructuredGraph lastCompiledGraph; 947 948 protected SpeculationLog getSpeculationLog() { 949 return null; 950 } 951 952 protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) { 953 return backend.addInstalledCode(method, null, compilationResult); 954 } 955 956 protected InstalledCode addDefaultMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) { 957 return backend.createDefaultInstalledCode(method, compilationResult); 958 } 959 960 private final Map<ResolvedJavaMethod, Method> methodMap = new HashMap<>(); 961 962 /** 963 * Converts a reflection {@link Method} to a {@link ResolvedJavaMethod}. 964 */ 965 protected ResolvedJavaMethod asResolvedJavaMethod(Method method) { 966 ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method); 967 methodMap.put(javaMethod, method); 968 return javaMethod; 969 } 970 971 protected ResolvedJavaMethod getResolvedJavaMethod(String methodName) { 972 return asResolvedJavaMethod(getMethod(methodName)); 973 } 974 975 protected ResolvedJavaMethod getResolvedJavaMethod(Class<?> clazz, String methodName) { 976 return asResolvedJavaMethod(getMethod(clazz, methodName)); 977 } 978 979 protected ResolvedJavaMethod getResolvedJavaMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) { 980 return asResolvedJavaMethod(getMethod(clazz, methodName, parameterTypes)); 981 } 982 983 /** 984 * Gets the reflection {@link Method} from which a given {@link ResolvedJavaMethod} was created 985 * or null if {@code javaMethod} does not correspond to a reflection method. 986 */ 987 protected Method lookupMethod(ResolvedJavaMethod javaMethod) { 988 return methodMap.get(javaMethod); 989 } 990 991 protected Object invoke(ResolvedJavaMethod javaMethod, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 992 Method method = lookupMethod(javaMethod); 993 Assert.assertTrue(method != null); 994 if (!method.isAccessible()) { 995 method.setAccessible(true); 996 } 997 return method.invoke(receiver, applyArgSuppliers(args)); 998 } 999 1000 /** 1001 * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to 1002 * produce a graph. 1003 * 1004 * @param methodName the name of the method in {@code this.getClass()} to be parsed 1005 */ 1006 protected StructuredGraph parseProfiled(String methodName, AllowAssumptions allowAssumptions) { 1007 return parseProfiled(getResolvedJavaMethod(methodName), allowAssumptions); 1008 } 1009 1010 /** 1011 * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to 1012 * produce a graph. 1013 */ 1014 protected final StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { 1015 return parseProfiled(m, allowAssumptions, getCompilationId(m)); 1016 } 1017 1018 protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { 1019 return parse1(m, getDefaultGraphBuilderSuite(), allowAssumptions, compilationId); 1020 } 1021 1022 /** 1023 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)} 1024 * set to true to produce a graph. 1025 * 1026 * @param methodName the name of the method in {@code this.getClass()} to be parsed 1027 */ 1028 protected final StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions) { 1029 return parseEager(getResolvedJavaMethod(methodName), allowAssumptions); 1030 } 1031 1032 /** 1033 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)} 1034 * set to true to produce a graph. 1035 */ 1036 protected final StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { 1037 return parseEager(m, allowAssumptions, getCompilationId(m)); 1038 } 1039 1040 protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { 1041 return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)), allowAssumptions, compilationId); 1042 } 1043 1044 /** 1045 * Parses a Java method using {@linkplain GraphBuilderConfiguration#withFullInfopoints(boolean) 1046 * full debug} set to true to produce a graph. 1047 */ 1048 protected final StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) { 1049 return parseDebug(m, allowAssumptions, getCompilationId(m)); 1050 } 1051 1052 protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { 1053 return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)), allowAssumptions, compilationId); 1054 } 1055 1056 @SuppressWarnings("try") 1057 private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId) { 1058 assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod; 1059 StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions, getSpeculationLog(), compilationId); 1060 try (Scope ds = Debug.scope("Parsing", javaMethod, graph)) { 1061 graphBuilderSuite.apply(graph, getDefaultHighTierContext()); 1062 return graph; 1063 } catch (Throwable e) { 1064 throw Debug.handle(e); 1065 } 1066 } 1067 1068 protected Plugins getDefaultGraphBuilderPlugins() { 1069 PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite(); 1070 Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins(); 1071 // defensive copying 1072 return new Plugins(defaultPlugins); 1073 } 1074 1075 protected PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() { 1076 // defensive copying 1077 return backend.getSuites().getDefaultGraphBuilderSuite().copy(); 1078 } 1079 1080 protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) { 1081 PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite(); 1082 ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class); 1083 GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy()); 1084 iterator.remove(); 1085 iterator.add(new GraphBuilderPhase(gbConfCopy)); 1086 return suite; 1087 } 1088 1089 protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { 1090 InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins(); 1091 invocationPlugins.register(new InvocationPlugin() { 1092 @Override 1093 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1094 b.add(new BreakpointNode()); 1095 return true; 1096 } 1097 }, GraalCompilerTest.class, "breakpoint"); 1098 invocationPlugins.register(new InvocationPlugin() { 1099 @Override 1100 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg0) { 1101 b.add(new BreakpointNode(arg0)); 1102 return true; 1103 } 1104 }, GraalCompilerTest.class, "breakpoint", int.class); 1105 invocationPlugins.register(new InvocationPlugin() { 1106 @Override 1107 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1108 b.add(new NotOptimizedNode()); 1109 return true; 1110 } 1111 }, GraalCompilerTest.class, "shouldBeOptimizedAway"); 1112 1113 conf.getPlugins().prependInlineInvokePlugin(new InlineInvokePlugin() { 1114 1115 @Override 1116 public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { 1117 BytecodeParserNeverInline neverInline = method.getAnnotation(BytecodeParserNeverInline.class); 1118 if (neverInline != null) { 1119 return neverInline.invokeWithException() ? DO_NOT_INLINE_WITH_EXCEPTION : DO_NOT_INLINE_NO_EXCEPTION; 1120 } 1121 if (method.getAnnotation(BytecodeParserForceInline.class) != null) { 1122 return InlineInfo.createStandardInlineInfo(method); 1123 } 1124 return bytecodeParserShouldInlineInvoke(b, method, args); 1125 } 1126 }); 1127 return conf; 1128 } 1129 1130 /** 1131 * Supplements {@link BytecodeParserForceInline} and {@link BytecodeParserNeverInline} in terms 1132 * of allowing a test to influence the inlining decision made during bytecode parsing. 1133 * 1134 * @see InlineInvokePlugin#shouldInlineInvoke(GraphBuilderContext, ResolvedJavaMethod, 1135 * ValueNode[]) 1136 */ 1137 @SuppressWarnings("unused") 1138 protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { 1139 return null; 1140 } 1141 1142 @NodeInfo 1143 public static class NotOptimizedNode extends FixedWithNextNode { 1144 private static final NodeClass<NotOptimizedNode> TYPE = NodeClass.create(NotOptimizedNode.class); 1145 1146 protected NotOptimizedNode() { 1147 super(TYPE, StampFactory.forVoid()); 1148 } 1149 1150 } 1151 1152 protected Replacements getReplacements() { 1153 return getProviders().getReplacements(); 1154 } 1155 1156 /** 1157 * Inject a probability for a branch condition into the profiling information of this test case. 1158 * 1159 * @param p the probability that cond is true 1160 * @param cond the condition of the branch 1161 * @return cond 1162 */ 1163 protected static boolean branchProbability(double p, boolean cond) { 1164 return GraalDirectives.injectBranchProbability(p, cond); 1165 } 1166 1167 /** 1168 * Inject an iteration count for a loop condition into the profiling information of this test 1169 * case. 1170 * 1171 * @param i the iteration count of the loop 1172 * @param cond the condition of the loop 1173 * @return cond 1174 */ 1175 protected static boolean iterationCount(double i, boolean cond) { 1176 return GraalDirectives.injectIterationCount(i, cond); 1177 } 1178 1179 /** 1180 * Test if the current test runs on the given platform. The name must match the name given in 1181 * the {@link Architecture#getName()}. 1182 * 1183 * @param name The name to test 1184 * @return true if we run on the architecture given by name 1185 */ 1186 protected boolean isArchitecture(String name) { 1187 return name.equals(backend.getTarget().arch.getName()); 1188 } 1189 }