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