1 /*
   2  * Copyright (c) 2012, 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 package com.oracle.graal.hotspot;
  24 
  25 import static com.oracle.graal.nodes.StructuredGraph.*;
  26 import static com.oracle.graal.phases.common.InliningUtil.*;
  27 
  28 import java.lang.reflect.Modifier;
  29 import java.util.concurrent.*;
  30 
  31 import com.oracle.graal.api.code.*;
  32 import com.oracle.graal.api.meta.*;
  33 import com.oracle.graal.compiler.*;
  34 import com.oracle.graal.debug.*;
  35 import com.oracle.graal.debug.internal.*;
  36 import com.oracle.graal.hotspot.meta.*;
  37 import com.oracle.graal.nodes.*;
  38 import com.oracle.graal.nodes.spi.*;
  39 import com.oracle.graal.phases.*;
  40 
  41 public final class CompilationTask implements Runnable, Comparable<CompilationTask> {
  42 
  43     public static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
  44 
  45         @Override
  46         protected Boolean initialValue() {
  47             return Boolean.valueOf(Thread.currentThread() instanceof CompilerThread);
  48         }
  49     };
  50 
  51     private volatile boolean cancelled;
  52     private volatile boolean inProgress;
  53 
  54     private final HotSpotGraalRuntime graalRuntime;
  55     private final PhasePlan plan;
  56     private final OptimisticOptimizations optimisticOpts;
  57     private final HotSpotResolvedJavaMethod method;
  58     private final int entryBCI;
  59     private final int id;
  60     private final int priority;
  61 
  62     public static CompilationTask create(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int entryBCI, int id, int priority) {
  63         return new CompilationTask(graalRuntime, plan, optimisticOpts, method, entryBCI, id, priority);
  64     }
  65 
  66     private CompilationTask(HotSpotGraalRuntime graalRuntime, PhasePlan plan, OptimisticOptimizations optimisticOpts, HotSpotResolvedJavaMethod method, int entryBCI, int id, int priority) {
  67         this.graalRuntime = graalRuntime;
  68         this.plan = plan;
  69         this.method = method;
  70         this.optimisticOpts = optimisticOpts;
  71         this.entryBCI = entryBCI;
  72         this.id = id;
  73         this.priority = priority;
  74     }
  75 
  76     public ResolvedJavaMethod getMethod() {
  77         return method;
  78     }
  79 
  80     public int getPriority() {
  81         return priority;
  82     }
  83 
  84     public void cancel() {
  85         cancelled = true;
  86     }
  87 
  88     public boolean isInProgress() {
  89         return inProgress;
  90     }
  91 
  92     public boolean isCancelled() {
  93         return cancelled;
  94     }
  95 
  96     public int getEntryBCI() {
  97         return entryBCI;
  98     }
  99 
 100     public void run() {
 101         withinEnqueue.set(Boolean.FALSE);
 102         try {
 103             if (cancelled) {
 104                 return;
 105             }
 106             inProgress = true;
 107             if (GraalOptions.DynamicCompilePriority) {
 108                 int threadPriority = priority < GraalOptions.SlowQueueCutoff ? Thread.NORM_PRIORITY : Thread.MIN_PRIORITY;
 109                 if (Thread.currentThread().getPriority() != threadPriority) {
 110                     Thread.currentThread().setPriority(threadPriority);
 111                 }
 112             }
 113             runCompilation();
 114         } finally {
 115             if (method.currentTask() == this) {
 116                 method.setCurrentTask(null);
 117             }
 118             graalRuntime.getCompilerToVM().clearQueuedForCompilation(method);
 119             inProgress = false;
 120             withinEnqueue.set(Boolean.TRUE);
 121         }
 122     }
 123 
 124     /**
 125      * Time spent in compilation.
 126      */
 127     public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
 128 
 129     public void runCompilation() {
 130         CompilationStatistics stats = CompilationStatistics.create(method, entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI);
 131         try (TimerCloseable a = CompilationTime.start()) {
 132             final boolean printCompilation = GraalOptions.PrintCompilation && !TTY.isSuppressed();
 133             if (printCompilation) {
 134                 TTY.println(String.format("%-6d Graal %-70s %-45s %-50s %s...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature(),
 135                                 entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") "));
 136             }
 137             if (GraalOptions.HotSpotPrintCompilation) {
 138                 printCompilation();
 139             }
 140 
 141             CompilationResult result = null;
 142             TTY.Filter filter = new TTY.Filter(GraalOptions.PrintFilter, method);
 143             long start = System.currentTimeMillis();
 144             try {
 145                 result = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable<CompilationResult>() {
 146 
 147                     @Override
 148                     public CompilationResult call() throws Exception {
 149                         graalRuntime.evictDeoptedGraphs();
 150                         Replacements replacements = graalRuntime.getReplacements();
 151                         StructuredGraph graph = replacements.getMethodSubstitution(method);
 152                         if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
 153                             graph = new StructuredGraph(method, entryBCI);
 154                         } else {
 155                             // Compiling method substitution - must clone the graph
 156                             graph = graph.copy();
 157                         }
 158                         InlinedBytecodes.add(method.getCodeSize());
 159                         return GraalCompiler.compileMethod(graalRuntime.getRuntime(), replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan,
 160                                         optimisticOpts, method.getSpeculationLog());
 161                     }
 162                 });
 163             } finally {
 164                 filter.remove();
 165                 if (printCompilation) {
 166                     TTY.println(String.format("%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, (result != null ? result.getTargetCodeSize() : -1)));
 167                 }
 168             }
 169 
 170             installMethod(result);
 171         } catch (BailoutException bailout) {
 172             Debug.metric("Bailouts").increment();
 173             if (GraalOptions.ExitVMOnBailout) {
 174                 TTY.cachedOut.println(MetaUtil.format("Bailout in %H.%n(%p)", method));
 175                 bailout.printStackTrace(TTY.cachedOut);
 176                 System.exit(-1);
 177             } else if (GraalOptions.PrintBailout) {
 178                 TTY.cachedOut.println(MetaUtil.format("Bailout in %H.%n(%p)", method));
 179                 bailout.printStackTrace(TTY.cachedOut);
 180             }
 181         } catch (Throwable t) {
 182             if (GraalOptions.ExitVMOnException) {
 183                 t.printStackTrace(TTY.cachedOut);
 184                 System.exit(-1);
 185             }
 186         }
 187         stats.finish(method);
 188     }
 189 
 190     /**
 191      * Print a HotSpot-style compilation message to the console.
 192      */
 193     private void printCompilation() {
 194         final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
 195         final int mod = method.getModifiers();
 196         TTY.println(String.format("%7d %4d %c%c%c%c%c       %s %s(%d bytes)",
 197                     0, id,
 198                     isOSR ? '%' : ' ',
 199                     Modifier.isSynchronized(mod) ? 's' : ' ',
 200                     ' ',
 201                     ' ',
 202                     Modifier.isNative(mod) ? 'n' : ' ',
 203                     MetaUtil.format("%H::%n(%p)", method),
 204                     isOSR ? "@ " + entryBCI + " " : "", method.getCodeSize()));
 205     }
 206 
 207     private void installMethod(final CompilationResult compResult) {
 208         Debug.scope("CodeInstall", new Object[]{new DebugDumpScope(String.valueOf(id), true), graalRuntime.getRuntime(), method}, new Runnable() {
 209 
 210             @Override
 211             public void run() {
 212                 HotSpotInstalledCode installedCode = graalRuntime.getRuntime().installMethod(method, entryBCI, compResult);
 213                 if (Debug.isDumpEnabled()) {
 214                     Debug.dump(new Object[]{compResult, installedCode}, "After code installation");
 215                 }
 216             }
 217 
 218         });
 219     }
 220 
 221     @Override
 222     public int compareTo(CompilationTask o) {
 223         if (priority < o.priority) {
 224             return -1;
 225         }
 226         if (priority > o.priority) {
 227             return 1;
 228         }
 229         return id < o.id ? -1 : (id > o.id ? 1 : 0);
 230     }
 231 
 232     @Override
 233     public String toString() {
 234         return "Compilation[id=" + id + ", prio=" + priority + " " + MetaUtil.format("%H.%n(%p)", method) + (entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "@" + entryBCI) + "]";
 235     }
 236 }