1 /* 2 * Copyright (c) 2017, 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 java.io.BufferedReader; 29 import java.io.FileNotFoundException; 30 import java.io.FileReader; 31 import java.io.IOException; 32 import java.util.ArrayList; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Set; 36 37 import jdk.tools.jaotc.collect.ClassSearch; 38 import jdk.tools.jaotc.collect.FileSupport; 39 import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; 40 import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; 41 import jdk.tools.jaotc.collect.jar.JarSourceProvider; 42 import jdk.tools.jaotc.collect.module.ModuleSourceProvider; 43 import jdk.vm.ci.meta.MetaAccessProvider; 44 import jdk.vm.ci.meta.ResolvedJavaMethod; 45 import jdk.vm.ci.meta.ResolvedJavaType; 46 47 final class Collector { 48 49 private final Main main; 50 51 Collector(Main main) { 52 this.main = main; 53 } 54 55 Set<Class<?>> collectClassesToCompile() { 56 Set<Class<?>> classesToCompile = new HashSet<>(); 57 FileSupport fileSupport = new FileSupport(); 58 ClassSearch lookup = new ClassSearch(); 59 lookup.addProvider(new ModuleSourceProvider()); 60 lookup.addProvider(new ClassNameSourceProvider(fileSupport)); 61 lookup.addProvider(new JarSourceProvider()); 62 lookup.addProvider(new DirectorySourceProvider(fileSupport)); 63 64 List<LoadedClass> foundClasses = null; 65 try { 66 foundClasses = lookup.search(main.options.files, main.options.searchPath, this::handleLoadingError); 67 } catch (InternalError e) { 68 main.printer.reportError(e); 69 return null; 70 } 71 72 for (LoadedClass loadedClass : foundClasses) { 73 classesToCompile.add(loadedClass.getLoadedClass()); 74 } 75 return classesToCompile; 76 } 77 78 private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions) { 79 for (ResolvedJavaMethod m : methods) { 80 addMethod(aotClass, m, compilationRestrictions); 81 } 82 } 83 84 private void addMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method, CompilationSpec compilationRestrictions) { 85 // Don't compile native or abstract methods. 86 if (!method.hasBytecodes()) { 87 return; 88 } 89 if (!compilationRestrictions.shouldCompileMethod(method)) { 90 return; 91 } 92 if (!main.filters.shouldCompileMethod(method)) { 93 return; 94 } 95 96 aotClass.addMethod(method); 97 main.printer.printlnVerbose(" added " + method.getName() + method.getSignature().toMethodDescriptor()); 98 } 99 100 /** 101 * Collect all method we should compile. 102 * 103 * @return array list of AOT classes which have compiled methods. 104 */ 105 List<AOTCompiledClass> collectMethodsToCompile(Set<Class<?>> classesToCompile, MetaAccessProvider metaAccess) { 106 int total = 0; 107 int count = 0; 108 List<AOTCompiledClass> classes = new ArrayList<>(); 109 CompilationSpec compilationRestrictions = collectSpecifiedMethods(); 110 111 for (Class<?> c : classesToCompile) { 112 ResolvedJavaType resolvedJavaType = metaAccess.lookupJavaType(c); 113 if (main.filters.shouldCompileAnyMethodInClass(resolvedJavaType)) { 114 AOTCompiledClass aotClass = new AOTCompiledClass(resolvedJavaType); 115 main.printer.printlnVerbose(" Scanning " + c.getName()); 116 117 // Constructors 118 try { 119 ResolvedJavaMethod[] ctors = resolvedJavaType.getDeclaredConstructors(); 120 addMethods(aotClass, ctors, compilationRestrictions); 121 total += ctors.length; 122 } catch (Throwable e) { 123 handleLoadingError(c.getName(), e); 124 } 125 126 // Methods 127 try { 128 ResolvedJavaMethod[] methods = resolvedJavaType.getDeclaredMethods(); 129 addMethods(aotClass, methods, compilationRestrictions); 130 total += methods.length; 131 } catch (Throwable e) { 132 handleLoadingError(c.getName(), e); 133 } 134 135 // Class initializer 136 try { 137 ResolvedJavaMethod clinit = resolvedJavaType.getClassInitializer(); 138 if (clinit != null) { 139 addMethod(aotClass, clinit, compilationRestrictions); 140 total++; 141 } 142 } catch (Throwable e) { 143 handleLoadingError(c.getName(), e); 144 } 145 146 // Found any methods to compile? Add the class. 147 if (aotClass.hasMethods()) { 148 classes.add(aotClass); 149 count += aotClass.getMethodCount(); 150 } 151 } 152 } 153 main.printer.printInfo(total + " methods total, " + count + " methods to compile"); 154 return classes; 155 } 156 157 /** 158 * If a file with compilation limitations is specified using flag --compile-commands, read the 159 * file's contents and collect the restrictions. 160 */ 161 private CompilationSpec collectSpecifiedMethods() { 162 CompilationSpec compilationRestrictions = new CompilationSpec(); 163 String methodListFileName = main.options.methodList; 164 165 if (methodListFileName != null && !methodListFileName.equals("")) { 166 try { 167 FileReader methListFile = new FileReader(methodListFileName); 168 BufferedReader readBuf = new BufferedReader(methListFile); 169 String line = null; 170 while ((line = readBuf.readLine()) != null) { 171 String trimmedLine = line.trim(); 172 if (!trimmedLine.startsWith("#")) { 173 String[] components = trimmedLine.split(" "); 174 if (components.length == 2) { 175 String directive = components[0]; 176 String pattern = components[1]; 177 switch (directive) { 178 case "compileOnly": 179 compilationRestrictions.addCompileOnlyPattern(pattern); 180 break; 181 case "exclude": 182 compilationRestrictions.addExcludePattern(pattern); 183 break; 184 default: 185 System.out.println("Unrecognized command " + directive + ". Ignoring\n\t" + line + "\n encountered in " + methodListFileName); 186 } 187 } else { 188 if (!trimmedLine.equals("")) { 189 System.out.println("Ignoring malformed line:\n\t " + line + "\n"); 190 } 191 } 192 } 193 } 194 readBuf.close(); 195 } catch (FileNotFoundException e) { 196 throw new InternalError("Unable to open method list file: " + methodListFileName, e); 197 } catch (IOException e) { 198 throw new InternalError("Unable to read method list file: " + methodListFileName, e); 199 } 200 } 201 202 return compilationRestrictions; 203 } 204 205 private void handleLoadingError(String name, Throwable t) { 206 if (main.options.ignoreClassLoadingErrors) { 207 main.printer.printError(name + ": " + t); 208 } else { 209 throw new InternalError(t); 210 } 211 } 212 }