1 /* 2 * Copyright (c) 2013, 2016, 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 sun.hotspot.tools.ctw; 25 26 import jdk.internal.misc.Unsafe; 27 28 import java.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.Objects; 32 import java.util.concurrent.Executor; 33 import java.util.concurrent.atomic.AtomicLong; 34 import java.util.regex.Matcher; 35 import java.util.regex.Pattern; 36 37 /** 38 * Abstract handler for path. 39 * Concrete subclasses should implement method {@link #process()}. 40 */ 41 public abstract class PathHandler { 42 private static final Unsafe UNSAFE = jdk.test.lib.Utils.getUnsafe(); 43 private static final AtomicLong CLASS_COUNT = new AtomicLong(0L); 44 private static volatile boolean CLASSES_LIMIT_REACHED = false; 45 private static final Pattern JAR_IN_DIR_PATTERN 46 = Pattern.compile("^(.*[/\\\\])?\\*$"); 47 protected final Path root; 48 protected final Executor executor; 49 private ClassLoader loader; 50 51 /** 52 * @param root root path to process 53 * @param executor executor used for process task invocation 54 * @throws NullPointerException if {@code root} or {@code executor} is 55 * {@code null} 56 */ 57 protected PathHandler(Path root, Executor executor) { 58 Objects.requireNonNull(root); 59 Objects.requireNonNull(executor); 60 this.root = root.normalize(); 61 this.executor = executor; 62 this.loader = ClassLoader.getSystemClassLoader(); 63 } 64 65 /** 66 * Factory method. Construct concrete handler in depends from {@code path}. 67 * 68 * @param path the path to process 69 * @param executor executor used for compile task invocation 70 * @throws NullPointerException if {@code path} or {@code executor} is 71 * {@code null} 72 */ 73 public static PathHandler create(String path, Executor executor) { 74 Objects.requireNonNull(path); 75 Objects.requireNonNull(executor); 76 Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path); 77 if (matcher.matches()) { 78 path = matcher.group(1); 79 path = path.isEmpty() ? "." : path; 80 return new ClassPathJarInDirEntry(Paths.get(path), executor); 81 } else { 82 path = path.isEmpty() ? "." : path; 83 Path p = Paths.get(path); 84 if (isJarFile(p)) { 85 return new ClassPathJarEntry(p, executor); 86 } else if (isListFile(p)) { 87 return new ClassesListInFile(p, executor); 88 } else if (isJimageFile(p)) { 89 return new ClassPathJimageEntry(p, executor); 90 } else { 91 return new ClassPathDirEntry(p, executor); 92 } 93 } 94 } 95 96 private static boolean isJarFile(Path path) { 97 if (Files.isRegularFile(path)) { 98 String name = path.toString(); 99 return Utils.endsWithIgnoreCase(name, ".zip") 100 || Utils.endsWithIgnoreCase(name, ".jar"); 101 } 102 return false; 103 } 104 105 private static boolean isJimageFile(Path path) { 106 String filename = path.getFileName().toString(); 107 return Files.isRegularFile(path) 108 && ("modules".equals(filename) 109 || Utils.endsWithIgnoreCase(filename, ".jimage")); 110 } 111 112 private static boolean isListFile(Path path) { 113 if (Files.isRegularFile(path)) { 114 String name = path.toString(); 115 return Utils.endsWithIgnoreCase(name, ".lst"); 116 } 117 return false; 118 } 119 120 /** 121 * Processes all classes in specified path. 122 */ 123 public abstract void process(); 124 125 /** 126 * Sets class loader, that will be used to define class at 127 * {@link #processClass(String)}. 128 * 129 * @param loader class loader 130 * @throws NullPointerException if {@code loader} is {@code null} 131 */ 132 protected final void setLoader(ClassLoader loader) { 133 Objects.requireNonNull(loader); 134 this.loader = loader; 135 } 136 137 /** 138 * Processes specified class. 139 * @param name fully qualified name of class to process 140 */ 141 protected final void processClass(String name) { 142 Objects.requireNonNull(name); 143 if (CLASSES_LIMIT_REACHED) { 144 return; 145 } 146 long id = CLASS_COUNT.incrementAndGet(); 147 if (id > Utils.COMPILE_THE_WORLD_STOP_AT) { 148 CLASSES_LIMIT_REACHED = true; 149 return; 150 } 151 if (id >= Utils.COMPILE_THE_WORLD_START_AT) { 152 try { 153 Class<?> aClass = loader.loadClass(name); 154 if (name != "sun.reflect.misc.Trampoline" 155 && name != "sun.tools.jconsole.OutputViewer") { // workaround for JDK-8159155 156 UNSAFE.ensureClassInitialized(aClass); 157 } 158 CompileTheWorld.OUT.printf("[%d]\t%s%n", id, name); 159 Compiler.compileClass(aClass, id, executor); 160 } catch (ClassNotFoundException e) { 161 CompileTheWorld.OUT.printf("Class %s loading failed : %s%n", 162 name, e.getMessage()); 163 } 164 } 165 } 166 167 /** 168 * @return count of processed classes 169 */ 170 public static long getClassCount() { 171 long id = CLASS_COUNT.get(); 172 if (id < Utils.COMPILE_THE_WORLD_START_AT) { 173 return 0; 174 } 175 if (id > Utils.COMPILE_THE_WORLD_STOP_AT) { 176 return Utils.COMPILE_THE_WORLD_STOP_AT - Utils.COMPILE_THE_WORLD_START_AT + 1; 177 } 178 return id - Utils.COMPILE_THE_WORLD_START_AT + 1; 179 } 180 181 /** 182 * @return {@code true} if classes limit is reached and processing should be stopped 183 */ 184 public static boolean isFinished() { 185 return CLASSES_LIMIT_REACHED; 186 } 187 188 } 189