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