1 /*
   2  * Copyright (c) 2016, 2017, 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 
  26 package jdk.tools.jaotc;
  27 
  28 import java.util.concurrent.TimeUnit;
  29 import java.util.concurrent.atomic.AtomicInteger;
  30 
  31 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  32 import org.graalvm.compiler.code.CompilationResult;
  33 import org.graalvm.compiler.core.GraalCompilerOptions;
  34 import org.graalvm.compiler.debug.DebugContext;
  35 import org.graalvm.compiler.debug.DebugContext.Activation;
  36 import org.graalvm.compiler.debug.TTY;
  37 import org.graalvm.compiler.options.OptionValues;
  38 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
  39 import org.graalvm.compiler.serviceprovider.GraalServices;
  40 
  41 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  42 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  43 import jdk.vm.ci.meta.ResolvedJavaMethod;
  44 import jdk.vm.ci.runtime.JVMCICompiler;
  45 
  46 /**
  47  * Represents a task in the compile queue.
  48  *
  49  * This class encapsulates all Graal-specific information that is used during offline AOT
  50  * compilation of classes. It also defines methods that parse compilation result of Graal to create
  51  * target-independent representation {@code BinaryContainer} of the intended target binary.
  52  */
  53 final class AOTCompilationTask implements Runnable, Comparable<Object> {
  54 
  55     private static final AtomicInteger ids = new AtomicInteger();
  56 
  57     private final Main main;
  58 
  59     private OptionValues graalOptions;
  60 
  61     /**
  62      * The compilation id of this task.
  63      */
  64     private final int id;
  65 
  66     private final AOTCompiledClass holder;
  67 
  68     /**
  69      * Method this task represents.
  70      */
  71     private final ResolvedJavaMethod method;
  72 
  73     private final AOTBackend aotBackend;
  74 
  75     /**
  76      * The result of this compilation task.
  77      */
  78     private CompiledMethodInfo result;
  79 
  80     AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
  81         this.main = main;
  82         this.graalOptions = graalOptions;
  83         this.id = ids.incrementAndGet();
  84         this.holder = holder;
  85         this.method = method;
  86         this.aotBackend = aotBackend;
  87     }
  88 
  89     /**
  90      * Compile a method or a constructor.
  91      */
  92     @Override
  93     @SuppressWarnings("try")
  94     public void run() {
  95         // Ensure a JVMCI runtime is initialized prior to Debug being initialized as the former
  96         // may include processing command line options used by the latter.
  97         HotSpotJVMCIRuntime.runtime();
  98 
  99         AOTCompiler.logCompilation(JavaMethodInfo.uniqueMethodName(method), "Compiling");
 100 
 101         final long threadId = Thread.currentThread().getId();
 102 
 103         final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed() && GraalServices.isThreadAllocatedMemorySupported();
 104         if (printCompilation) {
 105             TTY.println(getMethodDescription() + "...");
 106         }
 107 
 108         final long start;
 109         final long allocatedBytesBefore;
 110         if (printCompilation) {
 111             start = System.currentTimeMillis();
 112             allocatedBytesBefore = GraalServices.getThreadAllocatedBytes(threadId);
 113         } else {
 114             start = 0L;
 115             allocatedBytesBefore = 0L;
 116         }
 117 
 118         CompilationResult compResult = null;
 119         final long startTime = System.currentTimeMillis();
 120         SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
 121         try (DebugContext debug = DebugContext.create(graalOptions, new GraalDebugHandlersFactory(snippetReflection)); Activation a = debug.activate()) {
 122             compResult = aotBackend.compileMethod(method, debug);
 123         }
 124         final long endTime = System.currentTimeMillis();
 125 
 126         if (printCompilation) {
 127             final long stop = System.currentTimeMillis();
 128             final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1;
 129             final long allocatedBytesAfter = GraalServices.getThreadAllocatedBytes(threadId);
 130             final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
 131 
 132             TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
 133         }
 134 
 135         if (compResult == null) {
 136             result = null;
 137             return;
 138         }
 139 
 140         // For now precision to the nearest second is sufficient.
 141         LogPrinter.writeLog("    Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
 142         if (main.options.debug) {
 143             aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
 144         }
 145 
 146         result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend(), graalOptions));
 147     }
 148 
 149     private String getMethodDescription() {
 150         return String.format("%-6d aot %s %s", getId(), JavaMethodInfo.uniqueMethodName(method),
 151                         getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
 152     }
 153 
 154     private int getId() {
 155         return id;
 156     }
 157 
 158     private static int getEntryBCI() {
 159         return JVMCICompiler.INVOCATION_ENTRY_BCI;
 160     }
 161 
 162     ResolvedJavaMethod getMethod() {
 163         return method;
 164     }
 165 
 166     /**
 167      * Returns the holder of this method as a {@link AOTCompiledClass}.
 168      *
 169      * @return the holder of this method
 170      */
 171     AOTCompiledClass getHolder() {
 172         return holder;
 173     }
 174 
 175     /**
 176      * Returns the result of this compilation task.
 177      *
 178      * @return result of this compilation task
 179      */
 180     CompiledMethodInfo getResult() {
 181         return result;
 182     }
 183 
 184     @Override
 185     public int compareTo(Object obj) {
 186         AOTCompilationTask other = (AOTCompilationTask) obj;
 187         return this.id - other.id;
 188     }
 189 
 190     @Override
 191     public boolean equals(Object obj) {
 192         if (this == obj) {
 193             return true;
 194         }
 195         if (obj == null) {
 196             return false;
 197         }
 198         if (getClass() != obj.getClass()) {
 199             return false;
 200         }
 201         AOTCompilationTask other = (AOTCompilationTask) obj;
 202         return (this.id == other.id);
 203     }
 204 
 205     @Override
 206     public int hashCode() {
 207         return 31 + id;
 208     }
 209 
 210 }