1 /*
   2  * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.core;
  26 
  27 import org.graalvm.compiler.code.CompilationResult;
  28 import org.graalvm.compiler.core.common.PermanentBailoutException;
  29 import org.graalvm.compiler.core.common.RetryableBailoutException;
  30 import org.graalvm.compiler.core.common.util.CompilationAlarm;
  31 import org.graalvm.compiler.core.target.Backend;
  32 import org.graalvm.compiler.debug.DebugCloseable;
  33 import org.graalvm.compiler.debug.DebugContext;
  34 import org.graalvm.compiler.debug.MethodFilter;
  35 import org.graalvm.compiler.debug.TimerKey;
  36 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
  37 import org.graalvm.compiler.lir.phases.LIRSuites;
  38 import org.graalvm.compiler.nodes.StructuredGraph;
  39 import org.graalvm.compiler.phases.OptimisticOptimizations;
  40 import org.graalvm.compiler.phases.PhaseSuite;
  41 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
  42 import org.graalvm.compiler.phases.tiers.HighTierContext;
  43 import org.graalvm.compiler.phases.tiers.LowTierContext;
  44 import org.graalvm.compiler.phases.tiers.MidTierContext;
  45 import org.graalvm.compiler.phases.tiers.Suites;
  46 import org.graalvm.compiler.phases.tiers.TargetProvider;
  47 import org.graalvm.compiler.phases.util.Providers;
  48 
  49 import jdk.vm.ci.meta.ProfilingInfo;
  50 import jdk.vm.ci.meta.ResolvedJavaMethod;
  51 
  52 /**
  53  * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
  54  */
  55 public class GraalCompiler {
  56 
  57     private static final TimerKey CompilerTimer = DebugContext.timer("GraalCompiler").doc("Time spent in compilation (excludes code installation).");
  58     private static final TimerKey FrontEnd = DebugContext.timer("FrontEnd").doc("Time spent processing HIR.");
  59 
  60     /**
  61      * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}.
  62      */
  63     public static class Request<T extends CompilationResult> {
  64         public final StructuredGraph graph;
  65         public final ResolvedJavaMethod installedCodeOwner;
  66         public final Providers providers;
  67         public final Backend backend;
  68         public final PhaseSuite<HighTierContext> graphBuilderSuite;
  69         public final OptimisticOptimizations optimisticOpts;
  70         public final ProfilingInfo profilingInfo;
  71         public final Suites suites;
  72         public final LIRSuites lirSuites;
  73         public final T compilationResult;
  74         public final CompilationResultBuilderFactory factory;
  75         public final boolean verifySourcePositions;
  76 
  77         /**
  78          * @param graph the graph to be compiled
  79          * @param installedCodeOwner the method the compiled code will be associated with once
  80          *            installed. This argument can be null.
  81          * @param providers
  82          * @param backend
  83          * @param graphBuilderSuite
  84          * @param optimisticOpts
  85          * @param profilingInfo
  86          * @param suites
  87          * @param lirSuites
  88          * @param compilationResult
  89          * @param factory
  90          */
  91         public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
  92                         OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory,
  93                         boolean verifySourcePositions) {
  94             this.graph = graph;
  95             this.installedCodeOwner = installedCodeOwner;
  96             this.providers = providers;
  97             this.backend = backend;
  98             this.graphBuilderSuite = graphBuilderSuite;
  99             this.optimisticOpts = optimisticOpts;
 100             this.profilingInfo = profilingInfo;
 101             this.suites = suites;
 102             this.lirSuites = lirSuites;
 103             this.compilationResult = compilationResult;
 104             this.factory = factory;
 105             this.verifySourcePositions = verifySourcePositions;
 106         }
 107 
 108         /**
 109          * Executes this compilation request.
 110          *
 111          * @return the result of the compilation
 112          */
 113         public T execute() {
 114             return GraalCompiler.compile(this);
 115         }
 116     }
 117 
 118     /**
 119      * Requests compilation of a given graph.
 120      *
 121      * @param graph the graph to be compiled
 122      * @param installedCodeOwner the method the compiled code will be associated with once
 123      *            installed. This argument can be null.
 124      * @return the result of the compilation
 125      */
 126     public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
 127                     PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
 128                     CompilationResultBuilderFactory factory, boolean verifySourcePositions) {
 129         return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory,
 130                         verifySourcePositions));
 131     }
 132 
 133     /**
 134      * Services a given compilation request.
 135      *
 136      * @return the result of the compilation
 137      */
 138     @SuppressWarnings("try")
 139     public static <T extends CompilationResult> T compile(Request<T> r) {
 140         DebugContext debug = r.graph.getDebug();
 141         try (CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(r.graph.getOptions())) {
 142             assert !r.graph.isFrozen();
 143             try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) {
 144                 emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
 145                 r.backend.emitBackEnd(r.graph, null, r.installedCodeOwner, r.compilationResult, r.factory, null, r.lirSuites);
 146                 if (r.verifySourcePositions) {
 147                     assert r.graph.verifySourcePositions(true);
 148                 }
 149             } catch (Throwable e) {
 150                 throw debug.handle(e);
 151             }
 152             checkForRequestedCrash(r.graph);
 153             return r.compilationResult;
 154         }
 155     }
 156 
 157     /**
 158      * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation
 159      * of {@code graph} should result in an exception.
 160      *
 161      * @param graph a graph currently being compiled
 162      * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches
 163      *             {@code graph.method()} or {@code graph.name}
 164      */
 165     private static void checkForRequestedCrash(StructuredGraph graph) {
 166         String value = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
 167         if (value != null) {
 168             boolean bailout = false;
 169             boolean permanentBailout = false;
 170             String methodPattern = value;
 171             if (value.endsWith(":Bailout")) {
 172                 methodPattern = value.substring(0, value.length() - ":Bailout".length());
 173                 bailout = true;
 174             } else if (value.endsWith(":PermanentBailout")) {
 175                 methodPattern = value.substring(0, value.length() - ":PermanentBailout".length());
 176                 permanentBailout = true;
 177             }
 178             String crashLabel = null;
 179             if (graph.name != null && graph.name.contains(methodPattern)) {
 180                 crashLabel = graph.name;
 181             }
 182             if (crashLabel == null) {
 183                 ResolvedJavaMethod method = graph.method();
 184                 MethodFilter[] filters = MethodFilter.parse(methodPattern);
 185                 for (MethodFilter filter : filters) {
 186                     if (filter.matches(method)) {
 187                         crashLabel = method.format("%H.%n(%p)");
 188                     }
 189                 }
 190             }
 191             if (crashLabel != null) {
 192                 if (permanentBailout) {
 193                     throw new PermanentBailoutException("Forced crash after compiling " + crashLabel);
 194                 }
 195                 if (bailout) {
 196                     throw new RetryableBailoutException("Forced crash after compiling " + crashLabel);
 197                 }
 198                 throw new RuntimeException("Forced crash after compiling " + crashLabel);
 199             }
 200         }
 201     }
 202 
 203     /**
 204      * Builds the graph, optimizes it.
 205      */
 206     @SuppressWarnings("try")
 207     public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
 208                     ProfilingInfo profilingInfo, Suites suites) {
 209         DebugContext debug = graph.getDebug();
 210         try (DebugContext.Scope s = debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start(debug)) {
 211             HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
 212             if (graph.start().next() == null) {
 213                 graphBuilderSuite.apply(graph, highTierContext);
 214                 new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
 215                 debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing");
 216             } else {
 217                 debug.dump(DebugContext.INFO_LEVEL, graph, "initial state");
 218             }
 219 
 220             suites.getHighTier().apply(graph, highTierContext);
 221             graph.maybeCompress();
 222             debug.dump(DebugContext.BASIC_LEVEL, graph, "After high tier");
 223 
 224             MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
 225             suites.getMidTier().apply(graph, midTierContext);
 226             graph.maybeCompress();
 227             debug.dump(DebugContext.BASIC_LEVEL, graph, "After mid tier");
 228 
 229             LowTierContext lowTierContext = new LowTierContext(providers, target);
 230             suites.getLowTier().apply(graph, lowTierContext);
 231             debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
 232 
 233             debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
 234             graph.logInliningTree();
 235         } catch (Throwable e) {
 236             throw debug.handle(e);
 237         } finally {
 238             graph.checkCancellation();
 239         }
 240     }
 241 
 242     protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) {
 243         if (compilationResult != null && compilationResult.getName() != null) {
 244             return compilationResult.getName();
 245         }
 246         ResolvedJavaMethod method = graph.method();
 247         if (method == null) {
 248             return "<unknown>";
 249         }
 250         return method.format("%H.%n(%p)");
 251     }
 252 }