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