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.LinkedList; 47 import java.util.List; 48 import java.util.Set; 49 import java.util.stream.Stream; 50 51 import jdk.tools.jaotc.binformat.BinaryContainer; 52 import jdk.tools.jaotc.binformat.ByteContainer; 53 import jdk.tools.jaotc.collect.ClassCollector; 54 import jdk.tools.jaotc.utils.Timer; 55 56 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; 57 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 58 import org.graalvm.compiler.hotspot.HotSpotHostBackend; 59 import org.graalvm.compiler.runtime.RuntimeProvider; 60 61 import jdk.vm.ci.meta.MetaAccessProvider; 62 import jdk.vm.ci.meta.ResolvedJavaMethod; 63 import jdk.vm.ci.meta.ResolvedJavaType; 64 import jdk.vm.ci.runtime.JVMCI; 65 66 public class Main implements LogPrinter { 67 static { 68 GeneratePIC.setValue(true); 69 ImmutableCode.setValue(true); 70 } 71 72 static class BadArgs extends Exception { 73 private static final long serialVersionUID = 1L; 74 final String key; 75 final Object[] args; 76 boolean showUsage; 77 78 BadArgs(String key, Object... args) { 79 super(MessageFormat.format(key, args)); 80 this.key = key; 81 this.args = args; 82 } 83 84 BadArgs showUsage(boolean b) { 85 showUsage = b; 86 return this; 87 } 88 } 89 90 abstract static class Option { 91 final String help; 92 final boolean hasArg; 93 final String[] aliases; 94 95 Option(String help, boolean hasArg, String... aliases) { 96 this.help = help; 97 this.hasArg = hasArg; 98 this.aliases = aliases; 99 } 100 101 boolean isHidden() { 102 return false; 103 } 104 105 boolean matches(String opt) { 106 for (String a : aliases) { 107 if (a.equals(opt)) { 108 return true; 109 } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { 110 return true; 111 } 112 } 113 return false; 114 } 115 116 boolean ignoreRest() { 117 return false; 118 } 119 120 abstract void process(Main task, String opt, String arg) throws BadArgs; 121 } 122 123 static Option[] recognizedOptions = {new Option(" --module <name> Module to compile", true, "--module") { 124 @Override 125 void process(Main task, String opt, String arg) { 126 task.options.module = arg; 127 } 128 }, new Option(" --module-path <path> Specify where to find module to compile", true, "--module-path") { 129 @Override 130 void process(Main task, String opt, String arg) { 131 task.options.modulepath = arg; 132 } 133 }, new Option(" --output <file> Output file name", true, "--output") { 134 @Override 135 void process(Main task, String opt, String arg) { 136 String name = arg; 137 task.options.outputName = name; 138 } 139 }, new Option(" --compile-commands <file> Name of file with compile commands", true, "--compile-commands") { 140 @Override 141 void process(Main task, String opt, String arg) { 142 task.options.methodList = arg; 143 } 144 }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") { 145 @Override 146 void process(Main task, String opt, String arg) { 147 TieredAOT.setValue(true); 148 } 149 }, new Option(" --classpath <path> Specify where to find user class files", true, "--classpath", "--class-path") { 150 @Override 151 void process(Main task, String opt, String arg) { 152 task.options.classpath = arg; 153 } 154 }, new Option(" --threads <number> Number of compilation threads to be used", true, "--threads") { 155 @Override 156 void process(Main task, String opt, String arg) { 157 int threads = Integer.parseInt(arg); 158 final int available = Runtime.getRuntime().availableProcessors(); 159 if (threads <= 0) { 160 task.warning("invalid number of threads specified: {0}, using: {1}", threads, available); 161 threads = available; 162 } 163 if (threads > available) { 164 task.warning("too many threads specified: {0}, limiting to: {1}", threads, available); 165 } 166 task.options.threads = Integer.min(threads, available); 167 } 168 }, new Option(" --ignore-errors Ignores all exceptions thrown during class loading", false, "--ignore-errors") { 169 @Override 170 void process(Main task, String opt, String arg) { 171 task.options.ignoreClassLoadingErrors = true; 172 } 173 }, new Option(" --exit-on-error Exit on compilation errors", false, "--exit-on-error") { 174 @Override 175 void process(Main task, String opt, String arg) { 176 task.options.exitOnError = true; 177 } 178 }, new Option(" --info Print information during compilation", false, "--info") { 179 @Override 180 void process(Main task, String opt, String arg) throws BadArgs { 181 task.options.info = true; 182 } 183 }, new Option(" --verbose Print verbose information", false, "--verbose") { 184 @Override 185 void process(Main task, String opt, String arg) throws BadArgs { 186 task.options.info = true; 187 task.options.verbose = true; 188 } 189 }, new Option(" --debug Print debug information", false, "--debug") { 190 @Override 191 void process(Main task, String opt, String arg) throws BadArgs { 192 task.options.info = true; 193 task.options.verbose = true; 194 task.options.debug = true; 195 } 196 }, new Option(" --help Print this usage message", false, "--help") { 197 @Override 198 void process(Main task, String opt, String arg) { 199 task.options.help = true; 200 } 201 }, new Option(" --version Version information", false, "--version") { 202 @Override 203 void process(Main task, String opt, String arg) { 204 task.options.version = true; 205 } 206 }, new Option(" -J<flag> Pass <flag> directly to the runtime system", false, "-J") { 207 @Override 208 void process(Main task, String opt, String arg) { 209 } 210 }}; 211 212 public static class Options { 213 public List<String> files = new LinkedList<>(); 214 public String module = null; 215 public String modulepath = "modules"; 216 public String outputName = "unnamed.so"; 217 public String methodList; 218 public String classpath = "."; 219 220 /** 221 * We don't see scaling beyond 16 threads. 222 */ 223 private static final int COMPILER_THREADS = 16; 224 225 int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); 226 227 public boolean ignoreClassLoadingErrors; 228 public boolean exitOnError; 229 boolean info; 230 boolean verbose; 231 boolean debug; 232 boolean help; 233 boolean version; 234 } 235 236 /* package */final Options options = new Options(); 237 238 /** 239 * Logfile. 240 */ 241 private static FileWriter logFile = null; 242 243 private static final int EXIT_OK = 0; // No errors. 244 private static final int EXIT_CMDERR = 2; // Bad command-line arguments and/or switches. 245 private static final int EXIT_ABNORMAL = 4; // Terminated abnormally. 246 247 private static final String PROGNAME = "jaotc"; 248 249 private static final String JVM_VERSION = System.getProperty("java.runtime.version"); 250 251 public static void main(String[] args) throws Exception { 252 Main t = new Main(); 253 final int exitCode = t.run(args); 254 System.exit(exitCode); 255 } 256 257 private int run(String[] args) { 258 if (log == null) { 259 log = new PrintWriter(System.out); 260 } 261 262 try { 263 handleOptions(args); 264 if (options.help) { 265 showHelp(); 266 return EXIT_OK; 267 } 268 if (options.version) { 269 showVersion(); 270 return EXIT_OK; 271 } 272 273 printlnInfo("Compiling " + options.outputName + "..."); 274 final long start = System.currentTimeMillis(); 275 run(); 276 final long end = System.currentTimeMillis(); 277 printlnInfo("Total time: " + (end - start) + " ms"); 278 279 return EXIT_OK; 280 } catch (BadArgs e) { 281 reportError(e.key, e.args); 282 if (e.showUsage) { 283 showUsage(); 284 } 285 return EXIT_CMDERR; 286 } catch (Exception e) { 287 e.printStackTrace(); 288 return EXIT_ABNORMAL; 289 } finally { 290 log.flush(); 291 } 292 } 293 294 private static String humanReadableByteCount(long bytes) { 295 int unit = 1024; 296 297 if (bytes < unit) { 298 return bytes + " B"; 299 } 300 301 int exp = (int) (Math.log(bytes) / Math.log(unit)); 302 char pre = "KMGTPE".charAt(exp - 1); 303 return String.format("%.1f %cB", bytes / Math.pow(unit, exp), pre); 304 } 305 306 void printMemoryUsage() { 307 if (options.verbose) { 308 MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); 309 float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); 310 log.format(" [used: %-7s, comm: %-7s, freeRatio ~= %.1f%%]", 311 humanReadableByteCount(memusage.getUsed()), 312 humanReadableByteCount(memusage.getCommitted()), 313 freeratio * 100); 314 } 315 } 316 317 /** 318 * Search for Visual Studio link.exe 319 * Search Order is: VS2013, VS2015, VS2012 320 */ 321 private String getWindowsLinkPath() { 322 String vs2013 = "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"; 323 String vs2015 = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\bin\\amd64\\link.exe"; 324 String vs2012 = "C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\amd64\\link.exe"; 325 326 if (new File(vs2015).exists()) return vs2015; 327 if (new File(vs2013).exists()) return vs2013; 328 if (new File(vs2012).exists()) return vs2012; 329 return null; 330 } 331 332 @SuppressWarnings("try") 333 private void run() throws Exception { 334 openLog(); 335 336 try { 337 CompilationSpec compilationRestrictions = collectSpecifiedMethods(); 338 339 Set<Class<?>> classesToCompile; 340 341 try (Timer t = new Timer(this, "")) { 342 ClassCollector collector = new ClassCollector(this.options, this); 343 classesToCompile = collector.collectClassesToCompile(); 344 printInfo(classesToCompile.size() + " classes found"); 345 } 346 347 GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler(); 348 HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime(); 349 HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend(); 350 MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess(); 351 GraalFilters filters = new GraalFilters(metaAccess); 352 353 List<AOTCompiledClass> classes; 354 355 try (Timer t = new Timer(this, "")) { 356 classes = collectMethodsToCompile(classesToCompile, compilationRestrictions, filters, metaAccess); 357 } 358 359 // Free memory! 360 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 361 printMemoryUsage(); 362 compilationRestrictions = null; 363 classesToCompile = null; 364 System.gc(); 365 } 366 367 AOTBackend aotBackend = new AOTBackend(this, backend, filters); 368 AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads); 369 classes = compiler.compileClasses(classes); 370 371 // Free memory! 372 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 373 printMemoryUsage(); 374 aotBackend = null; 375 compiler = null; 376 System.gc(); 377 } 378 379 BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION); 380 DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); 381 dataBuilder.prepareData(); 382 383 // Print information about section sizes 384 printContainerInfo(binaryContainer.getHeaderContainer().getContainer()); 385 printContainerInfo(binaryContainer.getConfigContainer()); 386 printContainerInfo(binaryContainer.getKlassesOffsetsContainer()); 387 printContainerInfo(binaryContainer.getMethodsOffsetsContainer()); 388 printContainerInfo(binaryContainer.getKlassesDependenciesContainer()); 389 printContainerInfo(binaryContainer.getStubsOffsetsContainer()); 390 printContainerInfo(binaryContainer.getMethodMetadataContainer()); 391 printContainerInfo(binaryContainer.getCodeContainer()); 392 printContainerInfo(binaryContainer.getCodeSegmentsContainer()); 393 printContainerInfo(binaryContainer.getConstantDataContainer()); 394 printContainerInfo(binaryContainer.getMetaspaceGotContainer()); 395 printContainerInfo(binaryContainer.getMetadataGotContainer()); 396 printContainerInfo(binaryContainer.getMethodStateContainer()); 397 printContainerInfo(binaryContainer.getOopGotContainer()); 398 printContainerInfo(binaryContainer.getMetaspaceNamesContainer()); 399 400 // Free memory! 401 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 402 printMemoryUsage(); 403 backend = null; 404 for (AOTCompiledClass aotCompClass : classes) { 405 aotCompClass.clear(); 406 } 407 classes.clear(); 408 classes = null; 409 dataBuilder = null; 410 binaryContainer.freeMemory(); 411 System.gc(); 412 } 413 414 String name = options.outputName; 415 String objectFileName = name; 416 417 // [TODO] The jtregs tests expect .so extension so don't 418 // override with platform specific file extension until the 419 // tests are fixed. 420 String libraryFileName = name; 421 422 String ldCmd; 423 String osName = System.getProperty("os.name"); 424 425 if (name.endsWith(".so")) { 426 objectFileName = name.substring(0, name.length() - ".so".length()); 427 } 428 else if (name.endsWith(".dylib")) { 429 objectFileName = name.substring(0, name.length() - ".dylib".length()); 430 } 431 else if (name.endsWith(".dll")) { 432 objectFileName = name.substring(0, name.length() - ".dll".length()); 433 } 434 435 switch (osName) { 436 case "Linux": 437 // libraryFileName = options.outputName + ".so"; 438 objectFileName = objectFileName + ".o"; 439 ldCmd = "ld -shared -z noexecstack -o " + libraryFileName + " " + objectFileName; 440 break; 441 case "SunOS": 442 // libraryFileName = options.outputName + ".so"; 443 objectFileName = objectFileName + ".o"; 444 ldCmd = "ld -shared -o " + libraryFileName + " " + objectFileName; 445 break; 446 case "Mac OS X": 447 // libraryFileName = options.outputName + ".dylib"; 448 objectFileName = objectFileName + ".o"; 449 ldCmd = "ld -dylib -o " + libraryFileName + " " + objectFileName; 450 break; 451 default: 452 if (osName.startsWith("Windows")) { 453 // libraryFileName = options.outputName + ".dll"; 454 objectFileName = objectFileName + ".obj"; 455 String linkpath = getWindowsLinkPath(); 456 if (linkpath == null) { 457 throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe"); 458 } 459 ldCmd = linkpath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName; 460 break; 461 } 462 else 463 throw new InternalError("Unsupported platform: " + osName); 464 } 465 466 try (Timer t = new Timer(this, "Creating binary: " + objectFileName)) { 467 binaryContainer.createBinary(objectFileName, JVM_VERSION); 468 } 469 470 // Free memory! 471 try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { 472 printMemoryUsage(); 473 binaryContainer = null; 474 System.gc(); 475 } 476 477 try (Timer t = new Timer(this, "Creating shared library: " + libraryFileName)) { 478 Process p = Runtime.getRuntime().exec(ldCmd); 479 final int exitCode = p.waitFor(); 480 if (exitCode != 0) { 481 InputStream stderr = p.getErrorStream(); 482 BufferedReader br = new BufferedReader(new InputStreamReader(stderr)); 483 Stream<String> lines = br.lines(); 484 StringBuilder sb = new StringBuilder(); 485 lines.iterator().forEachRemaining(e -> sb.append(e)); 486 throw new InternalError(sb.toString()); 487 } 488 File objFile = new File(objectFileName); 489 if (objFile.exists()) { 490 if (!objFile.delete()) { 491 throw new InternalError("Failed to delete " + objectFileName + " file"); 492 } 493 } 494 // Make non-executable for all. 495 File libFile = new File(libraryFileName); 496 if (libFile.exists() && !osName.startsWith("Windows")) { 497 if (!libFile.setExecutable(false, false)) { 498 throw new InternalError("Failed to change attribute for " + libraryFileName + " file"); 499 } 500 } 501 } 502 503 printVerbose("Final memory "); 504 printMemoryUsage(); 505 printlnVerbose(""); 506 507 } finally { 508 closeLog(); 509 } 510 } 511 512 private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { 513 for (ResolvedJavaMethod m : methods) { 514 addMethod(aotClass, m, compilationRestrictions, filters); 515 } 516 } 517 518 private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions, GraalFilters filters) { 519 // Don't compile native or abstract methods. 520 if (!method.hasBytecodes()) { 521 return; 522 } 523 if (!compilationRestrictions.shouldCompileMethod(method)) { 524 return; 525 } 526 if (!filters.shouldCompileMethod(method)) { 527 return; 528 } 529 530 aotClass.addMethod(method); 531 printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor()); 532 } 533 534 private void printContainerInfo(ByteContainer container) { 535 printlnVerbose(container.getContainerName() + ": " + container.getByteStreamSize() + " bytes"); 536 } 537 538 PrintWriter log; 539 540 private void handleOptions(String[] args) throws BadArgs { 541 if (args.length == 0) { 542 options.help = true; 543 return; 544 } 545 546 // Make checkstyle happy. 547 int i = 0; 548 for (; i < args.length; i++) { 549 String arg = args[i]; 550 551 if (arg.charAt(0) == '-') { 552 Option option = getOption(arg); 553 String param = null; 554 555 if (option.hasArg) { 556 if (arg.startsWith("--") && arg.indexOf('=') > 0) { 557 param = arg.substring(arg.indexOf('=') + 1, arg.length()); 558 } else if (i + 1 < args.length) { 559 param = args[++i]; 560 } 561 562 if (param == null || param.isEmpty() || param.charAt(0) == '-') { 563 throw new BadArgs("missing argument for option: {0}", arg).showUsage(true); 564 } 565 } 566 567 option.process(this, arg, param); 568 569 if (option.ignoreRest()) { 570 break; 571 } 572 } else { 573 options.files.add(arg); 574 } 575 } 576 } 577 578 private static Option getOption(String name) throws BadArgs { 579 for (Option o : recognizedOptions) { 580 if (o.matches(name)) { 581 return o; 582 } 583 } 584 throw new BadArgs("unknown option: {0}", name).showUsage(true); 585 } 586 587 public void printInfo(String message) { 588 if (options.info) { 589 log.print(message); 590 log.flush(); 591 } 592 } 593 594 public void printlnInfo(String message) { 595 if (options.info) { 596 log.println(message); 597 log.flush(); 598 } 599 } 600 601 public void printVerbose(String message) { 602 if (options.verbose) { 603 log.print(message); 604 log.flush(); 605 } 606 } 607 608 public void printlnVerbose(String message) { 609 if (options.verbose) { 610 log.println(message); 611 log.flush(); 612 } 613 } 614 615 public void printDebug(String message) { 616 if (options.debug) { 617 log.print(message); 618 log.flush(); 619 } 620 } 621 622 public void printlnDebug(String message) { 623 if (options.debug) { 624 log.println(message); 625 log.flush(); 626 } 627 } 628 629 public void printError(String message) { 630 log.println("Error: " + message); 631 log.flush(); 632 } 633 634 private void reportError(String key, Object... args) { 635 printError(MessageFormat.format(key, args)); 636 } 637 638 private void warning(String key, Object... args) { 639 log.println("Warning: " + MessageFormat.format(key, args)); 640 log.flush(); 641 } 642 643 private void showUsage() { 644 log.println("Usage: " + PROGNAME + " <options> list..."); 645 log.println("use --help for a list of possible options"); 646 } 647 648 private void showHelp() { 649 log.println("Usage: " + PROGNAME + " <options> <--module name> | <list...>"); 650 log.println(); 651 log.println(" list A list of class files, jar files or directories which"); 652 log.println(" contains class files."); 653 log.println(); 654 log.println("where possible options include:"); 655 for (Option o : recognizedOptions) { 656 String name = o.aliases[0].substring(1); // there must always be at least one name 657 name = name.charAt(0) == '-' ? name.substring(1) : name; 658 if (o.isHidden() || name.equals("h")) { 659 continue; 660 } 661 log.println(o.help); 662 } 663 } 664 665 private void showVersion() { 666 log.println(PROGNAME + " " + JVM_VERSION); 667 } 668 669 /** 670 * Collect all method we should compile. 671 * 672 * @return array list of AOT classes which have compiled methods. 673 */ 674 private List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, CompilationSpec compilationRestrictions, GraalFilters filters, MetaAccessProvider metaAccess) { 675 int total = 0; 676 int count = 0; 677 List<AOTCompiledClass> classes = new ArrayList<>(); 678 679 for (Class<?> c : classesToCompile) { 680 ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c); 681 if (filters.shouldCompileAnyMethodInClass(resolvedJavaType)) { 682 AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType); 683 printlnVerbose(" Scanning " + c.getName()); 684 685 // Constructors 686 try { 687 ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors(); 688 addMethods(aotClass, ctors, compilationRestrictions, filters); 689 total += ctors.length; 690 } catch (Throwable e) { 691 // If we are running in JCK mode we ignore all exceptions. 692 if (options.ignoreClassLoadingErrors) { 693 printError(c.getName() + ": " + e); 694 } else { 695 throw new InternalError(e); 696 } 697 } 698 699 // Methods 700 try { 701 ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods(); 702 addMethods(aotClass, methods, compilationRestrictions, filters); 703 total += methods.length; 704 } catch (Throwable e) { 705 // If we are running in JCK mode we ignore all exceptions. 706 if (options.ignoreClassLoadingErrors) { 707 printError(c.getName() + ": " + e); 708 } else { 709 throw new InternalError(e); 710 } 711 } 712 713 // Class initializer 714 try { 715 ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer(); 716 if (clinit != null) { 717 addMethod(aotClass, clinit, compilationRestrictions, filters); 718 total++; 719 } 720 } catch (Throwable e) { 721 // If we are running in JCK mode we ignore all exceptions. 722 if (options.ignoreClassLoadingErrors) { 723 printError(c.getName() + ": " + e); 724 } else { 725 throw new InternalError(e); 726 } 727 } 728 729 // Found any methods to compile? Add the class. 730 if (aotClass.hasMethods()) { 731 classes.add(aotClass); 732 count += aotClass.getMethodCount(); 733 } 734 } 735 } 736 printInfo(total + " methods total, " + count + " methods to compile"); 737 return classes; 738 } 739 740 /** 741 * If a file with compilation limitations is specified using the java property 742 * jdk.tools.jaotc.compile.method.list, read the file's contents and collect the restrictions. 743 */ 744 private CompilationSpec collectSpecifiedMethods() { 745 CompilationSpec compilationRestrictions = new CompilationSpec(); 746 String methodListFileName = options.methodList; 747 748 if (methodListFileName != null && !methodListFileName.equals("")) { 749 try { 750 FileReader methListFile = new FileReader(methodListFileName); 751 BufferedReader readBuf = new BufferedReader(methListFile); 752 String line = null; 753 while ((line = readBuf.readLine()) != null) { 754 String trimmedLine = line.trim(); 755 if (!trimmedLine.startsWith("#")) { 756 String[] components = trimmedLine.split(" "); 757 if (components.length == 2) { 758 String directive = components[0]; 759 String pattern = components[1]; 760 switch (directive) { 761 case "compileOnly": 762 compilationRestrictions.addCompileOnlyPattern(pattern); 763 break; 764 case "exclude": 765 compilationRestrictions.addExcludePattern(pattern); 766 break; 767 default: 768 System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName); 769 } 770 } else { 771 if (!trimmedLine.equals("")) { 772 System.out.println("Ignoring malformed line:\n\t " + line + "\n"); 773 } 774 } 775 } 776 } 777 readBuf.close(); 778 } catch (FileNotFoundException e) { 779 throw new InternalError("Unable to open method list file: " + methodListFileName, e); 780 } catch (IOException e) { 781 throw new InternalError("Unable to read method list file: " + methodListFileName, e); 782 } 783 } 784 785 return compilationRestrictions; 786 } 787 788 private static void openLog() { 789 int v = Integer.getInteger("jdk.tools.jaotc.logCompilation", 0); 790 if (v == 0) { 791 logFile = null; 792 return; 793 } 794 // Create log file in current directory 795 String fileName = "aot_compilation" + new Date().getTime() + ".log"; 796 Path logFilePath = Paths.get("./", fileName); 797 String logFileName = logFilePath.toString(); 798 try { 799 // Create file to which we do not append 800 logFile = new FileWriter(logFileName, false); 801 } catch (IOException e) { 802 System.out.println("Unable to open logfile :" + logFileName + "\nNo logs will be created"); 803 logFile = null; 804 } 805 } 806 807 public static void writeLog(String str) { 808 if (logFile != null) { 809 try { 810 logFile.write(str + "\n"); 811 logFile.flush(); 812 } catch (IOException e) { 813 // Print to console 814 System.out.println(str + "\n"); 815 } 816 } 817 } 818 819 public static void closeLog() { 820 if (logFile != null) { 821 try { 822 logFile.close(); 823 } catch (IOException e) { 824 // Do nothing 825 } 826 } 827 } 828 }