1 /* 2 * Copyright (c) 2016, 2017, 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.BufferedReader; 31 import java.io.File; 32 import java.io.FileNotFoundException; 33 import java.io.FileReader; 34 import java.io.FileWriter; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.io.InputStreamReader; 38 import java.io.PrintWriter; 39 import java.lang.management.ManagementFactory; 40 import java.lang.management.MemoryUsage; 41 import java.nio.file.Path; 42 import java.nio.file.Paths; 43 import java.text.MessageFormat; 44 import java.util.ArrayList; 45 import java.util.Date; 46 import java.util.HashSet; 47 import java.util.LinkedList; 48 import java.util.List; 49 import java.util.ListIterator; 50 import java.util.Set; 51 import java.util.stream.Stream; 52 53 import jdk.tools.jaotc.binformat.BinaryContainer; 54 import jdk.tools.jaotc.binformat.ByteContainer; 55 import jdk.tools.jaotc.collect.*; 56 import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; 57 import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; 58 import jdk.tools.jaotc.collect.jar.JarSourceProvider; 59 import jdk.tools.jaotc.collect.module.ModuleSourceProvider; 60 import jdk.tools.jaotc.utils.Timer; 61 62 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; 63 import org.graalvm.compiler.hotspot.CompilerConfigurationFactory; 64 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 65 import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory; 66 import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues; 67 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 68 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 69 import org.graalvm.compiler.java.GraphBuilderPhase; 70 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 71 import org.graalvm.compiler.options.OptionValues; 72 import org.graalvm.compiler.phases.BasePhase; 73 import org.graalvm.compiler.phases.PhaseSuite; 74 import org.graalvm.compiler.phases.tiers.HighTierContext; 75 import org.graalvm.compiler.runtime.RuntimeProvider; 76 77 import jdk.vm.ci.meta.MetaAccessProvider; 78 import jdk.vm.ci.meta.ResolvedJavaMethod; 79 import jdk.vm.ci.meta.ResolvedJavaType; 80 import jdk.vm.ci.runtime.JVMCI; 81 82 public 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(graalOptions, 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 }