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 }