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;
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
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);
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
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 }
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())));
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
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
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 }
|
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.graalvm.compiler.api.directives.GraalDirectives;
48 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
49 import org.graalvm.compiler.api.test.Graal;
50 import org.graalvm.compiler.code.CompilationResult;
51 import org.graalvm.compiler.core.GraalCompiler;
52 import org.graalvm.compiler.core.GraalCompiler.Request;
53 import org.graalvm.compiler.core.common.CompilationIdentifier;
54 import org.graalvm.compiler.core.common.type.StampFactory;
55 import org.graalvm.compiler.core.common.util.ModuleAPI;
56 import org.graalvm.compiler.core.target.Backend;
57 import org.graalvm.compiler.debug.Debug;
58 import org.graalvm.compiler.debug.Debug.Scope;
59 import org.graalvm.compiler.debug.DebugDumpScope;
60 import org.graalvm.compiler.debug.DebugEnvironment;
61 import org.graalvm.compiler.debug.GraalError;
62 import org.graalvm.compiler.debug.TTY;
63 import org.graalvm.compiler.graph.Node;
64 import org.graalvm.compiler.graph.NodeClass;
65 import org.graalvm.compiler.graph.NodeMap;
66 import org.graalvm.compiler.java.BytecodeParser;
67 import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
68 import org.graalvm.compiler.java.GraphBuilderPhase;
69 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
70 import org.graalvm.compiler.lir.phases.LIRSuites;
71 import org.graalvm.compiler.nodeinfo.NodeInfo;
72 import org.graalvm.compiler.nodeinfo.NodeSize;
73 import org.graalvm.compiler.nodeinfo.Verbosity;
74 import org.graalvm.compiler.nodes.BreakpointNode;
75 import org.graalvm.compiler.nodes.ConstantNode;
76 import org.graalvm.compiler.nodes.FixedWithNextNode;
77 import org.graalvm.compiler.nodes.FrameState;
78 import org.graalvm.compiler.nodes.FullInfopointNode;
79 import org.graalvm.compiler.nodes.InvokeNode;
80 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
81 import org.graalvm.compiler.nodes.ProxyNode;
82 import org.graalvm.compiler.nodes.ReturnNode;
83 import org.graalvm.compiler.nodes.StructuredGraph;
84 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
85 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
86 import org.graalvm.compiler.nodes.ValueNode;
87 import org.graalvm.compiler.nodes.cfg.Block;
88 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
89 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
90 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
91 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
92 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
93 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
94 import org.graalvm.compiler.nodes.spi.LoweringProvider;
95 import org.graalvm.compiler.nodes.spi.Replacements;
96 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
97 import org.graalvm.compiler.options.OptionValues;
98 import org.graalvm.compiler.phases.BasePhase;
99 import org.graalvm.compiler.phases.OptimisticOptimizations;
100 import org.graalvm.compiler.phases.Phase;
101 import org.graalvm.compiler.phases.PhaseSuite;
102 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
103 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
104 import org.graalvm.compiler.phases.schedule.SchedulePhase;
105 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
106 import org.graalvm.compiler.phases.tiers.HighTierContext;
107 import org.graalvm.compiler.phases.tiers.Suites;
108 import org.graalvm.compiler.phases.tiers.TargetProvider;
109 import org.graalvm.compiler.phases.util.Providers;
110 import org.graalvm.compiler.runtime.RuntimeProvider;
111 import org.graalvm.compiler.test.AddExports;
112 import org.graalvm.compiler.test.GraalTest;
113 import org.junit.After;
114 import org.junit.Assert;
115 import org.junit.Before;
116 import org.junit.Test;
117 import org.junit.internal.AssumptionViolatedException;
118
119 import jdk.vm.ci.code.Architecture;
120 import jdk.vm.ci.code.BailoutException;
121 import jdk.vm.ci.code.CodeCacheProvider;
122 import jdk.vm.ci.code.InstalledCode;
123 import jdk.vm.ci.code.TargetDescription;
124 import jdk.vm.ci.meta.ConstantReflectionProvider;
125 import jdk.vm.ci.meta.DeoptimizationReason;
126 import jdk.vm.ci.meta.JavaKind;
127 import jdk.vm.ci.meta.JavaType;
128 import jdk.vm.ci.meta.MetaAccessProvider;
129 import jdk.vm.ci.meta.ProfilingInfo;
130 import jdk.vm.ci.meta.ResolvedJavaMethod;
131 import jdk.vm.ci.meta.ResolvedJavaType;
132 import jdk.vm.ci.meta.SpeculationLog;
133 import jdk.vm.ci.meta.Assumptions.Assumption;
134 import jdk.vm.ci.services.Services;
135
136 /**
137 * Base class for Graal compiler unit tests.
138 * <p>
139 * White box tests for Graal compiler transformations use this pattern:
140 * <ol>
141 * <li>Create a graph by {@linkplain #parseEager parsing} a method.</li>
142 * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li>
143 * <li>Apply a transformation to the graph.</li>
144 * <li>Assert that the transformed graph is equal to an expected graph.</li>
145 * </ol>
146 * <p>
147 * See {@link InvokeHintsTest} as an example of a white box test.
148 * <p>
149 * Black box tests use the {@link #test(String, Object...)} or
150 * {@link #testN(int, String, Object...)} to execute some method in the interpreter and compare its
151 * result against that produced by a Graal compiled version of the method.
152 * <p>
153 * These tests will be run by the {@code mx unittest} command.
154 */
155 @AddExports({"jdk.internal.vm.ci/jdk.vm.ci.meta",
156 "jdk.internal.vm.ci/jdk.vm.ci.services",
157 "jdk.internal.vm.ci/jdk.vm.ci.code",
158 "jdk.internal.vm.ci/jdk.vm.ci.services",
159 "java.base/jdk.internal.org.objectweb.asm",
160 "java.base/jdk.internal.org.objectweb.asm.tree"})
161 public abstract class GraalCompilerTest extends GraalTest {
162
163 /**
164 * Gets the initial option values provided by the Graal runtime. These are option values
165 * typically parsed from the command line.
166 */
167 public static OptionValues getInitialOptions() {
168 return Graal.getRequiredCapability(OptionValues.class);
169 }
170
171 private static final int BAILOUT_RETRY_LIMIT = 1;
172 private final Providers providers;
173 private final Backend backend;
174
175 /**
176 * Representative class for the {@code java.base} module.
177 */
178 public static final Class<?> JAVA_BASE = Class.class;
179
180 /**
181 * Representative class for the {@code jdk.vm.ci} module.
182 */
183 public static final Class<?> JDK_VM_CI = Services.class;
184
185 /**
186 * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
187 * this object's module. This must be called before accessing packages that are no longer public
188 * as of JDK 9.
189 */
190 protected final void exportPackage(Class<?> moduleMember, String packageName) {
191 if (!Java8OrEarlier) {
192 ModuleAPI.exportPackageTo(moduleMember, packageName, getClass());
193 }
194 }
195
196 /**
197 * Denotes a test method that must be inlined by the {@link BytecodeParser}.
198 */
199 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
200 @Retention(RetentionPolicy.RUNTIME)
201 public @interface BytecodeParserForceInline {
202 }
203
204 /**
205 * Denotes a test method that must never be inlined by the {@link BytecodeParser}.
206 */
207 @Retention(RetentionPolicy.RUNTIME)
208 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
209 public @interface BytecodeParserNeverInline {
210 /**
211 * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead
212 * of {@link InvokeNode}.
213 */
214 boolean invokeWithException() default false;
234
235 /**
236 * Can be overridden by unit tests to verify properties of the graph.
237 *
238 * @param graph the graph at the end of LowTier
239 */
240 protected boolean checkLowTierGraph(StructuredGraph graph) {
241 return true;
242 }
243
244 protected static void breakpoint() {
245 }
246
247 @SuppressWarnings("unused")
248 protected static void breakpoint(int arg0) {
249 }
250
251 protected static void shouldBeOptimizedAway() {
252 }
253
254 protected Suites createSuites(OptionValues opts) {
255 Suites ret = backend.getSuites().getDefaultSuites(opts).copy();
256 ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(ConvertDeoptimizeToGuardPhase.class, true);
257 if (iter == null) {
258 /*
259 * in the economy configuration, we don't have the ConvertDeoptimizeToGuard phase, so we
260 * just select the first CanonicalizerPhase in HighTier
261 */
262 iter = ret.getHighTier().findPhase(CanonicalizerPhase.class);
263 }
264 iter.add(new Phase() {
265
266 @Override
267 protected void run(StructuredGraph graph) {
268 ComputeLoopFrequenciesClosure.compute(graph);
269 }
270
271 @Override
272 public float codeSizeIncrease() {
273 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
274 }
275
315 ret.getLowTier().appendPhase(new Phase() {
316
317 @Override
318 protected void run(StructuredGraph graph) {
319 assert checkLowTierGraph(graph) : "failed LowTier graph check";
320 }
321
322 @Override
323 public float codeSizeIncrease() {
324 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
325 }
326
327 @Override
328 protected CharSequence getName() {
329 return "CheckGraphPhase";
330 }
331 });
332 return ret;
333 }
334
335 protected LIRSuites createLIRSuites(OptionValues opts) {
336 LIRSuites ret = backend.getSuites().getDefaultLIRSuites(opts).copy();
337 return ret;
338 }
339
340 public GraalCompilerTest() {
341 this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
342 this.providers = getBackend().getProviders();
343 }
344
345 /**
346 * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} )
347 * whether the desired backend is available.
348 *
349 * @param arch the name of the desired backend architecture
350 */
351 public GraalCompilerTest(Class<? extends Architecture> arch) {
352 RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class);
353 Backend b = runtime.getBackend(arch);
354 if (b != null) {
355 this.backend = b;
356 } else {
357 // Fall back to the default/host backend
358 this.backend = runtime.getHostBackend();
359 }
360 this.providers = backend.getProviders();
361 }
362
363 /**
364 * Set up a test for a non-default backend.
365 *
366 * @param backend the desired backend
367 */
368 public GraalCompilerTest(Backend backend) {
369 this.backend = backend;
370 this.providers = backend.getProviders();
371 }
372
373 private Scope debugScope;
374
375 @Before
376 public void beforeTest() {
377 assert debugScope == null;
378 debugScope = Debug.scope(getClass());
379 }
380
381 @After
382 public void afterTest() {
383 if (debugScope != null) {
384 debugScope.close();
385 }
386 debugScope = null;
387 }
388
389 protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
390 assertEquals(expected, graph, false, true);
548 result.append("Block " + block + " ");
549 if (block == scheduleResult.getCFG().getStartBlock()) {
550 result.append("* ");
551 }
552 result.append("-> ");
553 for (Block succ : block.getSuccessors()) {
554 result.append(succ + " ");
555 }
556 result.append("\n");
557 for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
558 result.append(String.format("%1S\n", node));
559 }
560 }
561 return result.toString();
562 }
563
564 protected Backend getBackend() {
565 return backend;
566 }
567
568 protected final Providers getProviders() {
569 return providers;
570 }
571
572 protected HighTierContext getDefaultHighTierContext() {
573 return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
574 }
575
576 protected SnippetReflectionProvider getSnippetReflection() {
577 return Graal.getRequiredCapability(SnippetReflectionProvider.class);
578 }
579
580 protected TargetDescription getTarget() {
581 return getTargetProvider().getTarget();
582 }
583
584 protected TargetProvider getTargetProvider() {
585 return getBackend();
586 }
587
629 };
630 threads[i] = t;
631 t.start();
632 }
633 for (int i = 0; i < n; i++) {
634 try {
635 threads[i].join();
636 } catch (InterruptedException e) {
637 errors.add(e);
638 }
639 }
640 if (!errors.isEmpty()) {
641 throw new MultiCauseAssertionError(errors.size() + " failures", errors.toArray(new Throwable[errors.size()]));
642 }
643 }
644
645 protected Object referenceInvoke(ResolvedJavaMethod method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
646 return invoke(method, receiver, args);
647 }
648
649 public static class Result {
650
651 public final Object returnValue;
652 public final Throwable exception;
653
654 public Result(Object returnValue, Throwable exception) {
655 this.returnValue = returnValue;
656 this.exception = exception;
657 }
658
659 @Override
660 public String toString() {
661 return exception == null ? returnValue == null ? "null" : returnValue.toString() : "!" + exception;
662 }
663 }
664
665 /**
666 * Called before a test is executed.
667 */
668 protected void before(@SuppressWarnings("unused") ResolvedJavaMethod method) {
669 }
673 */
674 protected void after() {
675 }
676
677 protected Result executeExpected(ResolvedJavaMethod method, Object receiver, Object... args) {
678 before(method);
679 try {
680 // This gives us both the expected return value as well as ensuring that the method to
681 // be compiled is fully resolved
682 return new Result(referenceInvoke(method, receiver, args), null);
683 } catch (InvocationTargetException e) {
684 return new Result(null, e.getTargetException());
685 } catch (Exception e) {
686 throw new RuntimeException(e);
687 } finally {
688 after();
689 }
690 }
691
692 protected Result executeActual(ResolvedJavaMethod method, Object receiver, Object... args) {
693 return executeActual(getInitialOptions(), method, receiver, args);
694 }
695
696 protected Result executeActual(OptionValues options, ResolvedJavaMethod method, Object receiver, Object... args) {
697 before(method);
698 Object[] executeArgs = argsWithReceiver(receiver, args);
699
700 checkArgs(method, executeArgs);
701
702 InstalledCode compiledMethod = getCode(method, options);
703 try {
704 return new Result(compiledMethod.executeVarargs(executeArgs), null);
705 } catch (Throwable e) {
706 return new Result(null, e);
707 } finally {
708 after();
709 }
710 }
711
712 protected void checkArgs(ResolvedJavaMethod method, Object[] args) {
713 JavaType[] sig = method.toParameterTypes();
714 Assert.assertEquals(sig.length, args.length);
715 for (int i = 0; i < args.length; i++) {
716 JavaType javaType = sig[i];
717 JavaKind kind = javaType.getJavaKind();
718 Object arg = args[i];
719 if (kind == JavaKind.Object) {
720 if (arg != null && javaType instanceof ResolvedJavaType) {
721 ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType;
722 Assert.assertTrue(resolvedJavaType + " from " + getMetaAccess().lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(getMetaAccess().lookupJavaType(arg.getClass())));
730
731 /**
732 * Prepends a non-null receiver argument to a given list or args.
733 *
734 * @param receiver the receiver argument to prepend if it is non-null
735 */
736 protected Object[] argsWithReceiver(Object receiver, Object... args) {
737 Object[] executeArgs;
738 if (receiver == null) {
739 executeArgs = args;
740 } else {
741 executeArgs = new Object[args.length + 1];
742 executeArgs[0] = receiver;
743 for (int i = 0; i < args.length; i++) {
744 executeArgs[i + 1] = args[i];
745 }
746 }
747 return applyArgSuppliers(executeArgs);
748 }
749
750 protected final Result test(String name, Object... args) {
751 return test(getInitialOptions(), name, args);
752 }
753
754 protected final Result test(OptionValues options, String name, Object... args) {
755 try {
756 ResolvedJavaMethod method = getResolvedJavaMethod(name);
757 Object receiver = method.isStatic() ? null : this;
758 return test(options, method, receiver, args);
759 } catch (AssumptionViolatedException e) {
760 // Suppress so that subsequent calls to this method within the
761 // same Junit @Test annotated method can proceed.
762 return null;
763 }
764 }
765
766 /**
767 * Type denoting a lambda that supplies a fresh value each time it is called. This is useful
768 * when supplying an argument to {@link GraalCompilerTest#test(String, Object...)} where the
769 * test modifies the state of the argument (e.g., updates a field).
770 */
771 @FunctionalInterface
772 public interface ArgSupplier extends Supplier<Object> {
773 }
774
775 /**
776 * Convenience method for using an {@link ArgSupplier} lambda in a varargs list.
777 */
778 public static Object supply(ArgSupplier supplier) {
779 return supplier;
780 }
781
782 protected Result test(ResolvedJavaMethod method, Object receiver, Object... args) {
783 return test(getInitialOptions(), method, receiver, args);
784 }
785
786 protected Result test(OptionValues options, ResolvedJavaMethod method, Object receiver, Object... args) {
787 Result expect = executeExpected(method, receiver, args);
788 if (getCodeCache() != null) {
789 testAgainstExpected(options, method, expect, receiver, args);
790 }
791 return expect;
792 }
793
794 /**
795 * Process a given set of arguments, converting any {@link ArgSupplier} argument to the argument
796 * it supplies.
797 */
798 protected Object[] applyArgSuppliers(Object... args) {
799 Object[] res = args;
800 for (int i = 0; i < args.length; i++) {
801 if (args[i] instanceof ArgSupplier) {
802 if (res == args) {
803 res = args.clone();
804 }
805 res[i] = ((ArgSupplier) args[i]).get();
806 }
807 }
808 return res;
809 }
810
811 protected final void testAgainstExpected(ResolvedJavaMethod method, Result expect, Object receiver, Object... args) {
812 testAgainstExpected(getInitialOptions(), method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args);
813 }
814
815 protected void testAgainstExpected(ResolvedJavaMethod method, Result expect, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
816 testAgainstExpected(getInitialOptions(), method, expect, shouldNotDeopt, receiver, args);
817 }
818
819 protected final void testAgainstExpected(OptionValues options, ResolvedJavaMethod method, Result expect, Object receiver, Object... args) {
820 testAgainstExpected(options, method, expect, Collections.<DeoptimizationReason> emptySet(), receiver, args);
821 }
822
823 protected void testAgainstExpected(OptionValues options, ResolvedJavaMethod method, Result expect, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
824 Result actual = executeActualCheckDeopt(options, method, shouldNotDeopt, receiver, args);
825 assertEquals(expect, actual);
826 }
827
828 protected Result executeActualCheckDeopt(OptionValues options, ResolvedJavaMethod method, Set<DeoptimizationReason> shouldNotDeopt, Object receiver, Object... args) {
829 Map<DeoptimizationReason, Integer> deoptCounts = new EnumMap<>(DeoptimizationReason.class);
830 ProfilingInfo profile = method.getProfilingInfo();
831 for (DeoptimizationReason reason : shouldNotDeopt) {
832 deoptCounts.put(reason, profile.getDeoptimizationCount(reason));
833 }
834 Result actual = executeActual(options, method, receiver, args);
835 profile = method.getProfilingInfo(); // profile can change after execution
836 for (DeoptimizationReason reason : shouldNotDeopt) {
837 Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
838 }
839 return actual;
840 }
841
842 protected void assertEquals(Result expect, Result actual) {
843 if (expect.exception != null) {
844 Assert.assertTrue("expected " + expect.exception, actual.exception != null);
845 Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass());
846 Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage());
847 } else {
848 if (actual.exception != null) {
849 throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception);
850 }
851 assertDeepEquals(expect.returnValue, actual.returnValue);
852 }
853 }
854
855 private Map<ResolvedJavaMethod, InstalledCode> cache = new HashMap<>();
856
857 /**
858 * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
859 * {@link #parseEager eagerly}.
860 */
861 protected final InstalledCode getCode(ResolvedJavaMethod method) {
862 return getCode(method, null, false, false, getInitialOptions());
863 }
864
865 protected final InstalledCode getCode(ResolvedJavaMethod method, OptionValues options) {
866 return getCode(method, null, false, false, options);
867 }
868
869 /**
870 * Gets installed code for a given method, compiling it first if necessary.
871 *
872 * @param installedCodeOwner the method the compiled code will be associated with when installed
873 * @param graph the graph to be compiled. If null, a graph will be obtained from
874 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
875 */
876 protected final InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
877 return getCode(installedCodeOwner, graph, false, false, graph == null ? getInitialOptions() : graph.getOptions());
878 }
879
880 /**
881 * Gets installed code for a given method and graph, compiling it first if necessary.
882 *
883 * @param installedCodeOwner the method the compiled code will be associated with when installed
884 * @param graph the graph to be compiled. If null, a graph will be obtained from
885 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
886 * @param forceCompile specifies whether to ignore any previous code cached for the (method,
887 * key) pair
888 */
889 protected final InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile) {
890 return getCode(installedCodeOwner, graph, forceCompile, false, graph == null ? getInitialOptions() : graph.getOptions());
891 }
892
893 /**
894 * Gets installed code for a given method and graph, compiling it first if necessary.
895 *
896 * @param installedCodeOwner the method the compiled code will be associated with when installed
897 * @param graph the graph to be compiled. If null, a graph will be obtained from
898 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
899 * @param forceCompile specifies whether to ignore any previous code cached for the (method,
900 * key) pair
901 * @param installAsDefault specifies whether to install as the default implementation
902 * @param options the options that will be used in {@link #parseForCompile(ResolvedJavaMethod)}
903 */
904 @SuppressWarnings("try")
905 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
906 if (!forceCompile) {
907 InstalledCode cached = cache.get(installedCodeOwner);
908 if (cached != null) {
909 if (cached.isValid()) {
910 return cached;
911 }
912 }
913 }
914 // loop for retrying compilation
915 for (int retry = 0; retry <= BAILOUT_RETRY_LIMIT; retry++) {
916 final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph);
917
918 InstalledCode installedCode = null;
919 try (AllocSpy spy = AllocSpy.open(installedCodeOwner); Scope ds = Debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
920 final boolean printCompilation = PrintCompilation.getValue(options) && !TTY.isSuppressed();
921 if (printCompilation) {
922 TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s ...", id, installedCodeOwner.getDeclaringClass().getName(), installedCodeOwner.getName(),
923 installedCodeOwner.getSignature()));
924 }
925 long start = System.currentTimeMillis();
926 CompilationResult compResult = compile(installedCodeOwner, graph, new CompilationResult(), id, options);
927 if (printCompilation) {
928 TTY.println(String.format("@%-6s Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
929 }
930
931 try (Scope s = Debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult)) {
932 try {
933 if (installAsDefault) {
934 installedCode = addDefaultMethod(installedCodeOwner, compResult);
935 } else {
936 installedCode = addMethod(installedCodeOwner, compResult);
937 }
938 if (installedCode == null) {
939 throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
940 }
941 } catch (BailoutException e) {
942 if (retry <= BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
943 // retry (if there is no predefined graph)
944 TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
945 continue;
946 }
947 throw e;
948 }
949 } catch (Throwable e) {
950 throw Debug.handle(e);
951 }
952 } catch (Throwable e) {
953 throw Debug.handle(e);
954 }
955
956 if (!forceCompile) {
957 cache.put(installedCodeOwner, installedCode);
958 }
959 return installedCode;
960 }
961 throw GraalError.shouldNotReachHere();
962 }
963
964 /**
965 * Used to produce a graph for a method about to be compiled by
966 * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method
967 * is null.
968 *
969 * The default implementation in {@link GraalCompilerTest} is to call {@link #parseEager}.
970 */
971 protected StructuredGraph parseForCompile(ResolvedJavaMethod method, OptionValues options) {
972 return parseEager(method, AllowAssumptions.YES, getCompilationId(method), options);
973 }
974
975 protected final StructuredGraph parseForCompile(ResolvedJavaMethod method) {
976 return parseEager(method, AllowAssumptions.YES, getCompilationId(method), getInitialOptions());
977 }
978
979 protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) {
980 return parseEager(method, AllowAssumptions.YES, compilationId, options);
981 }
982
983 /**
984 * Compiles a given method.
985 *
986 * @param installedCodeOwner the method the compiled code will be associated with when installed
987 * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will
988 * be obtained from {@code installedCodeOwner} via
989 * {@link #parseForCompile(ResolvedJavaMethod)}.
990 */
991 protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
992 OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
993 return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
994 }
995
996 protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
997 OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
998 return compile(installedCodeOwner, graph, new CompilationResult(), compilationId, options);
999 }
1000
1001 protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) {
1002 assert graph == null || graph.getOptions() == options;
1003 return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
1004 }
1005
1006 /**
1007 * Compiles a given method.
1008 *
1009 * @param installedCodeOwner the method the compiled code will be associated with when installed
1010 * @param graph the graph to be compiled for {@code installedCodeOwner}. If null, a graph will
1011 * be obtained from {@code installedCodeOwner} via
1012 * {@link #parseForCompile(ResolvedJavaMethod)}.
1013 * @param compilationId
1014 */
1015 @SuppressWarnings("try")
1016 protected CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationResult compilationResult, CompilationIdentifier compilationId, OptionValues options) {
1017 StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, compilationId, options) : graph;
1018 lastCompiledGraph = graphToCompile;
1019 try (Scope s = Debug.scope("Compile", graphToCompile)) {
1020 assert options != null;
1021 Request<CompilationResult> request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
1022 graphToCompile.getProfilingInfo(), createSuites(options), createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default);
1023 return GraalCompiler.compile(request);
1024 } catch (Throwable e) {
1025 throw Debug.handle(e);
1026 }
1027 }
1028
1029 protected StructuredGraph lastCompiledGraph;
1030
1031 protected SpeculationLog getSpeculationLog() {
1032 return null;
1033 }
1034
1035 protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) {
1036 return backend.addInstalledCode(method, null, compilationResult);
1037 }
1038
1039 protected InstalledCode addDefaultMethod(final ResolvedJavaMethod method, final CompilationResult compilationResult) {
1040 return backend.createDefaultInstalledCode(method, compilationResult);
1041 }
1042
1068 * or null if {@code javaMethod} does not correspond to a reflection method.
1069 */
1070 protected Method lookupMethod(ResolvedJavaMethod javaMethod) {
1071 return methodMap.get(javaMethod);
1072 }
1073
1074 protected Object invoke(ResolvedJavaMethod javaMethod, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
1075 Method method = lookupMethod(javaMethod);
1076 Assert.assertTrue(method != null);
1077 if (!method.isAccessible()) {
1078 method.setAccessible(true);
1079 }
1080 return method.invoke(receiver, applyArgSuppliers(args));
1081 }
1082
1083 /**
1084 * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
1085 * produce a graph.
1086 *
1087 * @param methodName the name of the method in {@code this.getClass()} to be parsed
1088 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1089 */
1090 protected final StructuredGraph parseProfiled(String methodName, AllowAssumptions allowAssumptions) {
1091 return parseProfiled(getResolvedJavaMethod(methodName), allowAssumptions);
1092 }
1093
1094 /**
1095 * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault default} mode to
1096 * produce a graph.
1097 *
1098 * @param method the method to be parsed
1099 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1100 */
1101 protected final StructuredGraph parseProfiled(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
1102 return parse1(method, getDefaultGraphBuilderSuite(), allowAssumptions, getCompilationId(method), getInitialOptions());
1103 }
1104
1105 /**
1106 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
1107 * set to true to produce a graph.
1108 *
1109 * @param methodName the name of the method in {@code this.getClass()} to be parsed
1110 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1111 */
1112 protected final StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions) {
1113 return parseEager(getResolvedJavaMethod(methodName), allowAssumptions, getInitialOptions());
1114 }
1115
1116 /**
1117 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
1118 * set to true to produce a graph.
1119 *
1120 * @param methodName the name of the method in {@code this.getClass()} to be parsed
1121 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1122 * @param options the option values to be used when compiling the graph
1123 */
1124 protected final StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions, OptionValues options) {
1125 return parseEager(getResolvedJavaMethod(methodName), allowAssumptions, options);
1126 }
1127
1128 /**
1129 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
1130 * set to true to produce a graph.
1131 *
1132 * @param method the method to be parsed
1133 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1134 */
1135 protected final StructuredGraph parseEager(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
1136 return parseEager(method, allowAssumptions, getCompilationId(method), getInitialOptions());
1137 }
1138
1139 /**
1140 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
1141 * set to true to produce a graph.
1142 *
1143 * @param method the method to be parsed
1144 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1145 * @param options the option values to be used when compiling the graph
1146 */
1147 protected final StructuredGraph parseEager(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, OptionValues options) {
1148 return parseEager(method, allowAssumptions, getCompilationId(method), options);
1149 }
1150
1151 /**
1152 * Parses a Java method with {@linkplain GraphBuilderConfiguration#withEagerResolving(boolean)}
1153 * set to true to produce a graph.
1154 *
1155 * @param method the method to be parsed
1156 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1157 * @param compilationId the compilation identifier to be associated with the graph
1158 * @param options the option values to be used when compiling the graph
1159 */
1160 protected StructuredGraph parseEager(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId, OptionValues options) {
1161 return parse1(method, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true)), allowAssumptions, compilationId, options);
1162 }
1163
1164 /**
1165 * Parses a Java method using {@linkplain GraphBuilderConfiguration#withFullInfopoints(boolean)
1166 * full debug} set to true to produce a graph.
1167 *
1168 * @param method the method to be parsed
1169 * @param allowAssumptions specifies if {@link Assumption}s can be made compiling the graph
1170 */
1171 protected StructuredGraph parseDebug(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
1172 return parse1(method, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)), allowAssumptions, getCompilationId(method),
1173 getInitialOptions());
1174 }
1175
1176 @SuppressWarnings("try")
1177 private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId,
1178 OptionValues options) {
1179 assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
1180 StructuredGraph graph = new StructuredGraph.Builder(options, allowAssumptions).method(javaMethod).speculationLog(getSpeculationLog()).useProfilingInfo(true).compilationId(
1181 compilationId).build();
1182 try (Scope ds = Debug.scope("Parsing", javaMethod, graph)) {
1183 graphBuilderSuite.apply(graph, getDefaultHighTierContext());
1184 return graph;
1185 } catch (Throwable e) {
1186 throw Debug.handle(e);
1187 }
1188 }
1189
1190 protected Plugins getDefaultGraphBuilderPlugins() {
1191 PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite();
1192 Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins();
1193 // defensive copying
1194 return new Plugins(defaultPlugins);
1195 }
1196
1197 protected PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
1198 // defensive copying
1199 return backend.getSuites().getDefaultGraphBuilderSuite().copy();
1200 }
1201
1291 * case.
1292 *
1293 * @param i the iteration count of the loop
1294 * @param cond the condition of the loop
1295 * @return cond
1296 */
1297 protected static boolean iterationCount(double i, boolean cond) {
1298 return GraalDirectives.injectIterationCount(i, cond);
1299 }
1300
1301 /**
1302 * Test if the current test runs on the given platform. The name must match the name given in
1303 * the {@link Architecture#getName()}.
1304 *
1305 * @param name The name to test
1306 * @return true if we run on the architecture given by name
1307 */
1308 protected boolean isArchitecture(String name) {
1309 return name.equals(backend.getTarget().arch.getName());
1310 }
1311
1312 /**
1313 * This method should be called in "timeout" tests which JUnit runs in a different thread.
1314 */
1315 public static void initializeForTimeout() {
1316 // timeout tests run in a separate thread which needs the DebugEnvironment to be
1317 // initialized
1318 DebugEnvironment.ensureInitialized(getInitialOptions());
1319 }
1320 }
|