hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java
changeset 42650 1f304d0c888b
child 46260 5de61384fba6
child 43405 1fab8e6866d7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java	Sun Dec 11 19:07:04 2016 -0800
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.tools.jaotc;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryUsage;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import jdk.tools.jaotc.binformat.BinaryContainer;
+import jdk.tools.jaotc.binformat.ByteContainer;
+import jdk.tools.jaotc.collect.ClassCollector;
+import jdk.tools.jaotc.utils.Timer;
+
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.HotSpotHostBackend;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.runtime.JVMCI;
+
+public class Main implements LogPrinter {
+    static {
+        GeneratePIC.setValue(true);
+        ImmutableCode.setValue(true);
+    }
+
+    static class BadArgs extends Exception {
+        private static final long serialVersionUID = 1L;
+        final String key;
+        final Object[] args;
+        boolean showUsage;
+
+        BadArgs(String key, Object... args) {
+            super(MessageFormat.format(key, args));
+            this.key = key;
+            this.args = args;
+        }
+
+        BadArgs showUsage(boolean b) {
+            showUsage = b;
+            return this;
+        }
+    }
+
+    abstract static class Option {
+        final String help;
+        final boolean hasArg;
+        final String[] aliases;
+
+        Option(String help, boolean hasArg, String... aliases) {
+            this.help = help;
+            this.hasArg = hasArg;
+            this.aliases = aliases;
+        }
+
+        boolean isHidden() {
+            return false;
+        }
+
+        boolean matches(String opt) {
+            for (String a : aliases) {
+                if (a.equals(opt)) {
+                    return true;
+                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        boolean ignoreRest() {
+            return false;
+        }
+
+        abstract void process(Main task, String opt, String arg) throws BadArgs;
+    }
+
+    static Option[] recognizedOptions = {new Option("  --module <name>            Module to compile", true, "--module") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.module = arg;
+        }
+    }, new Option("  --module-path <path>       Specify where to find module to compile", true, "--module-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.modulepath = arg;
+        }
+    }, new Option("  --output <file>            Output file name", true, "--output") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            String name = arg;
+            if (name.endsWith(".so")) {
+                name = name.substring(0, name.length() - ".so".length());
+            }
+            task.options.outputName = name;
+        }
+    }, new Option("  --compile-commands <file>  Name of file with compile commands", true, "--compile-commands") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.methodList = arg;
+        }
+    }, new Option("  --compile-for-tiered       Generated profiling code for tiered compilation", false, "--compile-for-tiered") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            TieredAOT.setValue(true);
+        }
+    }, new Option("  --classpath <path>         Specify where to find user class files", true, "--classpath", "--class-path") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.classpath = arg;
+        }
+    }, new Option("  --threads <number>         Number of compilation threads to be used", true, "--threads") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            int threads = Integer.parseInt(arg);
+            final int available = Runtime.getRuntime().availableProcessors();
+            if (threads <= 0) {
+                task.warning("invalid number of threads specified: {0}, using: {1}", threads, available);
+                threads = available;
+            }
+            if (threads > available) {
+                task.warning("too many threads specified: {0}, limiting to: {1}", threads, available);
+            }
+            task.options.threads = Integer.min(threads, available);
+        }
+    }, new Option("  --ignore-errors            Ignores all exceptions thrown during class loading", false, "--ignore-errors") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.ignoreClassLoadingErrors = true;
+        }
+    }, new Option("  --exit-on-error            Exit on compilation errors", false, "--exit-on-error") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.exitOnError = true;
+        }
+    }, new Option("  --info                     Print information during compilation", false, "--info") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+        }
+    }, new Option("  --verbose                  Print verbose information", false, "--verbose") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+        }
+    }, new Option("  --debug                    Print debug information", false, "--debug") {
+        @Override
+        void process(Main task, String opt, String arg) throws BadArgs {
+            task.options.info = true;
+            task.options.verbose = true;
+            task.options.debug = true;
+        }
+    }, new Option("  --help                     Print this usage message", false, "--help") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.help = true;
+        }
+    }, new Option("  --version                  Version information", false, "--version") {
+        @Override
+        void process(Main task, String opt, String arg) {
+            task.options.version = true;
+        }
+    }, new Option("  -J<flag>                   Pass <flag> directly to the runtime system", false, "-J") {
+        @Override
+        void process(Main task, String opt, String arg) {
+        }
+    }};
+
+    public static class Options {
+        public List<String> files = new LinkedList<>();
+        public String module = null;
+        public String modulepath = "modules";
+        public String outputName = "unnamed";
+        public String methodList;
+        public String classpath = ".";
+
+        /**
+         * We don't see scaling beyond 16 threads.
+         */
+        private static final int COMPILER_THREADS = 16;
+
+        int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
+
+        public boolean ignoreClassLoadingErrors;
+        public boolean exitOnError;
+        boolean info;
+        boolean verbose;
+        boolean debug;
+        boolean help;
+        boolean version;
+    }
+
+    /* package */final Options options = new Options();
+
+    /**
+     * Logfile.
+     */
+    private static FileWriter logFile = null;
+
+    private static final int EXIT_OK = 0;        // No errors.
+    private static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
+    private static final int EXIT_ABNORMAL = 4;  // Terminated abnormally.
+
+    private static final String PROGNAME = "jaotc";
+
+    private static final String JVM_VERSION = System.getProperty("java.runtime.version");
+
+    public static void main(String[] args) throws Exception {
+        Main t = new Main();
+        final int exitCode = t.run(args);
+        System.exit(exitCode);
+    }
+
+    private int run(String[] args) {
+        if (log == null) {
+            log = new PrintWriter(System.out);
+        }
+
+        try {
+            handleOptions(args);
+            if (options.help) {
+                showHelp();
+                return EXIT_OK;
+            }
+            if (options.version) {
+                showVersion();
+                return EXIT_OK;
+            }
+
+            printlnInfo("Compiling " + options.outputName + "...");
+            final long start = System.currentTimeMillis();
+            run();
+            final long end = System.currentTimeMillis();
+            printlnInfo("Total time: " + (end - start) + " ms");
+
+            return EXIT_OK;
+        } catch (BadArgs e) {
+            reportError(e.key, e.args);
+            if (e.showUsage) {
+                showUsage();
+            }
+            return EXIT_CMDERR;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return EXIT_ABNORMAL;
+        } finally {
+            log.flush();
+        }
+    }
+
+    private static String humanReadableByteCount(long bytes) {
+        int unit = 1024;
+
+        if (bytes < unit) {
+            return bytes + " B";
+        }
+
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        char pre = "KMGTPE".charAt(exp - 1);
+        return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre);
+    }
+
+    void printMemoryUsage() {
+        if (options.verbose) {
+            MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+            float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
+            log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]",
+                            humanReadableByteCount(memusage.getUsed()),
+                            humanReadableByteCount(memusage.getCommitted()),
+                            freeratio * 100);
+        }
+    }
+
+    @SuppressWarnings("try")
+    private void run() throws Exception {
+        openLog();
+
+        try {
+            CompilationSpec compilationRestrictions = collectSpecifiedMethods();
+
+            Set<Class<?>> classesToCompile;
+
+            try (Timer t = new Timer(this, "")) {
+                ClassCollector collector = new ClassCollector(this.options, this);
+                classesToCompile = collector.collectClassesToCompile();
+                printInfo(classesToCompile.size() + " classes found");
+            }
+
+            GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler();
+            HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
+            HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
+            MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
+            GraalFilters filters = new GraalFilters(metaAccess);
+
+            List<AOTCompiledClass> classes;
+
+            try (Timer t = new Timer(this, "")) {
+                classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess);
+            }
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                compilationRestrictions = null;
+                classesToCompile = null;
+                System.gc();
+            }
+
+            AOTBackend aotBackend = new AOTBackend(this, backend, filters);
+            AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
+            classes = compiler.compileClasses(classes);
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                aotBackend = null;
+                compiler = null;
+                System.gc();
+            }
+
+            BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION);
+            DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
+            dataBuilder.prepareData();
+
+            // Print information about section sizes
+            printContainerInfo(binaryContainer.getHeaderContainer().getContainer());
+            printContainerInfo(binaryContainer.getConfigContainer());
+            printContainerInfo(binaryContainer.getKlassesOffsetsContainer());
+            printContainerInfo(binaryContainer.getMethodsOffsetsContainer());
+            printContainerInfo(binaryContainer.getKlassesDependenciesContainer());
+            printContainerInfo(binaryContainer.getStubsOffsetsContainer());
+            printContainerInfo(binaryContainer.getMethodMetadataContainer());
+            printContainerInfo(binaryContainer.getCodeContainer());
+            printContainerInfo(binaryContainer.getCodeSegmentsContainer());
+            printContainerInfo(binaryContainer.getConstantDataContainer());
+            printContainerInfo(binaryContainer.getMetaspaceGotContainer());
+            printContainerInfo(binaryContainer.getMetadataGotContainer());
+            printContainerInfo(binaryContainer.getMethodStateContainer());
+            printContainerInfo(binaryContainer.getOopGotContainer());
+            printContainerInfo(binaryContainer.getMetaspaceNamesContainer());
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                backend = null;
+                for (AOTCompiledClass aotCompClass : classes) {
+                    aotCompClass.clear();
+                }
+                classes.clear();
+                classes = null;
+                dataBuilder = null;
+                binaryContainer.freeMemory();
+                System.gc();
+            }
+
+            String objectFileName = options.outputName + ".o";
+            String libraryFileName = options.outputName + ".so";
+
+            try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) {
+                binaryContainer.createBinary(objectFileName, JVM_VERSION);
+            }
+
+            // Free memory!
+            try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
+                printMemoryUsage();
+                binaryContainer = null;
+                System.gc();
+            }
+
+            try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) {
+                Process p = Runtime.getRuntime().exec("ld -shared -z noexecstack -o " + libraryFileName + " " + objectFileName);
+                final int exitCode = p.waitFor();
+                if (exitCode != 0) {
+                    InputStream stderr = p.getErrorStream();
+                    BufferedReader br = new BufferedReader(new InputStreamReader(stderr));
+                    Stream<String> lines = br.lines();
+                    StringBuilder sb = new StringBuilder();
+                    lines.iterator().forEachRemaining(e -> sb.append(e));
+                    throw new InternalError(sb.toString());
+                }
+                File objFile = new File(objectFileName);
+                if (objFile.exists()) {
+                    if (!objFile.delete()) {
+                        throw new InternalError("Failed to delete " + objectFileName + " file");
+                    }
+                }
+                // Make non-executable for all.
+                File libFile = new File(libraryFileName);
+                if (libFile.exists()) {
+                    if (!libFile.setExecutable(false, false)) {
+                        throw new InternalError("Failed to change attribute for " + libraryFileName + " file");
+                    }
+                }
+            }
+
+            printVerbose("Final memory  ");
+            printMemoryUsage();
+            printlnVerbose("");
+
+        } finally {
+            closeLog();
+        }
+    }
+
+    private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
+        for (ResolvedJavaMethod m : methods) {
+            addMethod(aotClass, m, compilationRestrictions, filters);
+        }
+    }
+
+    private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) {
+        // Don't compile native or abstract methods.
+        if (!method.hasBytecodes()) {
+            return;
+        }
+        if (!compilationRestrictions.shouldCompileMethod(method)) {
+            return;
+        }
+        if (!filters.shouldCompileMethod(method)) {
+            return;
+        }
+
+        aotClass.addMethod(method);
+        printlnVerbose("  added " + method.getName() + method.getSignature().toMethodDescriptor());
+    }
+
+    private void printContainerInfo(ByteContainer container) {
+        printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes");
+    }
+
+    PrintWriter log;
+
+    private void handleOptions(String[] args) throws BadArgs {
+        if (args.length == 0) {
+            options.help = true;
+            return;
+        }
+
+        // Make checkstyle happy.
+        int i = 0;
+        for (; i < args.length; i++) {
+            String arg = args[i];
+
+            if (arg.charAt(0) == '-') {
+                Option option = getOption(arg);
+                String param = null;
+
+                if (option.hasArg) {
+                    if (arg.startsWith("--") && arg.indexOf('=') > 0) {
+                        param = arg.substring(arg.indexOf('=') + 1, arg.length());
+                    } else if (i + 1 < args.length) {
+                        param = args[++i];
+                    }
+
+                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
+                        throw new BadArgs("missing argument for option: {0}", arg).showUsage(true);
+                    }
+                }
+
+                option.process(this, arg, param);
+
+                if (option.ignoreRest()) {
+                    break;
+                }
+            } else {
+                options.files.add(arg);
+            }
+        }
+    }
+
+    private static Option getOption(String name) throws BadArgs {
+        for (Option o : recognizedOptions) {
+            if (o.matches(name)) {
+                return o;
+            }
+        }
+        throw new BadArgs("unknown option: {0}", name).showUsage(true);
+    }
+
+    public void printInfo(String message) {
+        if (options.info) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnInfo(String message) {
+        if (options.info) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printVerbose(String message) {
+        if (options.verbose) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnVerbose(String message) {
+        if (options.verbose) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printDebug(String message) {
+        if (options.debug) {
+            log.print(message);
+            log.flush();
+        }
+    }
+
+    public void printlnDebug(String message) {
+        if (options.debug) {
+            log.println(message);
+            log.flush();
+        }
+    }
+
+    public void printError(String message) {
+        log.println("Error: " + message);
+        log.flush();
+    }
+
+    private void reportError(String key, Object... args) {
+        printError(MessageFormat.format(key, args));
+    }
+
+    private void warning(String key, Object... args) {
+        log.println("Warning: " + MessageFormat.format(key, args));
+        log.flush();
+    }
+
+    private void showUsage() {
+        log.println("Usage: " + PROGNAME + " <options> list...");
+        log.println("use --help for a list of possible options");
+    }
+
+    private void showHelp() {
+        log.println("Usage: " + PROGNAME + " <options> <--module name> | <list...>");
+        log.println();
+        log.println("  list       A list of class files, jar files or directories which");
+        log.println("             contains class files.");
+        log.println();
+        log.println("where possible options include:");
+        for (Option o : recognizedOptions) {
+            String name = o.aliases[0].substring(1); // there must always be at least one name
+            name = name.charAt(0) == '-' ? name.substring(1) : name;
+            if (o.isHidden() || name.equals("h")) {
+                continue;
+            }
+            log.println(o.help);
+        }
+    }
+
+    private void showVersion() {
+        log.println(PROGNAME + " " + JVM_VERSION);
+    }
+
+    /**
+     * Collect all method we should compile.
+     *
+     * @return array list of AOT classes which have compiled methods.
+     */
+    private List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) {
+        int total = 0;
+        int count = 0;
+        List<AOTCompiledClass> classes = new ArrayList<>();
+
+        for (Class<?> c : classesToCompile) {
+            ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c);
+            if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) {
+                AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType);
+                printlnVerbose(" Scanning " + c.getName());
+
+                // Constructors
+                try {
+                    ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors();
+                    addMethods(aotClass, ctors, compilationRestrictions, filters);
+                    total += ctors.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Methods
+                try {
+                    ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods();
+                    addMethods(aotClass, methods, compilationRestrictions, filters);
+                    total += methods.length;
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Class initializer
+                try {
+                    ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer();
+                    if (clinit != null) {
+                        addMethod(aotClass, clinit, compilationRestrictions, filters);
+                        total++;
+                    }
+                } catch (Throwable e) {
+                    // If we are running in JCK mode we ignore all exceptions.
+                    if (options.ignoreClassLoadingErrors) {
+                        printError(c.getName() + ": " + e);
+                    } else {
+                        throw new InternalError(e);
+                    }
+                }
+
+                // Found any methods to compile? Add the class.
+                if (aotClass.hasMethods()) {
+                    classes.add(aotClass);
+                    count += aotClass.getMethodCount();
+                }
+            }
+        }
+        printInfo(total + " methods total, " + count + " methods to compile");
+        return classes;
+    }
+
+    /**
+     * If a file with compilation limitations is specified using the java property
+     * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions.
+     */
+    private CompilationSpec collectSpecifiedMethods() {
+        CompilationSpec compilationRestrictions = new CompilationSpec();
+        String methodListFileName = options.methodList;
+
+        if (methodListFileName != null && !methodListFileName.equals("")) {
+            try {
+                FileReader methListFile = new FileReader(methodListFileName);
+                BufferedReader readBuf = new BufferedReader(methListFile);
+                String line = null;
+                while ((line = readBuf.readLine()) != null) {
+                    String trimmedLine = line.trim();
+                    if (!trimmedLine.startsWith("#")) {
+                        String[] components = trimmedLine.split(" ");
+                        if (components.length == 2) {
+                            String directive = components[0];
+                            String pattern = components[1];
+                            switch (directive) {
+                                case "compileOnly":
+                                    compilationRestrictions.addCompileOnlyPattern(pattern);
+                                    break;
+                                case "exclude":
+                                    compilationRestrictions.addExcludePattern(pattern);
+                                    break;
+                                default:
+                                    System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName);
+                            }
+                        } else {
+                            if (!trimmedLine.equals("")) {
+                                System.out.println("Ignoring malformed line:\n\t " + line + "\n");
+                            }
+                        }
+                    }
+                }
+                readBuf.close();
+            } catch (FileNotFoundException e) {
+                throw new InternalError("Unable to open method list file: " + methodListFileName, e);
+            } catch (IOException e) {
+                throw new InternalError("Unable to read method list file: " + methodListFileName, e);
+            }
+        }
+
+        return compilationRestrictions;
+    }
+
+    private static void openLog() {
+        int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0);
+        if (v == 0) {
+            logFile = null;
+            return;
+        }
+        // Create log file in current directory
+        String fileName = "aot_compilation" + new Date().getTime() + ".log";
+        Path logFilePath = Paths.get("./", fileName);
+        String logFileName = logFilePath.toString();
+        try {
+            // Create file to which we do not append
+            logFile = new FileWriter(logFileName, false);
+        } catch (IOException e) {
+            System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created");
+            logFile = null;
+        }
+    }
+
+    public static void writeLog(String str) {
+        if (logFile != null) {
+            try {
+                logFile.write(str + "\n");
+                logFile.flush();
+            } catch (IOException e) {
+                // Print to console
+                System.out.println(str + "\n");
+            }
+        }
+    }
+
+    public static void closeLog() {
+        if (logFile != null) {
+            try {
+                logFile.close();
+            } catch (IOException e) {
+                // Do nothing
+            }
+        }
+    }
+}