| /* |
| * Copyright (c) 2016, 2017, 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.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.ListIterator; |
| 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.*; |
| import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; |
| import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; |
| import jdk.tools.jaotc.collect.jar.JarSourceProvider; |
| import jdk.tools.jaotc.collect.module.ModuleSourceProvider; |
| import jdk.tools.jaotc.utils.Timer; |
| |
| import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; |
| import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; |
| import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; |
| import org.graalvm.compiler.hotspot.HotSpotHostBackend; |
| import org.graalvm.compiler.java.GraphBuilderPhase; |
| import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; |
| import org.graalvm.compiler.phases.BasePhase; |
| import org.graalvm.compiler.phases.PhaseSuite; |
| import org.graalvm.compiler.phases.tiers.HighTierContext; |
| 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(" --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(" --class-name <class names> List of classes to compile", true, "--class-name", "--classname") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); |
| } |
| }, new Option(" --jar <jarfiles> List of jar files to compile", true, "--jar") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); |
| } |
| }, new Option(" --module <modules> List of modules to compile", true, "--module") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); |
| } |
| }, new Option(" --directory <dirs> List of directories where to search for files to compile", true, "--directory") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); |
| } |
| }, new Option(" --search-path <dirs> List of directories where to search for specified files", true, "--search-path") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| String[] elements = arg.split(":"); |
| task.options.searchPath.add(elements); |
| } |
| }, 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 Generate profiling code for tiered compilation", false, "--compile-for-tiered") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| TieredAOT.setValue(true); |
| } |
| }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { |
| @Override |
| void process(Main task, String opt, String arg) { |
| task.options.compileWithAssertions = true; |
| } |
| }, new Option(" --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--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<SearchFor> files = new LinkedList<>(); |
| public String outputName = "unnamed"; |
| public String methodList; |
| public List<ClassSource> sources = new ArrayList<>(); |
| public SearchPath searchPath = new SearchPath(); |
| |
| /** |
| * We don't see scaling beyond 16 threads. |
| */ |
| private static final int COMPILER_THREADS = 16; |
| |
| public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); |
| |
| public boolean ignoreClassLoadingErrors; |
| public boolean exitOnError; |
| public boolean info; |
| public boolean verbose; |
| public boolean debug; |
| public boolean help; |
| public boolean version; |
| public boolean compileWithAssertions; |
| } |
| |
| /* 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(); |
| if (!run()) { |
| return EXIT_ABNORMAL; |
| } |
| 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 boolean run() throws Exception { |
| openLog(); |
| |
| try { |
| CompilationSpec compilationRestrictions = collectSpecifiedMethods(); |
| |
| Set<Class<?>> classesToCompile = new HashSet<>(); |
| |
| try (Timer t = new Timer(this, "")) { |
| FileSupport fileSupport = new FileSupport(); |
| ClassSearch lookup = new ClassSearch(); |
| lookup.addProvider(new ModuleSourceProvider()); |
| lookup.addProvider(new ClassNameSourceProvider(fileSupport)); |
| lookup.addProvider(new JarSourceProvider()); |
| lookup.addProvider(new DirectorySourceProvider(fileSupport)); |
| |
| List<LoadedClass> found = null; |
| try { |
| found = lookup.search(options.files, options.searchPath); |
| } catch (InternalError e) { |
| reportError(e); |
| return false; |
| } |
| |
| for (LoadedClass loadedClass : found) { |
| classesToCompile.add(loadedClass.getLoadedClass()); |
| } |
| |
| 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); |
| |
| GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); |
| PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite(); |
| ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); |
| GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); |
| |
| // Free memory! |
| try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { |
| printMemoryUsage(); |
| aotBackend = null; |
| compiler = null; |
| System.gc(); |
| } |
| |
| BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, 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(); |
| } |
| return true; |
| } |
| |
| 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(new SearchFor(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(Throwable e) { |
| log.println("Error: " + e.getMessage()); |
| e.printStackTrace(log); |
| 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> list"); |
| log.println(); |
| log.println(" list A : separated list of class names, modules, jar files"); |
| log.println(" or directories which contain class files."); |
| log.println(); |
| log.println("where 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 |
| } |
| } |
| } |
| } |