1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc; 25 26 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; 27 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; 28 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT; 29 30 import java.io.IOException; 31 import java.io.PrintWriter; 32 import java.text.MessageFormat; 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.ListIterator; 37 import java.util.Set; 38 import java.util.StringTokenizer; 39 import java.util.stream.Stream; 40 import java.nio.file.Files; 41 import java.nio.file.Paths; 42 43 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 44 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; 45 import org.graalvm.compiler.debug.DebugContext; 46 import org.graalvm.compiler.debug.DebugContext.Activation; 47 import org.graalvm.compiler.hotspot.CompilerConfigurationFactory; 48 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 49 import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory; 50 import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues; 51 import org.graalvm.compiler.hotspot.HotSpotGraalRuntime; 52 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 53 import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; 54 import org.graalvm.compiler.java.GraphBuilderPhase; 55 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 56 import org.graalvm.compiler.options.OptionValues; 57 import org.graalvm.compiler.phases.BasePhase; 58 import org.graalvm.compiler.phases.PhaseSuite; 59 import org.graalvm.compiler.phases.tiers.HighTierContext; 60 import org.graalvm.compiler.printer.GraalDebugHandlersFactory; 61 import org.graalvm.compiler.runtime.RuntimeProvider; 62 63 import jdk.tools.jaotc.Options.Option; 64 import jdk.tools.jaotc.binformat.BinaryContainer; 65 import jdk.vm.ci.meta.MetaAccessProvider; 66 import jdk.vm.ci.meta.ResolvedJavaMethod; 67 import jdk.vm.ci.runtime.JVMCI; 68 69 public final class Main { 70 71 final Options options = new Options(); 72 private PrintWriter log; 73 LogPrinter printer; 74 GraalFilters filters; 75 76 private static final int EXIT_OK = 0; // No errors. 77 private static final int EXIT_CMDERR = 2; // Bad command-line arguments and/or switches. 78 private static final int EXIT_ABNORMAL = 4; // Terminated abnormally. 79 80 private static final String PROGNAME = "jaotc"; 81 82 private static final String JVM_VERSION = System.getProperty("java.runtime.version"); 83 84 public static void main(String[] args) throws Exception { 85 Main t = new Main(); 86 final int exitCode = t.run(parse(args)); 87 System.exit(exitCode); 88 } 89 90 /** 91 * Expands '@file' in command line arguments by replacing '@file' with the content of 'file' 92 * parsed by StringTokenizer. '@' character can be quoted as '@@'. 93 */ 94 private static String[] parse(String[] args) throws IOException { 95 List<String> result = new ArrayList<>(); 96 for (String arg : args) { 97 if (arg.length() > 1 && arg.charAt(0) == '@') { 98 String v = arg.substring(1); 99 if (v.charAt(0) == '@') { 100 result.add(v); 101 } else { 102 try (Stream<String> file = Files.lines(Paths.get(v))) { 103 file.map(StringTokenizer::new).map(Collections::list).flatMap(l -> l.stream().map(o -> (String) o)).forEachOrdered(result::add); 104 } 105 } 106 } else { 107 result.add(arg); 108 } 109 } 110 return result.toArray(String[]::new); 111 } 112 113 private int run(String[] args) { 114 log = new PrintWriter(System.out); 115 printer = new LogPrinter(this, log); 116 117 try { 118 Options.handleOptions(this, args); 119 if (options.help) { 120 showHelp(); 121 return EXIT_OK; 122 } 123 if (options.version) { 124 showVersion(); 125 return EXIT_OK; 126 } 127 128 printer.printlnInfo("Compiling " + options.outputName + "..."); 129 final long start = System.currentTimeMillis(); 130 if (!run()) { 131 return EXIT_ABNORMAL; 132 } 133 final long end = System.currentTimeMillis(); 134 printer.printlnInfo("Total time: " + (end - start) + " ms"); 135 136 return EXIT_OK; 137 } catch (Options.BadArgs e) { 138 printer.reportError(e.key, e.args); 139 if (e.showUsage) { 140 showUsage(); 141 } 142 return EXIT_CMDERR; 143 } catch (Exception e) { 144 e.printStackTrace(); 145 return EXIT_ABNORMAL; 146 } finally { 147 log.flush(); 148 } 149 } 150 151 @SuppressWarnings("try") 152 private boolean run() throws Exception { 153 LogPrinter.openLog(); 154 155 try { 156 157 final Linker linker = new Linker(this); 158 final String objectFileName = linker.objFile(); 159 final Collector collector = new Collector(this); 160 Set<Class<?>> classesToCompile; 161 162 try (Timer t = new Timer(this, "")) { 163 classesToCompile = collector.collectClassesToCompile(); 164 printer.printInfo(classesToCompile.size() + " classes found"); 165 } 166 167 OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; 168 // Setting -Dgraal.TieredAOT overrides --compile-for-tiered 169 if (!TieredAOT.hasBeenSet(graalOptions)) { 170 graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered); 171 } 172 graalOptions = new OptionValues(graalOptions, GeneratePIC, true, ImmutableCode, true); 173 GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler("JAOTC", JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions)); 174 HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) graalCompiler.getGraalRuntime(); 175 HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend(); 176 MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); 177 filters = new GraalFilters(metaAccess); 178 179 List<AOTCompiledClass> classes; 180 181 try (Timer t = new Timer(this, "")) { 182 classes = collector.collectMethodsToCompile(classesToCompile, metaAccess); 183 } 184 185 // Free memory! 186 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 187 printer.printMemoryUsage(); 188 classesToCompile = null; 189 System.gc(); 190 } 191 192 AOTDynamicTypeStore dynoStore = new AOTDynamicTypeStore(); 193 AOTCompiledClass.setDynamicTypeStore(dynoStore); 194 195 AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, new HotSpotInvokeDynamicPlugin(dynoStore)); 196 SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection(); 197 AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads); 198 classes = compiler.compileClasses(classes); 199 200 GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); 201 PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite(); 202 ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); 203 GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); 204 205 // Free memory! 206 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 207 printer.printMemoryUsage(); 208 aotBackend = null; 209 compiler = null; 210 System.gc(); 211 } 212 213 int gc = runtime.getGarbageCollector().ordinal() + 1; 214 BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, gc, JVM_VERSION); 215 DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); 216 217 try (DebugContext debug = DebugContext.create(graalOptions, new GraalDebugHandlersFactory(snippetReflection)); Activation a = debug.activate()) { 218 dataBuilder.prepareData(debug); 219 } 220 221 // Print information about section sizes 222 printer.containersInfo(binaryContainer); 223 224 // Free memory! 225 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 226 printer.printMemoryUsage(); 227 backend = null; 228 for (AOTCompiledClass aotCompClass : classes) { 229 aotCompClass.clear(); 230 } 231 classes.clear(); 232 classes = null; 233 dataBuilder = null; 234 binaryContainer.freeMemory(); 235 System.gc(); 236 } 237 238 try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) { 239 binaryContainer.createBinary(objectFileName); 240 } 241 242 // Free memory! 243 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 244 printer.printMemoryUsage(); 245 binaryContainer = null; 246 System.gc(); 247 } 248 249 try (Timer t = new Timer(this, "Creating shared library: " + linker.libFile())) { 250 linker.link(); 251 } 252 253 printer.printVerbose("Final memory "); 254 printer.printMemoryUsage(); 255 printer.printlnVerbose(""); 256 257 } finally { 258 LogPrinter.closeLog(); 259 } 260 return true; 261 } 262 263 void handleError(ResolvedJavaMethod resolvedMethod, Throwable e, String message) { 264 String methodName = JavaMethodInfo.uniqueMethodName(resolvedMethod); 265 266 if (options.debug) { 267 printer.printError("Failed compilation: " + methodName + ": " + e); 268 } 269 270 // Ignore some exceptions when meta-compiling Graal. 271 if (GraalFilters.shouldIgnoreException(e)) { 272 return; 273 } 274 275 LogPrinter.writeLog("Failed compilation of method " + methodName + message); 276 277 if (!options.debug) { 278 printer.printError("Failed compilation: " + methodName + ": " + e); 279 } 280 281 if (options.verbose) { 282 e.printStackTrace(log); 283 } 284 285 if (options.exitOnError) { 286 System.exit(1); 287 } 288 } 289 290 void warning(String key, Object... args) { 291 log.println("Warning: " + MessageFormat.format(key, args)); 292 log.flush(); 293 } 294 295 private void showUsage() { 296 log.println("Usage: " + PROGNAME + " <options> list"); 297 log.println("use --help for a list of possible options"); 298 log.flush(); 299 } 300 301 private void showHelp() { 302 log.println("Usage: " + PROGNAME + " <options> list"); 303 log.println(); 304 log.println(" list A : separated list of class names, modules, jar files"); 305 log.println(" or directories which contain class files."); 306 log.println(); 307 log.println("where options include:"); 308 for (Option o : Options.recognizedOptions) { 309 String name = o.aliases[0].substring(1); // there must always be at least one name 310 name = name.charAt(0) == '-' ? name.substring(1) : name; 311 if (o.isHidden() || name.equals("h")) { 312 continue; 313 } 314 log.println(o.help); 315 } 316 log.flush(); 317 } 318 319 private void showVersion() { 320 log.println(PROGNAME + " " + JVM_VERSION); 321 } 322 }