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