Main.java revision 12968:4d8a004e5c6d
1193326Sed/*
2193326Sed * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
3193326Sed * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4193326Sed *
5193326Sed * This code is free software; you can redistribute it and/or modify it
6193326Sed * under the terms of the GNU General Public License version 2 only, as
7193326Sed * published by the Free Software Foundation.
8193326Sed *
9193326Sed * This code is distributed in the hope that it will be useful, but WITHOUT
10193326Sed * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11193326Sed * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12193326Sed * version 2 for more details (a copy is included in the LICENSE file that
13193326Sed * accompanied this code).
14193326Sed *
15193326Sed * You should have received a copy of the GNU General Public License version
16193326Sed * 2 along with this work; if not, write to the Free Software Foundation,
17193326Sed * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18193326Sed *
19193326Sed * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20193326Sed * or visit www.oracle.com if you need additional information or have any
21195341Sed * questions.
22193326Sed */
23193326Sed
24193326Sedpackage jdk.tools.jaotc;
25193326Sed
26226633Sdimimport static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
27193326Sedimport static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
28199482Srdivackyimport static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
29249423Sdim
30198092Srdivackyimport java.io.BufferedReader;
31193326Sedimport java.io.File;
32234353Sdimimport java.io.FileNotFoundException;
33193326Sedimport java.io.FileReader;
34193326Sedimport java.io.FileWriter;
35198092Srdivackyimport java.io.IOException;
36193326Sedimport java.io.InputStream;
37198092Srdivackyimport java.io.InputStreamReader;
38210299Sedimport java.io.PrintWriter;
39210299Sedimport java.lang.management.ManagementFactory;
40210299Sedimport java.lang.management.MemoryUsage;
41226633Sdimimport java.nio.file.Path;
42193326Sedimport java.nio.file.Paths;
43199482Srdivackyimport java.text.MessageFormat;
44249423Sdimimport java.util.ArrayList;
45195341Sedimport java.util.Date;
46193326Sedimport java.util.HashSet;
47193326Sedimport java.util.LinkedList;
48193326Sedimport java.util.List;
49import java.util.ListIterator;
50import java.util.Set;
51import java.util.stream.Stream;
52
53import jdk.tools.jaotc.binformat.BinaryContainer;
54import jdk.tools.jaotc.binformat.ByteContainer;
55import jdk.tools.jaotc.collect.*;
56import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
57import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
58import jdk.tools.jaotc.collect.jar.JarSourceProvider;
59import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
60import jdk.tools.jaotc.utils.Timer;
61
62import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
63import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
64import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
65import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
66import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues;
67import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
68import org.graalvm.compiler.hotspot.HotSpotHostBackend;
69import org.graalvm.compiler.java.GraphBuilderPhase;
70import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
71import org.graalvm.compiler.options.OptionValues;
72import org.graalvm.compiler.phases.BasePhase;
73import org.graalvm.compiler.phases.PhaseSuite;
74import org.graalvm.compiler.phases.tiers.HighTierContext;
75import org.graalvm.compiler.runtime.RuntimeProvider;
76
77import jdk.vm.ci.meta.MetaAccessProvider;
78import jdk.vm.ci.meta.ResolvedJavaMethod;
79import jdk.vm.ci.meta.ResolvedJavaType;
80import jdk.vm.ci.runtime.JVMCI;
81
82public class Main implements LogPrinter {
83    static class BadArgs extends Exception {
84        private static final long serialVersionUID = 1L;
85        final String key;
86        final Object[] args;
87        boolean showUsage;
88
89        BadArgs(String key, Object... args) {
90            super(MessageFormat.format(key, args));
91            this.key = key;
92            this.args = args;
93        }
94
95        BadArgs showUsage(boolean b) {
96            showUsage = b;
97            return this;
98        }
99    }
100
101    abstract static class Option {
102        final String help;
103        final boolean hasArg;
104        final String[] aliases;
105
106        Option(String help, boolean hasArg, String... aliases) {
107            this.help = help;
108            this.hasArg = hasArg;
109            this.aliases = aliases;
110        }
111
112        boolean isHidden() {
113            return false;
114        }
115
116        boolean matches(String opt) {
117            for (String a : aliases) {
118                if (a.equals(opt)) {
119                    return true;
120                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
121                    return true;
122                }
123            }
124            return false;
125        }
126
127        boolean ignoreRest() {
128            return false;
129        }
130
131        abstract void process(Main task, String opt, String arg) throws BadArgs;
132    }
133
134    static Option[] recognizedOptions = {new Option("  --output <file>            Output file name", true, "--output") {
135        @Override
136        void process(Main task, String opt, String arg) {
137            String name = arg;
138            task.options.outputName = name;
139        }
140    }, new Option("  --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
141        @Override
142        void process(Main task, String opt, String arg) {
143            task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
144        }
145    }, new Option("  --jar <jarfiles>           List of jar files to compile", true, "--jar") {
146        @Override
147        void process(Main task, String opt, String arg) {
148            task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
149        }
150    }, new Option("  --module <modules>         List of modules to compile", true, "--module") {
151        @Override
152        void process(Main task, String opt, String arg) {
153            task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
154        }
155    }, new Option("  --directory <dirs>         List of directories where to search for files to compile", true, "--directory") {
156        @Override
157        void process(Main task, String opt, String arg) {
158            task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
159        }
160    }, new Option("  --search-path <dirs>       List of directories where to search for specified files", true, "--search-path") {
161        @Override
162        void process(Main task, String opt, String arg) {
163            String[] elements = arg.split(":");
164            task.options.searchPath.add(elements);
165        }
166    }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
167        @Override
168        void process(Main task, String opt, String arg) {
169            task.options.methodList = arg;
170        }
171    }, new Option("  --compile-for-tiered       Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
172        @Override
173        void process(Main task, String opt, String arg) {
174            task.options.tiered = true;
175        }
176    }, new Option("  --compile-with-assertions  Compile with java assertions", false, "--compile-with-assertions") {
177        @Override
178        void process(Main task, String opt, String arg) {
179            task.options.compileWithAssertions = true;
180        }
181    }, new Option("  --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
182        @Override
183        void process(Main task, String opt, String arg) {
184            int threads = Integer.parseInt(arg);
185            final int available = Runtime.getRuntime().availableProcessors();
186            if (threads <= 0) {
187                task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
188                threads = available;
189            }
190            if (threads > available) {
191                task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
192            }
193            task.options.threads = Integer.min(threads, available);
194        }
195    }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
196        @Override
197        void process(Main task, String opt, String arg) {
198            task.options.ignoreClassLoadingErrors = true;
199        }
200    }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
201        @Override
202        void process(Main task, String opt, String arg) {
203            task.options.exitOnError = true;
204        }
205    }, new Option("  --info                     Print information during compilation", false, "--info") {
206        @Override
207        void process(Main task, String opt, String arg) throws BadArgs {
208            task.options.info = true;
209        }
210    }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
211        @Override
212        void process(Main task, String opt, String arg) throws BadArgs {
213            task.options.info = true;
214            task.options.verbose = true;
215        }
216    }, new Option("  --debug                    Print debug information", false, "--debug") {
217        @Override
218        void process(Main task, String opt, String arg) throws BadArgs {
219            task.options.info = true;
220            task.options.verbose = true;
221            task.options.debug = true;
222        }
223    }, new Option("  --help                     Print this usage message", false, "--help") {
224        @Override
225        void process(Main task, String opt, String arg) {
226            task.options.help = true;
227        }
228    }, new Option("  --version                  Version information", false, "--version") {
229        @Override
230        void process(Main task, String opt, String arg) {
231            task.options.version = true;
232        }
233    }, new Option("  --linker-path              Full path to linker executable", true, "--linker-path") {
234        @Override
235        void process(Main task, String opt, String arg) {
236            task.options.linkerpath = arg;
237        }
238    }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
239        @Override
240        void process(Main task, String opt, String arg) {
241        }
242    }};
243
244    public static class Options {
245        public List<SearchFor> files = new LinkedList<>();
246        public String outputName = "unnamed.so";
247        public String methodList;
248        public List<ClassSource> sources = new ArrayList<>();
249        public String linkerpath = null;
250        public SearchPath searchPath = new SearchPath();
251
252        /**
253         * We don't see scaling beyond 16 threads.
254         */
255        private static final int COMPILER_THREADS = 16;
256
257        public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
258
259        public boolean ignoreClassLoadingErrors;
260        public boolean exitOnError;
261        public boolean info;
262        public boolean verbose;
263        public boolean debug;
264        public boolean help;
265        public boolean version;
266        public boolean compileWithAssertions;
267        public boolean tiered;
268    }
269
270    /* package */final Options options = new Options();
271
272    /**
273     * Logfile.
274     */
275    private static FileWriter logFile = null;
276
277    private static final int EXIT_OK = 0;        // No errors.
278    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
279    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
280
281    private static final String PROGNAME = "jaotc";
282
283    private static final String JVM_VERSION = System.getProperty("java.runtime.version");
284
285    public static void main(String[] args) throws Exception {
286        Main t = new Main();
287        final int exitCode = t.run(args);
288        System.exit(exitCode);
289    }
290
291    private int run(String[] args) {
292        if (log == null) {
293            log = new PrintWriter(System.out);
294        }
295
296        try {
297            handleOptions(args);
298            if (options.help) {
299                showHelp();
300                return EXIT_OK;
301            }
302            if (options.version) {
303                showVersion();
304                return EXIT_OK;
305            }
306
307            printlnInfo("Compiling " + options.outputName + "...");
308            final long start = System.currentTimeMillis();
309            if (!run()) {
310                return EXIT_ABNORMAL;
311            }
312            final long end = System.currentTimeMillis();
313            printlnInfo("Total time: " + (end - start) + " ms");
314
315            return EXIT_OK;
316        } catch (BadArgs e) {
317            reportError(e.key, e.args);
318            if (e.showUsage) {
319                showUsage();
320            }
321            return EXIT_CMDERR;
322        } catch (Exception e) {
323            e.printStackTrace();
324            return EXIT_ABNORMAL;
325        } finally {
326            log.flush();
327        }
328    }
329
330    private static String humanReadableByteCount(long bytes) {
331        int unit = 1024;
332
333        if (bytes < unit) {
334            return bytes + " B";
335        }
336
337        int exp = (int) (Math.log(bytes) / Math.log(unit));
338        char pre = "KMGTPE".charAt(exp - 1);
339        return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
340    }
341
342    void printMemoryUsage() {
343        if (options.verbose) {
344            MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
345            float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
346            log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
347                            humanReadableByteCount(memusage.getUsed()),
348                            humanReadableByteCount(memusage.getCommitted()),
349                            freeratio * 100);
350        }
351    }
352
353    /**
354     * Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012
355     */
356    public enum VSVERSIONS {
357        VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
358        VS2015("VS140COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"),
359        VS2012("VS110COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe");
360
361        private final String envvariable;
362        private final String wkp;
363
364        VSVERSIONS(String envvariable, String wellknownpath) {
365            this.envvariable = envvariable;
366            this.wkp = wellknownpath;
367        }
368
369        String EnvVariable() {
370            return envvariable;
371        }
372
373        String WellKnownPath() {
374            return wkp;
375        }
376    }
377
378    /**
379     * Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012
380     */
381    private static String getWindowsLinkPath() {
382        String link = "\\VC\\bin\\amd64\\link.exe";
383
384        /**
385         * First try searching the paths pointed to by the VS environment variables.
386         */
387        for (VSVERSIONS vs : VSVERSIONS.values()) {
388            String vspath = System.getenv(vs.EnvVariable());
389            if (vspath != null) {
390                File commonTools = new File(vspath);
391                File vsRoot = commonTools.getParentFile().getParentFile();
392                File linkPath = new File(vsRoot, link);
393                if (linkPath.exists())
394                    return linkPath.getPath();
395            }
396        }
397
398        /**
399         * If we didn't find via the VS environment variables, try the well known paths
400         */
401        for (VSVERSIONS vs : VSVERSIONS.values()) {
402            String wkp = vs.WellKnownPath();
403            if (new File(wkp).exists()) {
404                return wkp;
405            }
406        }
407
408        return null;
409    }
410
411    @SuppressWarnings("try")
412    private boolean run() throws Exception {
413        openLog();
414
415        try {
416            CompilationSpec compilationRestrictions = collectSpecifiedMethods();
417
418            Set<Class<?>> classesToCompile = new HashSet<>();
419
420            try (Timer t = new Timer(this, "")) {
421                FileSupport fileSupport = new FileSupport();
422                ClassSearch lookup = new ClassSearch();
423                lookup.addProvider(new ModuleSourceProvider());
424                lookup.addProvider(new ClassNameSourceProvider(fileSupport));
425                lookup.addProvider(new JarSourceProvider());
426                lookup.addProvider(new DirectorySourceProvider(fileSupport));
427
428                List<LoadedClass> found = null;
429                try {
430                    found = lookup.search(options.files, options.searchPath);
431                } catch (InternalError e) {
432                    reportError(e);
433                    return false;
434                }
435
436                for (LoadedClass loadedClass : found) {
437                    classesToCompile.add(loadedClass.getLoadedClass());
438                }
439
440                printInfo(classesToCompile.size() + " classes found");
441            }
442
443            OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
444            // Setting -Dgraal.TieredAOT overrides --compile-for-tiered
445            if (!TieredAOT.hasBeenSet(graalOptions)) {
446                graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered);
447            }
448            graalOptions = new OptionValues(HotSpotGraalOptionValues.HOTSPOT_OPTIONS, GeneratePIC, true, ImmutableCode, true);
449            GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler(JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions));
450            HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
451            HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
452            MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
453            GraalFilters filters = new GraalFilters(metaAccess);
454
455            List<AOTCompiledClass> classes;
456
457            try (Timer t = new Timer(this, "")) {
458                classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess);
459            }
460
461            // Free memory!
462            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
463                printMemoryUsage();
464                compilationRestrictions = null;
465                classesToCompile = null;
466                System.gc();
467            }
468
469            AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, filters);
470            AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
471            classes = compiler.compileClasses(classes);
472
473            GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
474            PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite();
475            ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
476            GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
477
478            // Free memory!
479            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
480                printMemoryUsage();
481                aotBackend = null;
482                compiler = null;
483                System.gc();
484            }
485
486            BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
487            DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
488            dataBuilder.prepareData();
489
490            // Print information about section sizes
491            printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
492            printContainerInfo(binaryContainer.getConfigContainer());
493            printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
494            printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
495            printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
496            printContainerInfo(binaryContainer.getStubsOffsetsContainer());
497            printContainerInfo(binaryContainer.getMethodMetadataContainer());
498            printContainerInfo(binaryContainer.getCodeContainer());
499            printContainerInfo(binaryContainer.getCodeSegmentsContainer());
500            printContainerInfo(binaryContainer.getConstantDataContainer());
501            printContainerInfo(binaryContainer.getMetaspaceGotContainer());
502            printContainerInfo(binaryContainer.getMetadataGotContainer());
503            printContainerInfo(binaryContainer.getMethodStateContainer());
504            printContainerInfo(binaryContainer.getOopGotContainer());
505            printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
506
507            // Free memory!
508            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
509                printMemoryUsage();
510                backend = null;
511                for (AOTCompiledClass aotCompClass : classes) {
512                    aotCompClass.clear();
513                }
514                classes.clear();
515                classes = null;
516                dataBuilder = null;
517                binaryContainer.freeMemory();
518                System.gc();
519            }
520
521            String name = options.outputName;
522            String objectFileName = name;
523
524            // [TODO] The jtregs tests expect .so extension so don't
525            // override with platform specific file extension until the
526            // tests are fixed.
527            String libraryFileName = name;
528
529            String linkerCmd;
530            String linkerPath;
531            String osName = System.getProperty("os.name");
532
533            if (name.endsWith(".so")) {
534                objectFileName = name.substring(0, name.length() - ".so".length());
535            } else if (name.endsWith(".dylib")) {
536                objectFileName = name.substring(0, name.length() - ".dylib".length());
537            } else if (name.endsWith(".dll")) {
538                objectFileName = name.substring(0, name.length() - ".dll".length());
539            }
540
541            switch (osName) {
542                case "Linux":
543                    // libraryFileName = options.outputName + ".so";
544                    objectFileName = objectFileName + ".o";
545                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
546                    linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
547                    break;
548                case "SunOS":
549                    // libraryFileName = options.outputName + ".so";
550                    objectFileName = objectFileName + ".o";
551                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
552                    linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
553                    break;
554                case "Mac OS X":
555                    // libraryFileName = options.outputName + ".dylib";
556                    objectFileName = objectFileName + ".o";
557                    linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
558                    linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
559                    break;
560                default:
561                    if (osName.startsWith("Windows")) {
562                        // libraryFileName = options.outputName + ".dll";
563                        objectFileName = objectFileName + ".obj";
564                        linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath();
565                        if (linkerPath == null) {
566                            throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
567                        }
568                        linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
569                        break;
570                    } else
571                        throw new InternalError("Unsupported platform: " + osName);
572            }
573
574            try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
575                binaryContainer.createBinary(objectFileName, JVM_VERSION);
576            }
577
578            // Free memory!
579            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
580                printMemoryUsage();
581                binaryContainer = null;
582                System.gc();
583            }
584
585            try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) {
586                Process p = Runtime.getRuntime().exec(linkerCmd);
587                final int exitCode = p.waitFor();
588                if (exitCode != 0) {
589                    InputStream stderr = p.getErrorStream();
590                    BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
591                    Stream<String> lines = br.lines();
592                    StringBuilder sb = new StringBuilder();
593                    lines.iterator().forEachRemaining(e -> sb.append(e));
594                    throw new InternalError(sb.toString());
595                }
596                File objFile = new File(objectFileName);
597                if (objFile.exists()) {
598                    if (!objFile.delete()) {
599                        throw new InternalError("Failed to delete " + objectFileName + " file");
600                    }
601                }
602                // Make non-executable for all.
603                File libFile = new File(libraryFileName);
604                if (libFile.exists() && !osName.startsWith("Windows")) {
605                    if (!libFile.setExecutable(false, false)) {
606                        throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
607                    }
608                }
609            }
610
611            printVerbose("Final memory  ");
612            printMemoryUsage();
613            printlnVerbose("");
614
615        } finally {
616            closeLog();
617        }
618        return true;
619    }
620
621    private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
622        for (ResolvedJavaMethod m : methods) {
623            addMethod(aotClass, m, compilationRestrictions, filters);
624        }
625    }
626
627    private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) {
628        // Don't compile native or abstract methods.
629        if (!method.hasBytecodes()) {
630            return;
631        }
632        if (!compilationRestrictions.shouldCompileMethod(method)) {
633            return;
634        }
635        if (!filters.shouldCompileMethod(method)) {
636            return;
637        }
638
639        aotClass.addMethod(method);
640        printlnVerbose("  added " + method.getName() + method.getSignature().toMethodDescriptor());
641    }
642
643    private void printContainerInfo(ByteContainer container) {
644        printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
645    }
646
647    PrintWriter log;
648
649    private void handleOptions(String[] args) throws BadArgs {
650        if (args.length == 0) {
651            options.help = true;
652            return;
653        }
654
655        // Make checkstyle happy.
656        int i = 0;
657        for (; i < args.length; i++) {
658            String arg = args[i];
659
660            if (arg.charAt(0) == '-') {
661                Option option = getOption(arg);
662                String param = null;
663
664                if (option.hasArg) {
665                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
666                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
667                    } else if (i + 1 < args.length) {
668                        param = args[++i];
669                    }
670
671                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
672                        throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
673                    }
674                }
675
676                option.process(this, arg, param);
677
678                if (option.ignoreRest()) {
679                    break;
680                }
681            } else {
682                options.files.add(new SearchFor(arg));
683            }
684        }
685    }
686
687    private static Option getOption(String name) throws BadArgs {
688        for (Option o : recognizedOptions) {
689            if (o.matches(name)) {
690                return o;
691            }
692        }
693        throw new BadArgs("unknown option: {0}", name).showUsage(true);
694    }
695
696    public void printInfo(String message) {
697        if (options.info) {
698            log.print(message);
699            log.flush();
700        }
701    }
702
703    public void printlnInfo(String message) {
704        if (options.info) {
705            log.println(message);
706            log.flush();
707        }
708    }
709
710    public void printVerbose(String message) {
711        if (options.verbose) {
712            log.print(message);
713            log.flush();
714        }
715    }
716
717    public void printlnVerbose(String message) {
718        if (options.verbose) {
719            log.println(message);
720            log.flush();
721        }
722    }
723
724    public void printDebug(String message) {
725        if (options.debug) {
726            log.print(message);
727            log.flush();
728        }
729    }
730
731    public void printlnDebug(String message) {
732        if (options.debug) {
733            log.println(message);
734            log.flush();
735        }
736    }
737
738    public void printError(String message) {
739        log.println("Error: " + message);
740        log.flush();
741    }
742
743    private void reportError(Throwable e) {
744        log.println("Error: " + e.getMessage());
745        if (options.info) {
746            e.printStackTrace(log);
747        }
748        log.flush();
749    }
750
751    private void reportError(String key, Object... args) {
752        printError(MessageFormat.format(key, args));
753    }
754
755    private void warning(String key, Object... args) {
756        log.println("Warning: " + MessageFormat.format(key, args));
757        log.flush();
758    }
759
760    private void showUsage() {
761        log.println("Usage: " + PROGNAME + " <options> list");
762        log.println("use --help for a list of possible options");
763    }
764
765    private void showHelp() {
766        log.println("Usage: " + PROGNAME + " <options> list");
767        log.println();
768        log.println("  list       A : separated list of class names, modules, jar files");
769        log.println("             or directories which contain class files.");
770        log.println();
771        log.println("where options include:");
772        for (Option o : recognizedOptions) {
773            String name = o.aliases[0].substring(1); // there must always be at least one name
774            name = name.charAt(0) == '-' ? name.substring(1) : name;
775            if (o.isHidden() || name.equals("h")) {
776                continue;
777            }
778            log.println(o.help);
779        }
780    }
781
782    private void showVersion() {
783        log.println(PROGNAME + " " + JVM_VERSION);
784    }
785
786    /**
787     * Collect all method we should compile.
788     *
789     * @return array list of AOT classes which have compiled methods.
790     */
791    private List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) {
792        int total = 0;
793        int count = 0;
794        List<AOTCompiledClass> classes = new ArrayList<>();
795
796        for (Class<?> c : classesToCompile) {
797            ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
798            if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
799                AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
800                printlnVerbose(" Scanning " + c.getName());
801
802                // Constructors
803                try {
804                    ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
805                    addMethods(aotClass, ctors, compilationRestrictions, filters);
806                    total += ctors.length;
807                } catch (Throwable e) {
808                    // If we are running in JCK mode we ignore all exceptions.
809                    if (options.ignoreClassLoadingErrors) {
810                        printError(c.getName() + ": " + e);
811                    } else {
812                        throw new InternalError(e);
813                    }
814                }
815
816                // Methods
817                try {
818                    ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
819                    addMethods(aotClass, methods, compilationRestrictions, filters);
820                    total += methods.length;
821                } catch (Throwable e) {
822                    // If we are running in JCK mode we ignore all exceptions.
823                    if (options.ignoreClassLoadingErrors) {
824                        printError(c.getName() + ": " + e);
825                    } else {
826                        throw new InternalError(e);
827                    }
828                }
829
830                // Class initializer
831                try {
832                    ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
833                    if (clinit != null) {
834                        addMethod(aotClass, clinit, compilationRestrictions, filters);
835                        total++;
836                    }
837                } catch (Throwable e) {
838                    // If we are running in JCK mode we ignore all exceptions.
839                    if (options.ignoreClassLoadingErrors) {
840                        printError(c.getName() + ": " + e);
841                    } else {
842                        throw new InternalError(e);
843                    }
844                }
845
846                // Found any methods to compile? Add the class.
847                if (aotClass.hasMethods()) {
848                    classes.add(aotClass);
849                    count += aotClass.getMethodCount();
850                }
851            }
852        }
853        printInfo(total + " methods total, " + count + " methods to compile");
854        return classes;
855    }
856
857    /**
858     * If a file with compilation limitations is specified using the java property
859     * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions.
860     */
861    private CompilationSpec collectSpecifiedMethods() {
862        CompilationSpec compilationRestrictions = new CompilationSpec();
863        String methodListFileName = options.methodList;
864
865        if (methodListFileName != null && !methodListFileName.equals("")) {
866            try {
867                FileReader methListFile = new FileReader(methodListFileName);
868                BufferedReader readBuf = new BufferedReader(methListFile);
869                String line = null;
870                while ((line = readBuf.readLine()) != null) {
871                    String trimmedLine = line.trim();
872                    if (!trimmedLine.startsWith("#")) {
873                        String[] components = trimmedLine.split(" ");
874                        if (components.length == 2) {
875                            String directive = components[0];
876                            String pattern = components[1];
877                            switch (directive) {
878                                case "compileOnly":
879                                    compilationRestrictions.addCompileOnlyPattern(pattern);
880                                    break;
881                                case "exclude":
882                                    compilationRestrictions.addExcludePattern(pattern);
883                                    break;
884                                default:
885                                    System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
886                            }
887                        } else {
888                            if (!trimmedLine.equals("")) {
889                                System.out.println("Ignoring malformed line:\n\t " + line + "\n");
890                            }
891                        }
892                    }
893                }
894                readBuf.close();
895            } catch (FileNotFoundException e) {
896                throw new InternalError("Unable to open method list file: " + methodListFileName, e);
897            } catch (IOException e) {
898                throw new InternalError("Unable to read method list file: " + methodListFileName, e);
899            }
900        }
901
902        return compilationRestrictions;
903    }
904
905    private static void openLog() {
906        int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
907        if (v == 0) {
908            logFile = null;
909            return;
910        }
911        // Create log file in current directory
912        String fileName = "aot_compilation" + new Date().getTime() + ".log";
913        Path logFilePath = Paths.get("./", fileName);
914        String logFileName = logFilePath.toString();
915        try {
916            // Create file to which we do not append
917            logFile = new FileWriter(logFileName, false);
918        } catch (IOException e) {
919            System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
920            logFile = null;
921        }
922    }
923
924    public static void writeLog(String str) {
925        if (logFile != null) {
926            try {
927                logFile.write(str + "\n");
928                logFile.flush();
929            } catch (IOException e) {
930                // Print to console
931                System.out.println(str + "\n");
932            }
933        }
934    }
935
936    public static void closeLog() {
937        if (logFile != null) {
938            try {
939                logFile.close();
940            } catch (IOException e) {
941                // Do nothing
942            }
943        }
944    }
945}
946