package org.graalvm.compiler.core;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.RetryableBailoutException;
import org.graalvm.compiler.core.common.util.CompilationAlarm;
import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
import org.graalvm.compiler.debug.MethodFilter;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.MidTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.compiler.phases.tiers.TargetProvider;
import org.graalvm.compiler.phases.util.Providers;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class GraalCompiler {
private static final TimerKey CompilerTimer = DebugContext.timer("GraalCompiler").doc("Time spent in compilation (excludes code installation).");
private static final TimerKey FrontEnd = DebugContext.timer("FrontEnd").doc("Time spent processing HIR.");
public static class Request<T extends CompilationResult> {
public final StructuredGraph graph;
public final ResolvedJavaMethod installedCodeOwner;
public final Providers providers;
public final Backend backend;
public final PhaseSuite<HighTierContext> graphBuilderSuite;
public final OptimisticOptimizations optimisticOpts;
public final ProfilingInfo profilingInfo;
public final Suites suites;
public final LIRSuites lirSuites;
public final T compilationResult;
public final CompilationResultBuilderFactory factory;
public final boolean verifySourcePositions;
public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory,
boolean verifySourcePositions) {
this.graph = graph;
this.installedCodeOwner = installedCodeOwner;
this.providers = providers;
this.backend = backend;
this.graphBuilderSuite = graphBuilderSuite;
this.optimisticOpts = optimisticOpts;
this.profilingInfo = profilingInfo;
this.suites = suites;
this.lirSuites = lirSuites;
this.compilationResult = compilationResult;
this.factory = factory;
this.verifySourcePositions = verifySourcePositions;
}
public T execute() {
return GraalCompiler.compile(this);
}
}
public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
CompilationResultBuilderFactory factory, boolean verifySourcePositions) {
return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory,
verifySourcePositions));
}
@SuppressWarnings("try")
public static <T extends CompilationResult> T compile(Request<T> r) {
DebugContext debug = r.graph.getDebug();
try (CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(r.graph.getOptions())) {
assert !r.graph.isFrozen();
try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) {
emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
r.backend.emitBackEnd(r.graph, null, r.installedCodeOwner, r.compilationResult, r.factory, null, r.lirSuites);
if (r.verifySourcePositions) {
assert r.graph.verifySourcePositions(true);
}
} catch (Throwable e) {
throw debug.handle(e);
}
checkForRequestedCrash(r.graph);
return r.compilationResult;
}
}
private static void checkForRequestedCrash(StructuredGraph graph) {
String value = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
if (value != null) {
boolean bailout = false;
boolean permanentBailout = false;
String methodPattern = value;
if (value.endsWith(":Bailout")) {
methodPattern = value.substring(0, value.length() - ":Bailout".length());
bailout = true;
} else if (value.endsWith(":PermanentBailout")) {
methodPattern = value.substring(0, value.length() - ":PermanentBailout".length());
permanentBailout = true;
}
String crashLabel = null;
if (graph.name != null && graph.name.contains(methodPattern)) {
crashLabel = graph.name;
}
if (crashLabel == null) {
ResolvedJavaMethod method = graph.method();
MethodFilter filter = MethodFilter.parse(methodPattern);
if (filter.matches(method)) {
crashLabel = method.format("%H.%n(%p)");
}
}
if (crashLabel != null) {
if (permanentBailout) {
throw new PermanentBailoutException("Forced crash after compiling " + crashLabel);
}
if (bailout) {
throw new RetryableBailoutException("Forced crash after compiling " + crashLabel);
}
throw new RuntimeException("Forced crash after compiling " + crashLabel);
}
}
}
@SuppressWarnings("try")
public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
ProfilingInfo profilingInfo, Suites suites) {
DebugContext debug = graph.getDebug();
try (DebugContext.Scope s = debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start(debug)) {
HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
if (graph.start().next() == null) {
try (CompilerPhaseScope cps = debug.enterCompilerPhase("Parsing")) {
graphBuilderSuite.apply(graph, highTierContext);
new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing");
}
} else {
debug.dump(DebugContext.INFO_LEVEL, graph, "initial state");
}
suites.getHighTier().apply(graph, highTierContext);
graph.maybeCompress();
debug.dump(DebugContext.BASIC_LEVEL, graph, "After high tier");
MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
suites.getMidTier().apply(graph, midTierContext);
graph.maybeCompress();
debug.dump(DebugContext.BASIC_LEVEL, graph, "After mid tier");
LowTierContext lowTierContext = new LowTierContext(providers, target);
suites.getLowTier().apply(graph, lowTierContext);
debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
graph.logInliningTree();
} catch (Throwable e) {
throw debug.handle(e);
} finally {
graph.checkCancellation();
}
}
protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) {
if (compilationResult != null && compilationResult.getName() != null) {
return compilationResult.getName();
}
ResolvedJavaMethod method = graph.method();
if (method == null) {
return "<unknown>";
}
return method.format("%H.%n(%p)");
}
}