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 static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
27import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
28import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
29
30import java.io.PrintWriter;
31import java.text.MessageFormat;
32import java.util.List;
33import java.util.ListIterator;
34import java.util.Set;
35
36import jdk.tools.jaotc.binformat.BinaryContainer;
37import jdk.tools.jaotc.Options.Option;
38
39import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
40import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
41import org.graalvm.compiler.debug.DebugContext;
42import org.graalvm.compiler.debug.DebugContext.Activation;
43import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
44import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
45import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
46import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues;
47import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
48import org.graalvm.compiler.hotspot.HotSpotHostBackend;
49import org.graalvm.compiler.java.GraphBuilderPhase;
50import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
51import org.graalvm.compiler.options.OptionValues;
52import org.graalvm.compiler.phases.BasePhase;
53import org.graalvm.compiler.phases.PhaseSuite;
54import org.graalvm.compiler.phases.tiers.HighTierContext;
55import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
56import org.graalvm.compiler.runtime.RuntimeProvider;
57
58import jdk.vm.ci.meta.MetaAccessProvider;
59import jdk.vm.ci.meta.ResolvedJavaMethod;
60import jdk.vm.ci.runtime.JVMCI;
61
62public final class Main {
63
64    final Options options = new Options();
65    private PrintWriter log;
66    LogPrinter printer;
67    GraalFilters filters;
68
69    private static final int EXIT_OK = 0;        // No errors.
70    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
71    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
72
73    private static final String PROGNAME = "jaotc";
74
75    private static final String JVM_VERSION = System.getProperty("java.runtime.version");
76
77    public static void main(String[] args) throws Exception {
78        Main t = new Main();
79        final int exitCode = t.run(args);
80        System.exit(exitCode);
81    }
82
83    private int run(String[] args) {
84        log = new PrintWriter(System.out);
85        printer = new LogPrinter(this, log);
86
87        try {
88            Options.handleOptions(this, args);
89            if (options.help) {
90                showHelp();
91                return EXIT_OK;
92            }
93            if (options.version) {
94                showVersion();
95                return EXIT_OK;
96            }
97
98            printer.printlnInfo("Compiling " + options.outputName + "...");
99            final long start = System.currentTimeMillis();
100            if (!run()) {
101                return EXIT_ABNORMAL;
102            }
103            final long end = System.currentTimeMillis();
104            printer.printlnInfo("Total time: " + (end - start) + " ms");
105
106            return EXIT_OK;
107        } catch (Options.BadArgs e) {
108            printer.reportError(e.key, e.args);
109            if (e.showUsage) {
110                showUsage();
111            }
112            return EXIT_CMDERR;
113        } catch (Exception e) {
114            e.printStackTrace();
115            return EXIT_ABNORMAL;
116        } finally {
117            log.flush();
118        }
119    }
120
121    @SuppressWarnings("try")
122    private boolean run() throws Exception {
123        LogPrinter.openLog();
124
125        try {
126
127            final Linker linker = new Linker(this);
128            final String objectFileName = linker.objFile();
129            final Collector collector = new Collector(this);
130            Set<Class<?>> classesToCompile;
131
132            try (Timer t = new Timer(this, "")) {
133                classesToCompile = collector.collectClassesToCompile();
134                printer.printInfo(classesToCompile.size() + " classes found");
135            }
136
137            OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
138            // Setting -Dgraal.TieredAOT overrides --compile-for-tiered
139            if (!TieredAOT.hasBeenSet(graalOptions)) {
140                graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered);
141            }
142            graalOptions = new OptionValues(graalOptions, GeneratePIC, true, ImmutableCode, true);
143            GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler(JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions));
144            HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
145            HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
146            MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
147            filters = new GraalFilters(metaAccess);
148
149            List<AOTCompiledClass> classes;
150
151            try (Timer t = new Timer(this, "")) {
152                classes = collector.collectMethodsToCompile(classesToCompile, metaAccess);
153            }
154
155            // Free memory!
156            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
157                printer.printMemoryUsage();
158                classesToCompile = null;
159                System.gc();
160            }
161
162            AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend);
163            SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
164            AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
165            classes = compiler.compileClasses(classes);
166
167            GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
168            PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite();
169            ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
170            GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
171
172            // Free memory!
173            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
174                printer.printMemoryUsage();
175                aotBackend = null;
176                compiler = null;
177                System.gc();
178            }
179
180            BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
181            DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
182
183            try (DebugContext debug = DebugContext.create(graalOptions, new GraalDebugHandlersFactory(snippetReflection)); Activation a = debug.activate()) {
184                dataBuilder.prepareData(debug);
185            }
186
187            // Print information about section sizes
188            printer.containersInfo(binaryContainer);
189
190            // Free memory!
191            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
192                printer.printMemoryUsage();
193                backend = null;
194                for (AOTCompiledClass aotCompClass : classes) {
195                    aotCompClass.clear();
196                }
197                classes.clear();
198                classes = null;
199                dataBuilder = null;
200                binaryContainer.freeMemory();
201                System.gc();
202            }
203
204            try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
205                binaryContainer.createBinary(objectFileName);
206            }
207
208            // Free memory!
209            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
210                printer.printMemoryUsage();
211                binaryContainer = null;
212                System.gc();
213            }
214
215            try (Timer t = new Timer(this, "Creating shared library: " + linker.libFile())) {
216                linker.link();
217            }
218
219            printer.printVerbose("Final memory  ");
220            printer.printMemoryUsage();
221            printer.printlnVerbose("");
222
223        } finally {
224            LogPrinter.closeLog();
225        }
226        return true;
227    }
228
229    void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) {
230        String methodName = JavaMethodInfo.uniqueMethodName(resolvedMethod);
231
232        if (options.debug) {
233            printer.printError("Failed compilation: " + methodName + ": " + e);
234        }
235
236        // Ignore some exceptions when meta-compiling Graal.
237        if (GraalFilters.shouldIgnoreException(e)) {
238            return;
239        }
240
241        LogPrinter.writeLog("Failed compilation of method " + methodName + message);
242
243        if (!options.debug) {
244            printer.printError("Failed compilation: " + methodName + ": " + e);
245        }
246
247        if (options.verbose) {
248            e.printStackTrace(log);
249        }
250
251        if (options.exitOnError) {
252            System.exit(1);
253        }
254    }
255
256    void warning(String key, Object... args) {
257        log.println("Warning: " + MessageFormat.format(key, args));
258        log.flush();
259    }
260
261    private void showUsage() {
262        log.println("Usage: " + PROGNAME + " <options> list");
263        log.println("use --help for a list of possible options");
264        log.flush();
265    }
266
267    private void showHelp() {
268        log.println("Usage: " + PROGNAME + " <options> list");
269        log.println();
270        log.println("  list       A : separated list of class names, modules, jar files");
271        log.println("             or directories which contain class files.");
272        log.println();
273        log.println("where options include:");
274        for (Option o : Options.recognizedOptions) {
275            String name = o.aliases[0].substring(1); // there must always be at least one name
276            name = name.charAt(0) == '-' ? name.substring(1) : name;
277            if (o.isHidden() || name.equals("h")) {
278                continue;
279            }
280            log.println(o.help);
281        }
282        log.flush();
283    }
284
285    private void showVersion() {
286        log.println(PROGNAME + " " + JVM_VERSION);
287    }
288}
289