package com.oracle.svm.graal;
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
import java.io.PrintStream;
import java.util.EnumMap;
import java.util.Map;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.CompilationWrapper;
import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction;
import org.graalvm.compiler.core.GraalCompiler;
import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.Indent;
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.nativeimage.ImageSingletons;
import com.oracle.svm.core.CPUFeatureAccess;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.graal.code.SubstrateCompilationIdentifier;
import com.oracle.svm.core.graal.code.SubstrateCompilationResult;
import com.oracle.svm.core.graal.meta.RuntimeConfiguration;
import com.oracle.svm.core.meta.SharedMethod;
import com.oracle.svm.core.option.RuntimeOptionKey;
import com.oracle.svm.graal.meta.SubstrateMethod;
import jdk.vm.ci.code.Architecture;
public class SubstrateGraalUtils {
public static CompilationResult compile(DebugContext debug, final SubstrateMethod method) {
return doCompile(debug, GraalSupport.getRuntimeConfig(), GraalSupport.getSuites(), GraalSupport.getLIRSuites(), method);
}
private static final Map<ExceptionAction, Integer> compilationProblemsPerAction = new EnumMap<>(ExceptionAction.class);
public static CompilationResult doCompile(DebugContext initialDebug, RuntimeConfiguration runtimeConfig, Suites suites, LIRSuites lirSuites, final SubstrateMethod method) {
updateGraalArchitectureWithHostCPUFeatures(runtimeConfig.lookupBackend(method));
String methodString = method.format("%H.%n(%p)");
SubstrateCompilationIdentifier compilationId = new SubstrateCompilationIdentifier();
return new CompilationWrapper<CompilationResult>(GraalSupport.get().getDebugOutputDirectory(), compilationProblemsPerAction) {
@SuppressWarnings({"unchecked", "unused"})
<E extends Throwable> RuntimeException silenceThrowable(Class<E> type, Throwable ex) throws E {
throw (E) ex;
}
@Override
protected CompilationResult handleException(Throwable t) {
throw silenceThrowable(RuntimeException.class, t);
}
@Override
protected CompilationResult performCompilation(DebugContext debug) {
StructuredGraph graph = GraalSupport.decodeGraph(debug, null, compilationId, method);
return compileGraph(runtimeConfig, suites, lirSuites, method, graph);
}
@Override
public String toString() {
return methodString;
}
@SuppressWarnings("hiding")
@Override
protected DebugContext createRetryDebugContext(DebugContext initialDebug, OptionValues options, PrintStream logStream) {
return GraalSupport.get().openDebugContext(options, compilationId, method, logStream);
}
@Override
protected void exitHostVM(int status) {
System.exit(status);
}
}.run(initialDebug);
}
private static boolean architectureInitialized;
public static void updateGraalArchitectureWithHostCPUFeatures(Backend graalBackend) {
if (SubstrateUtil.HOSTED) {
throw shouldNotReachHere("Architecture should be updated only at runtime.");
}
if (!architectureInitialized) {
architectureInitialized = true;
CPUFeatureAccess cpuFeatureAccess = ImageSingletons.lookup(CPUFeatureAccess.class);
if (cpuFeatureAccess != null) {
cpuFeatureAccess.verifyHostSupportsArchitecture(graalBackend.getCodeCache().getTarget().arch);
Architecture architecture = graalBackend.getCodeCache().getTarget().arch;
cpuFeatureAccess.enableFeatures(architecture);
}
}
}
public static CompilationResult compileGraph(final SharedMethod method, final StructuredGraph graph) {
return compileGraph(GraalSupport.getRuntimeConfig(), GraalSupport.getSuites(), GraalSupport.getLIRSuites(), method, graph);
}
public static class Options {
@Option(help = "Force-dump graphs before compilation")
public static final RuntimeOptionKey<Boolean> ForceDumpGraphsBeforeCompilation = new RuntimeOptionKey<>(false);
}
@SuppressWarnings("try")
private static CompilationResult compileGraph(RuntimeConfiguration runtimeConfig, Suites suites, LIRSuites lirSuites, final SharedMethod method, final StructuredGraph graph) {
assert runtimeConfig != null : "no runtime";
if (Options.ForceDumpGraphsBeforeCompilation.getValue()) {
graph.getDebug().forceDump(graph, "Force dump before compilation");
}
String methodName = method.format("%h.%n");
try (DebugContext debug = graph.getDebug();
Indent indent = debug.logAndIndent("compile graph %s for method %s", graph, methodName)) {
OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseLoopLimitChecks);
final Backend backend = runtimeConfig.lookupBackend(method);
try (Indent indent2 = debug.logAndIndent("do compilation")) {
SubstrateCompilationResult result = new SubstrateCompilationResult(graph.compilationId(), method.format("%H.%n(%p)"));
GraalCompiler.compileGraph(graph, method, backend.getProviders(), backend, null, optimisticOpts, null, suites, lirSuites, result,
CompilationResultBuilderFactory.Default, false);
return result;
}
}
}
}