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