26
27 import static java.lang.reflect.Modifier.isStatic;
28 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
29 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
30 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
31 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
32
33 import java.lang.annotation.ElementType;
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.lang.annotation.Target;
37 import java.lang.reflect.Constructor;
38 import java.lang.reflect.Executable;
39 import java.lang.reflect.InvocationTargetException;
40 import java.lang.reflect.Method;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.Collections;
45 import java.util.EnumMap;
46 import java.util.List;
47 import java.util.ListIterator;
48 import java.util.Map;
49 import java.util.Set;
50 import java.util.concurrent.ConcurrentHashMap;
51 import java.util.function.Supplier;
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.CompilationPrinter;
58 import org.graalvm.compiler.core.GraalCompiler;
59 import org.graalvm.compiler.core.GraalCompiler.Request;
60 import org.graalvm.compiler.core.common.CompilationIdentifier;
61 import org.graalvm.compiler.core.common.type.StampFactory;
62 import org.graalvm.compiler.core.target.Backend;
63 import org.graalvm.compiler.debug.DebugContext;
64 import org.graalvm.compiler.debug.DebugDumpHandler;
65 import org.graalvm.compiler.debug.DebugDumpScope;
66 import org.graalvm.compiler.debug.DebugHandlersFactory;
67 import org.graalvm.compiler.debug.GraalError;
68 import org.graalvm.compiler.debug.TTY;
69 import org.graalvm.compiler.graph.Node;
70 import org.graalvm.compiler.graph.NodeClass;
71 import org.graalvm.compiler.graph.NodeMap;
72 import org.graalvm.compiler.java.BytecodeParser;
73 import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
74 import org.graalvm.compiler.java.GraphBuilderPhase;
75 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
76 import org.graalvm.compiler.lir.phases.LIRSuites;
77 import org.graalvm.compiler.nodeinfo.NodeInfo;
78 import org.graalvm.compiler.nodeinfo.NodeSize;
79 import org.graalvm.compiler.nodeinfo.Verbosity;
80 import org.graalvm.compiler.nodes.BreakpointNode;
81 import org.graalvm.compiler.nodes.Cancellable;
82 import org.graalvm.compiler.nodes.ConstantNode;
83 import org.graalvm.compiler.nodes.FixedWithNextNode;
84 import org.graalvm.compiler.nodes.FrameState;
85 import org.graalvm.compiler.nodes.FullInfopointNode;
86 import org.graalvm.compiler.nodes.Invoke;
87 import org.graalvm.compiler.nodes.InvokeNode;
88 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
89 import org.graalvm.compiler.nodes.ParameterNode;
90 import org.graalvm.compiler.nodes.ProxyNode;
91 import org.graalvm.compiler.nodes.ReturnNode;
92 import org.graalvm.compiler.nodes.StructuredGraph;
93 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
94 import org.graalvm.compiler.nodes.StructuredGraph.Builder;
95 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
96 import org.graalvm.compiler.nodes.ValueNode;
97 import org.graalvm.compiler.nodes.cfg.Block;
98 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
99 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
100 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
101 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
102 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
103 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
104 import org.graalvm.compiler.nodes.java.AccessFieldNode;
105 import org.graalvm.compiler.nodes.spi.LoweringProvider;
106 import org.graalvm.compiler.nodes.spi.Replacements;
107 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
108 import org.graalvm.compiler.options.OptionValues;
109 import org.graalvm.compiler.phases.BasePhase;
110 import org.graalvm.compiler.phases.OptimisticOptimizations;
111 import org.graalvm.compiler.phases.Phase;
112 import org.graalvm.compiler.phases.PhaseSuite;
113 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
114 import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
115 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
116 import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
117 import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
118 import org.graalvm.compiler.phases.schedule.SchedulePhase;
119 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
120 import org.graalvm.compiler.phases.tiers.HighTierContext;
121 import org.graalvm.compiler.phases.tiers.MidTierContext;
122 import org.graalvm.compiler.phases.tiers.Suites;
123 import org.graalvm.compiler.phases.tiers.TargetProvider;
124 import org.graalvm.compiler.phases.util.Providers;
125 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
126 import org.graalvm.compiler.runtime.RuntimeProvider;
127 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
128 import org.graalvm.compiler.test.AddExports;
129 import org.graalvm.compiler.test.GraalTest;
130 import org.graalvm.compiler.test.JLModule;
131 import org.junit.After;
132 import org.junit.Assert;
133 import org.junit.Test;
134 import org.junit.internal.AssumptionViolatedException;
135
136 import jdk.vm.ci.code.Architecture;
137 import jdk.vm.ci.code.BailoutException;
138 import jdk.vm.ci.code.CodeCacheProvider;
139 import jdk.vm.ci.code.InstalledCode;
140 import jdk.vm.ci.code.TargetDescription;
141 import jdk.vm.ci.meta.Assumptions.Assumption;
142 import jdk.vm.ci.meta.ConstantReflectionProvider;
143 import jdk.vm.ci.meta.DeoptimizationReason;
144 import jdk.vm.ci.meta.JavaConstant;
145 import jdk.vm.ci.meta.JavaKind;
146 import jdk.vm.ci.meta.JavaType;
147 import jdk.vm.ci.meta.MetaAccessProvider;
148 import jdk.vm.ci.meta.ProfilingInfo;
149 import jdk.vm.ci.meta.ResolvedJavaMethod;
150 import jdk.vm.ci.meta.ResolvedJavaType;
151 import jdk.vm.ci.meta.SpeculationLog;
152
178 */
179 public static OptionValues getInitialOptions() {
180 return Graal.getRequiredCapability(OptionValues.class);
181 }
182
183 private static final int BAILOUT_RETRY_LIMIT = 1;
184 private final Providers providers;
185 private final Backend backend;
186
187 /**
188 * Representative class for the {@code java.base} module.
189 */
190 public static final Class<?> JAVA_BASE = Class.class;
191
192 /**
193 * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
194 * this object's module. This must be called before accessing packages that are no longer public
195 * as of JDK 9.
196 */
197 protected final void exportPackage(Class<?> moduleMember, String packageName) {
198 if (JavaVersionUtil.JAVA_SPEC > 8) {
199 JLModule.exportPackageTo(moduleMember, packageName, getClass());
200 }
201 }
202
203 /**
204 * Denotes a test method that must be inlined by the {@link BytecodeParser}.
205 */
206 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
207 @Retention(RetentionPolicy.RUNTIME)
208 public @interface BytecodeParserForceInline {
209 }
210
211 /**
212 * Denotes a test method that must never be inlined by the {@link BytecodeParser}.
213 */
214 @Retention(RetentionPolicy.RUNTIME)
215 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
216 public @interface BytecodeParserNeverInline {
217 /**
218 * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead
219 * of {@link InvokeNode}.
220 */
327 }
328
329 @Override
330 public float codeSizeIncrease() {
331 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
332 }
333
334 @Override
335 protected CharSequence getName() {
336 return "CheckGraphPhase";
337 }
338 });
339 return ret;
340 }
341
342 protected LIRSuites createLIRSuites(OptionValues opts) {
343 LIRSuites ret = backend.getSuites().getDefaultLIRSuites(opts).copy();
344 return ret;
345 }
346
347 public GraalCompilerTest() {
348 this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
349 this.providers = getBackend().getProviders();
350 }
351
352 /**
353 * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} )
354 * whether the desired backend is available.
355 *
356 * @param arch the name of the desired backend architecture
357 */
358 public GraalCompilerTest(Class<? extends Architecture> arch) {
359 RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class);
360 Backend b = runtime.getBackend(arch);
361 if (b != null) {
362 this.backend = b;
363 } else {
364 // Fall back to the default/host backend
365 this.backend = runtime.getHostBackend();
366 }
906 ArrayStoreException.class,
907 ClassCastException.class,
908 NullPointerException.class);
909
910 protected void assertEquals(Result expect, Result actual) {
911 if (expect.exception != null) {
912 Assert.assertTrue("expected " + expect.exception, actual.exception != null);
913 Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass());
914 // C2 can optimize out the stack trace and message in some cases
915 if (expect.exception.getMessage() != null || !C2_OMIT_STACK_TRACE_IN_FAST_THROW_EXCEPTIONS.contains(expect.exception.getClass())) {
916 Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage());
917 }
918 } else {
919 if (actual.exception != null) {
920 throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception);
921 }
922 assertDeepEquals(expect.returnValue, actual.returnValue);
923 }
924 }
925
926 private Map<ResolvedJavaMethod, InstalledCode> cache = new ConcurrentHashMap<>();
927
928 /**
929 * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
930 * {@link #parseEager eagerly}.
931 */
932 protected final InstalledCode getCode(ResolvedJavaMethod method) {
933 return getCode(method, null, false, false, getInitialOptions());
934 }
935
936 protected final InstalledCode getCode(ResolvedJavaMethod method, OptionValues options) {
937 return getCode(method, null, false, false, options);
938 }
939
940 /**
941 * Gets installed code for a given method, compiling it first if necessary.
942 *
943 * @param installedCodeOwner the method the compiled code will be associated with when installed
944 * @param graph the graph to be compiled. If null, a graph will be obtained from
945 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
946 */
947 protected final InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
959 */
960 protected final InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile) {
961 return getCode(installedCodeOwner, graph, forceCompile, false, graph == null ? getInitialOptions() : graph.getOptions());
962 }
963
964 /**
965 * Gets installed code for a given method and graph, compiling it first if necessary.
966 *
967 * @param installedCodeOwner the method the compiled code will be associated with when installed
968 * @param graph the graph to be compiled. If null, a graph will be obtained from
969 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
970 * @param forceCompile specifies whether to ignore any previous code cached for the (method,
971 * key) pair
972 * @param installAsDefault specifies whether to install as the default implementation
973 * @param options the options that will be used in {@link #parseForCompile(ResolvedJavaMethod)}
974 */
975 @SuppressWarnings("try")
976 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
977 boolean useCache = !forceCompile && getArgumentToBind() == null;
978 if (useCache && graph == null) {
979 InstalledCode cached = cache.get(installedCodeOwner);
980 if (cached != null) {
981 if (cached.isValid()) {
982 return cached;
983 }
984 }
985 }
986 // loop for retrying compilation
987 for (int retry = 0; retry <= BAILOUT_RETRY_LIMIT; retry++) {
988 final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph);
989
990 InstalledCode installedCode = null;
991 StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, id, options) : graph;
992 DebugContext debug = graphToCompile.getDebug();
993
994 try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
995 CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
996 CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
997 printer.finish(compResult);
998
999 try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
1000 DebugContext.Activation a = debug.activate()) {
1001 try {
1002 if (installAsDefault) {
1003 installedCode = addDefaultMethod(debug, installedCodeOwner, compResult);
1004 } else {
1005 installedCode = addMethod(debug, installedCodeOwner, compResult);
1006 }
1007 if (installedCode == null) {
1008 throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
1009 }
1010 } catch (BailoutException e) {
1011 if (retry < BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
1012 // retry (if there is no predefined graph)
1013 TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
1014 continue;
1015 }
1016 throw e;
1017 }
1018 } catch (Throwable e) {
1019 throw debug.handle(e);
1020 }
1021 } catch (Throwable e) {
1022 throw debug.handle(e);
1023 }
1024
1025 if (useCache) {
1026 cache.put(installedCodeOwner, installedCode);
1027 }
1028 return installedCode;
1029 }
1030 throw GraalError.shouldNotReachHere();
1031 }
1032
1033 /**
1034 * Used to produce a graph for a method about to be compiled by
1035 * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method
1036 * is null.
1037 *
1038 * The default implementation in {@link GraalCompilerTest} is to call {@link #parseEager}.
1039 */
1040 protected StructuredGraph parseForCompile(ResolvedJavaMethod method, OptionValues options) {
1041 return parseEager(method, AllowAssumptions.YES, getCompilationId(method), options);
1042 }
1043
1044 protected final StructuredGraph parseForCompile(ResolvedJavaMethod method, DebugContext debug) {
1045 return parseEager(method, AllowAssumptions.YES, debug);
1046 }
1305 ResolvedJavaMethod javaMethod = builder.getMethod();
1306 builder.speculationLog(getSpeculationLog());
1307 if (builder.getCancellable() == null) {
1308 builder.cancellable(getCancellable(javaMethod));
1309 }
1310 assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
1311 StructuredGraph graph = builder.build();
1312 DebugContext debug = graph.getDebug();
1313 try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) {
1314 graphBuilderSuite.apply(graph, getDefaultHighTierContext());
1315 Object[] args = getArgumentToBind();
1316 if (args != null) {
1317 bindArguments(graph, args);
1318 }
1319 return graph;
1320 } catch (Throwable e) {
1321 throw debug.handle(e);
1322 }
1323 }
1324
1325 protected void bindArguments(StructuredGraph graph, Object[] argsToBind) {
1326 ResolvedJavaMethod m = graph.method();
1327 Object receiver = isStatic(m.getModifiers()) ? null : this;
1328 Object[] args = argsWithReceiver(receiver, argsToBind);
1329 JavaType[] parameterTypes = m.toParameterTypes();
1330 assert parameterTypes.length == args.length;
1331 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
1332 JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
1333 ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
1334 param.replaceAtUsages(replacement);
1335 }
1336 }
1337
1338 protected Object[] getArgumentToBind() {
1339 return null;
1340 }
1341
1342 protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
1343 return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
1344 }
1345
1346 /**
1347 * Gets the cancellable that should be associated with a graph being created by any of the
1348 * {@code parse...()} methods.
1349 *
1350 * @param method the method being parsed into a graph
1351 */
1352 protected Cancellable getCancellable(ResolvedJavaMethod method) {
1353 return null;
1354 }
|
26
27 import static java.lang.reflect.Modifier.isStatic;
28 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
29 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
30 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
31 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION;
32
33 import java.lang.annotation.ElementType;
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.lang.annotation.Target;
37 import java.lang.reflect.Constructor;
38 import java.lang.reflect.Executable;
39 import java.lang.reflect.InvocationTargetException;
40 import java.lang.reflect.Method;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.Collections;
45 import java.util.EnumMap;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.ListIterator;
49 import java.util.Map;
50 import java.util.Set;
51 import java.util.concurrent.ConcurrentHashMap;
52 import java.util.function.Supplier;
53
54 import org.graalvm.compiler.api.directives.GraalDirectives;
55 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
56 import org.graalvm.compiler.api.test.Graal;
57 import org.graalvm.compiler.code.CompilationResult;
58 import org.graalvm.compiler.core.CompilationPrinter;
59 import org.graalvm.compiler.core.GraalCompiler;
60 import org.graalvm.compiler.core.GraalCompiler.Request;
61 import org.graalvm.compiler.core.common.CompilationIdentifier;
62 import org.graalvm.compiler.core.common.type.StampFactory;
63 import org.graalvm.compiler.core.target.Backend;
64 import org.graalvm.compiler.debug.DebugContext;
65 import org.graalvm.compiler.debug.DebugDumpHandler;
66 import org.graalvm.compiler.debug.DebugHandlersFactory;
67 import org.graalvm.compiler.debug.GraalError;
68 import org.graalvm.compiler.debug.TTY;
69 import org.graalvm.compiler.graph.Node;
70 import org.graalvm.compiler.graph.NodeClass;
71 import org.graalvm.compiler.graph.NodeMap;
72 import org.graalvm.compiler.java.BytecodeParser;
73 import org.graalvm.compiler.java.ComputeLoopFrequenciesClosure;
74 import org.graalvm.compiler.java.GraphBuilderPhase;
75 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
76 import org.graalvm.compiler.lir.phases.LIRSuites;
77 import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
78 import org.graalvm.compiler.nodeinfo.NodeInfo;
79 import org.graalvm.compiler.nodeinfo.NodeSize;
80 import org.graalvm.compiler.nodeinfo.Verbosity;
81 import org.graalvm.compiler.nodes.BreakpointNode;
82 import org.graalvm.compiler.nodes.Cancellable;
83 import org.graalvm.compiler.nodes.ConstantNode;
84 import org.graalvm.compiler.nodes.FixedWithNextNode;
85 import org.graalvm.compiler.nodes.FrameState;
86 import org.graalvm.compiler.nodes.FullInfopointNode;
87 import org.graalvm.compiler.nodes.Invoke;
88 import org.graalvm.compiler.nodes.InvokeNode;
89 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
90 import org.graalvm.compiler.nodes.ParameterNode;
91 import org.graalvm.compiler.nodes.ProxyNode;
92 import org.graalvm.compiler.nodes.ReturnNode;
93 import org.graalvm.compiler.nodes.StructuredGraph;
94 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
95 import org.graalvm.compiler.nodes.StructuredGraph.Builder;
96 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
97 import org.graalvm.compiler.nodes.ValueNode;
98 import org.graalvm.compiler.nodes.cfg.Block;
99 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
100 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
101 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
102 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
103 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
104 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
105 import org.graalvm.compiler.nodes.java.AccessFieldNode;
106 import org.graalvm.compiler.nodes.spi.LoweringProvider;
107 import org.graalvm.compiler.nodes.spi.Replacements;
108 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
109 import org.graalvm.compiler.options.OptionValues;
110 import org.graalvm.compiler.phases.BasePhase;
111 import org.graalvm.compiler.phases.OptimisticOptimizations;
112 import org.graalvm.compiler.phases.Phase;
113 import org.graalvm.compiler.phases.PhaseSuite;
114 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
115 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
116 import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
117 import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
118 import org.graalvm.compiler.phases.schedule.SchedulePhase;
119 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
120 import org.graalvm.compiler.phases.tiers.HighTierContext;
121 import org.graalvm.compiler.phases.tiers.MidTierContext;
122 import org.graalvm.compiler.phases.tiers.Suites;
123 import org.graalvm.compiler.phases.tiers.TargetProvider;
124 import org.graalvm.compiler.phases.util.Providers;
125 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
126 import org.graalvm.compiler.runtime.RuntimeProvider;
127 import org.graalvm.compiler.test.AddExports;
128 import org.graalvm.compiler.test.GraalTest;
129 import org.graalvm.compiler.test.ModuleSupport;
130 import org.junit.After;
131 import org.junit.Assert;
132 import org.junit.BeforeClass;
133 import org.junit.Test;
134 import org.junit.internal.AssumptionViolatedException;
135
136 import jdk.vm.ci.code.Architecture;
137 import jdk.vm.ci.code.BailoutException;
138 import jdk.vm.ci.code.CodeCacheProvider;
139 import jdk.vm.ci.code.InstalledCode;
140 import jdk.vm.ci.code.TargetDescription;
141 import jdk.vm.ci.meta.Assumptions.Assumption;
142 import jdk.vm.ci.meta.ConstantReflectionProvider;
143 import jdk.vm.ci.meta.DeoptimizationReason;
144 import jdk.vm.ci.meta.JavaConstant;
145 import jdk.vm.ci.meta.JavaKind;
146 import jdk.vm.ci.meta.JavaType;
147 import jdk.vm.ci.meta.MetaAccessProvider;
148 import jdk.vm.ci.meta.ProfilingInfo;
149 import jdk.vm.ci.meta.ResolvedJavaMethod;
150 import jdk.vm.ci.meta.ResolvedJavaType;
151 import jdk.vm.ci.meta.SpeculationLog;
152
178 */
179 public static OptionValues getInitialOptions() {
180 return Graal.getRequiredCapability(OptionValues.class);
181 }
182
183 private static final int BAILOUT_RETRY_LIMIT = 1;
184 private final Providers providers;
185 private final Backend backend;
186
187 /**
188 * Representative class for the {@code java.base} module.
189 */
190 public static final Class<?> JAVA_BASE = Class.class;
191
192 /**
193 * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
194 * this object's module. This must be called before accessing packages that are no longer public
195 * as of JDK 9.
196 */
197 protected final void exportPackage(Class<?> moduleMember, String packageName) {
198 ModuleSupport.exportPackageTo(moduleMember, packageName, getClass());
199 }
200
201 /**
202 * Denotes a test method that must be inlined by the {@link BytecodeParser}.
203 */
204 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
205 @Retention(RetentionPolicy.RUNTIME)
206 public @interface BytecodeParserForceInline {
207 }
208
209 /**
210 * Denotes a test method that must never be inlined by the {@link BytecodeParser}.
211 */
212 @Retention(RetentionPolicy.RUNTIME)
213 @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
214 public @interface BytecodeParserNeverInline {
215 /**
216 * Specifies if the call should be implemented with {@link InvokeWithExceptionNode} instead
217 * of {@link InvokeNode}.
218 */
325 }
326
327 @Override
328 public float codeSizeIncrease() {
329 return NodeSize.IGNORE_SIZE_CONTRACT_FACTOR;
330 }
331
332 @Override
333 protected CharSequence getName() {
334 return "CheckGraphPhase";
335 }
336 });
337 return ret;
338 }
339
340 protected LIRSuites createLIRSuites(OptionValues opts) {
341 LIRSuites ret = backend.getSuites().getDefaultLIRSuites(opts).copy();
342 return ret;
343 }
344
345 private static final ThreadLocal<HashMap<ResolvedJavaMethod, InstalledCode>> cache = ThreadLocal.withInitial(HashMap::new);
346
347 @BeforeClass
348 public static void resetCache() {
349 cache.get().clear();
350 }
351
352 public GraalCompilerTest() {
353 this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
354 this.providers = getBackend().getProviders();
355 }
356
357 /**
358 * Set up a test for a non-default backend. The test should check (via {@link #getBackend()} )
359 * whether the desired backend is available.
360 *
361 * @param arch the name of the desired backend architecture
362 */
363 public GraalCompilerTest(Class<? extends Architecture> arch) {
364 RuntimeProvider runtime = Graal.getRequiredCapability(RuntimeProvider.class);
365 Backend b = runtime.getBackend(arch);
366 if (b != null) {
367 this.backend = b;
368 } else {
369 // Fall back to the default/host backend
370 this.backend = runtime.getHostBackend();
371 }
911 ArrayStoreException.class,
912 ClassCastException.class,
913 NullPointerException.class);
914
915 protected void assertEquals(Result expect, Result actual) {
916 if (expect.exception != null) {
917 Assert.assertTrue("expected " + expect.exception, actual.exception != null);
918 Assert.assertEquals("Exception class", expect.exception.getClass(), actual.exception.getClass());
919 // C2 can optimize out the stack trace and message in some cases
920 if (expect.exception.getMessage() != null || !C2_OMIT_STACK_TRACE_IN_FAST_THROW_EXCEPTIONS.contains(expect.exception.getClass())) {
921 Assert.assertEquals("Exception message", expect.exception.getMessage(), actual.exception.getMessage());
922 }
923 } else {
924 if (actual.exception != null) {
925 throw new AssertionError("expected " + expect.returnValue + " but got an exception", actual.exception);
926 }
927 assertDeepEquals(expect.returnValue, actual.returnValue);
928 }
929 }
930
931 /**
932 * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
933 * {@link #parseEager eagerly}.
934 */
935 protected final InstalledCode getCode(ResolvedJavaMethod method) {
936 return getCode(method, null, false, false, getInitialOptions());
937 }
938
939 protected final InstalledCode getCode(ResolvedJavaMethod method, OptionValues options) {
940 return getCode(method, null, false, false, options);
941 }
942
943 /**
944 * Gets installed code for a given method, compiling it first if necessary.
945 *
946 * @param installedCodeOwner the method the compiled code will be associated with when installed
947 * @param graph the graph to be compiled. If null, a graph will be obtained from
948 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
949 */
950 protected final InstalledCode getCode(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
962 */
963 protected final InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile) {
964 return getCode(installedCodeOwner, graph, forceCompile, false, graph == null ? getInitialOptions() : graph.getOptions());
965 }
966
967 /**
968 * Gets installed code for a given method and graph, compiling it first if necessary.
969 *
970 * @param installedCodeOwner the method the compiled code will be associated with when installed
971 * @param graph the graph to be compiled. If null, a graph will be obtained from
972 * {@code installedCodeOwner} via {@link #parseForCompile(ResolvedJavaMethod)}.
973 * @param forceCompile specifies whether to ignore any previous code cached for the (method,
974 * key) pair
975 * @param installAsDefault specifies whether to install as the default implementation
976 * @param options the options that will be used in {@link #parseForCompile(ResolvedJavaMethod)}
977 */
978 @SuppressWarnings("try")
979 protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
980 boolean useCache = !forceCompile && getArgumentToBind() == null;
981 if (useCache && graph == null) {
982 InstalledCode cached = cache.get().get(installedCodeOwner);
983 if (cached != null) {
984 if (cached.isValid()) {
985 return cached;
986 }
987 }
988 }
989 // loop for retrying compilation
990 for (int retry = 0; retry <= BAILOUT_RETRY_LIMIT; retry++) {
991 final CompilationIdentifier id = getOrCreateCompilationId(installedCodeOwner, graph);
992
993 InstalledCode installedCode = null;
994 StructuredGraph graphToCompile = graph == null ? parseForCompile(installedCodeOwner, id, options) : graph;
995 DebugContext debug = graphToCompile.getDebug();
996
997 try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", graph)) {
998 CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
999 CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
1000 printer.finish(compResult);
1001
1002 try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
1003 DebugContext.Activation a = debug.activate()) {
1004 try {
1005 if (installAsDefault) {
1006 installedCode = addDefaultMethod(debug, installedCodeOwner, compResult);
1007 } else {
1008 installedCode = addMethod(debug, installedCodeOwner, compResult);
1009 }
1010 if (installedCode == null) {
1011 throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
1012 }
1013 } catch (BailoutException e) {
1014 if (retry < BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
1015 // retry (if there is no predefined graph)
1016 TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
1017 continue;
1018 }
1019 throw e;
1020 }
1021 } catch (Throwable e) {
1022 throw debug.handle(e);
1023 }
1024 } catch (Throwable e) {
1025 throw debug.handle(e);
1026 }
1027
1028 if (useCache) {
1029 cache.get().put(installedCodeOwner, installedCode);
1030 }
1031 return installedCode;
1032 }
1033 throw GraalError.shouldNotReachHere();
1034 }
1035
1036 /**
1037 * Used to produce a graph for a method about to be compiled by
1038 * {@link #compile(ResolvedJavaMethod, StructuredGraph)} if the second parameter to that method
1039 * is null.
1040 *
1041 * The default implementation in {@link GraalCompilerTest} is to call {@link #parseEager}.
1042 */
1043 protected StructuredGraph parseForCompile(ResolvedJavaMethod method, OptionValues options) {
1044 return parseEager(method, AllowAssumptions.YES, getCompilationId(method), options);
1045 }
1046
1047 protected final StructuredGraph parseForCompile(ResolvedJavaMethod method, DebugContext debug) {
1048 return parseEager(method, AllowAssumptions.YES, debug);
1049 }
1308 ResolvedJavaMethod javaMethod = builder.getMethod();
1309 builder.speculationLog(getSpeculationLog());
1310 if (builder.getCancellable() == null) {
1311 builder.cancellable(getCancellable(javaMethod));
1312 }
1313 assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
1314 StructuredGraph graph = builder.build();
1315 DebugContext debug = graph.getDebug();
1316 try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) {
1317 graphBuilderSuite.apply(graph, getDefaultHighTierContext());
1318 Object[] args = getArgumentToBind();
1319 if (args != null) {
1320 bindArguments(graph, args);
1321 }
1322 return graph;
1323 } catch (Throwable e) {
1324 throw debug.handle(e);
1325 }
1326 }
1327
1328 protected static final Object NO_BIND = new Object();
1329
1330 protected void bindArguments(StructuredGraph graph, Object[] argsToBind) {
1331 ResolvedJavaMethod m = graph.method();
1332 Object receiver = isStatic(m.getModifiers()) ? null : this;
1333 Object[] args = argsWithReceiver(receiver, argsToBind);
1334 JavaType[] parameterTypes = m.toParameterTypes();
1335 assert parameterTypes.length == args.length;
1336 for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
1337 Object arg = args[param.index()];
1338 if (arg != NO_BIND) {
1339 JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), arg);
1340 ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
1341 param.replaceAtUsages(replacement);
1342 }
1343 }
1344 }
1345
1346 protected Object[] getArgumentToBind() {
1347 return null;
1348 }
1349
1350 protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
1351 return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
1352 }
1353
1354 /**
1355 * Gets the cancellable that should be associated with a graph being created by any of the
1356 * {@code parse...()} methods.
1357 *
1358 * @param method the method being parsed into a graph
1359 */
1360 protected Cancellable getCancellable(ResolvedJavaMethod method) {
1361 return null;
1362 }
|