Tue, 24 Dec 2013 09:17:37 -0800
8029230: Update copyright year to match last edit in jdk8 langtools repository for 2013
Reviewed-by: ksrini
Contributed-by: steve.sides@oracle.com
rfield@1422 | 1 | /* |
ksrini@2227 | 2 | * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
rfield@1422 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
rfield@1422 | 4 | * |
rfield@1422 | 5 | * This code is free software; you can redistribute it and/or modify it |
rfield@1422 | 6 | * under the terms of the GNU General Public License version 2 only, as |
rfield@1422 | 7 | * published by the Free Software Foundation. Oracle designates this |
rfield@1422 | 8 | * particular file as subject to the "Classpath" exception as provided |
rfield@1422 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
rfield@1422 | 10 | * |
rfield@1422 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
rfield@1422 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
rfield@1422 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
rfield@1422 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
rfield@1422 | 15 | * accompanied this code). |
rfield@1422 | 16 | * |
rfield@1422 | 17 | * You should have received a copy of the GNU General Public License version |
rfield@1422 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
rfield@1422 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
rfield@1422 | 20 | * |
rfield@1422 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
rfield@1422 | 22 | * or visit www.oracle.com if you need additional information or have any |
rfield@1422 | 23 | * questions. |
rfield@1422 | 24 | */ |
rfield@1422 | 25 | |
rfield@1422 | 26 | package org.openjdk.tests.separate; |
rfield@1422 | 27 | |
rfield@1422 | 28 | import java.util.*; |
rfield@1422 | 29 | import java.util.concurrent.atomic.AtomicInteger; |
rfield@1422 | 30 | import java.util.concurrent.ConcurrentHashMap; |
rfield@1422 | 31 | import java.io.*; |
rfield@1422 | 32 | import java.net.URI; |
rfield@1422 | 33 | import javax.tools.*; |
rfield@1422 | 34 | |
rfield@1422 | 35 | import com.sun.source.util.JavacTask; |
rfield@1422 | 36 | |
rfield@1422 | 37 | import static org.openjdk.tests.separate.SourceModel.Type; |
rfield@1422 | 38 | import static org.openjdk.tests.separate.SourceModel.Class; |
rfield@1422 | 39 | import static org.openjdk.tests.separate.SourceModel.Extends; |
rfield@1422 | 40 | import static org.openjdk.tests.separate.SourceModel.SourceProcessor; |
rfield@1422 | 41 | |
rfield@1422 | 42 | public class Compiler { |
rfield@1422 | 43 | |
rfield@1422 | 44 | public enum Flags { |
rfield@1422 | 45 | VERBOSE, // Prints out files as they are compiled |
rfield@1422 | 46 | USECACHE // Keeps results around for reuse. Only use this is |
rfield@1422 | 47 | // you're sure that each compilation name maps to the |
rfield@1422 | 48 | // same source code |
briangoetz@2174 | 49 | } |
rfield@1422 | 50 | |
rfield@1422 | 51 | private static final AtomicInteger counter = new AtomicInteger(); |
rfield@1422 | 52 | private static final String targetDir = "gen-separate"; |
rfield@1422 | 53 | private static final File root = new File(targetDir); |
rfield@1422 | 54 | private static ConcurrentHashMap<String,File> cache = |
rfield@1422 | 55 | new ConcurrentHashMap<>(); |
rfield@1422 | 56 | |
rfield@1422 | 57 | Set<Flags> flags; |
rfield@1422 | 58 | |
rfield@1422 | 59 | private JavaCompiler systemJavaCompiler; |
rfield@1422 | 60 | private StandardJavaFileManager fm; |
rfield@1422 | 61 | private List<File> tempDirs; |
rfield@1422 | 62 | private List<ClassFilePreprocessor> postprocessors; |
rfield@1422 | 63 | |
rfield@1422 | 64 | private static class SourceFile extends SimpleJavaFileObject { |
rfield@1422 | 65 | private final String content; |
rfield@1422 | 66 | |
rfield@1422 | 67 | public SourceFile(String name, String content) { |
rfield@1422 | 68 | super(URI.create("myfo:/" + name + ".java"), Kind.SOURCE); |
rfield@1422 | 69 | this.content = content; |
rfield@1422 | 70 | } |
rfield@1422 | 71 | |
rfield@1422 | 72 | public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
rfield@1422 | 73 | return toString(); |
rfield@1422 | 74 | } |
rfield@1422 | 75 | |
rfield@1422 | 76 | public String toString() { return this.content; } |
rfield@1422 | 77 | } |
rfield@1422 | 78 | |
rfield@1422 | 79 | public Compiler(Flags ... flags) { |
rfield@1422 | 80 | setFlags(flags); |
rfield@1422 | 81 | this.tempDirs = new ArrayList<>(); |
rfield@1422 | 82 | this.postprocessors = new ArrayList<>(); |
rfield@1422 | 83 | this.systemJavaCompiler = ToolProvider.getSystemJavaCompiler(); |
rfield@1422 | 84 | this.fm = systemJavaCompiler.getStandardFileManager(null, null, null); |
rfield@1422 | 85 | } |
rfield@1422 | 86 | |
rfield@1422 | 87 | public void setFlags(Flags ... flags) { |
briangoetz@2174 | 88 | this.flags = new HashSet<>(Arrays.asList(flags)); |
rfield@1422 | 89 | } |
rfield@1422 | 90 | |
rfield@1422 | 91 | public void addPostprocessor(ClassFilePreprocessor cfp) { |
rfield@1422 | 92 | this.postprocessors.add(cfp); |
rfield@1422 | 93 | } |
rfield@1422 | 94 | |
rfield@1422 | 95 | /** |
rfield@1422 | 96 | * Compile hierarchies starting with each of the 'types' and return |
rfield@1422 | 97 | * a ClassLoader that can be used to load the compiled classes. |
rfield@1422 | 98 | */ |
rfield@1422 | 99 | public ClassLoader compile(Type ... types) { |
rfield@1422 | 100 | ClassFilePreprocessor[] cfps = this.postprocessors.toArray( |
rfield@1422 | 101 | new ClassFilePreprocessor[0]); |
rfield@1422 | 102 | |
rfield@1422 | 103 | DirectedClassLoader dcl = new DirectedClassLoader(cfps); |
rfield@1422 | 104 | |
rfield@1422 | 105 | for (Type t : types) { |
rfield@1422 | 106 | for (Map.Entry<String,File> each : compileHierarchy(t).entrySet()) { |
rfield@1422 | 107 | dcl.setLocationFor(each.getKey(), each.getValue()); |
rfield@1422 | 108 | } |
rfield@1422 | 109 | } |
rfield@1422 | 110 | return dcl; |
rfield@1422 | 111 | } |
rfield@1422 | 112 | |
rfield@1422 | 113 | /** |
rfield@1422 | 114 | * Compiles and loads a hierarchy, starting at 'type' |
rfield@1422 | 115 | */ |
rfield@1422 | 116 | public java.lang.Class<?> compileAndLoad(Type type) |
rfield@1422 | 117 | throws ClassNotFoundException { |
rfield@1422 | 118 | |
rfield@1422 | 119 | ClassLoader loader = compile(type); |
rfield@1422 | 120 | return java.lang.Class.forName(type.getName(), false, loader); |
rfield@1422 | 121 | } |
rfield@1422 | 122 | |
rfield@1422 | 123 | /** |
rfield@1422 | 124 | * Compiles a hierarchy, starting at 'type' and return a mapping of the |
rfield@1422 | 125 | * name to the location where the classfile for that type resides. |
rfield@1422 | 126 | */ |
rfield@1422 | 127 | private Map<String,File> compileHierarchy(Type type) { |
rfield@1422 | 128 | HashMap<String,File> outputDirs = new HashMap<>(); |
rfield@1422 | 129 | |
rfield@1422 | 130 | File outDir = compileOne(type); |
rfield@1422 | 131 | outputDirs.put(type.getName(), outDir); |
rfield@1422 | 132 | |
rfield@1422 | 133 | Class superClass = type.getSuperclass(); |
briangoetz@2174 | 134 | if (superClass != null) |
briangoetz@2174 | 135 | outputDirs.putAll(compileHierarchy(superClass)); |
briangoetz@2174 | 136 | for (Extends ext : type.getSupertypes()) |
briangoetz@2174 | 137 | outputDirs.putAll(compileHierarchy(ext.getType())); |
rfield@1422 | 138 | |
rfield@1422 | 139 | return outputDirs; |
rfield@1422 | 140 | } |
rfield@1422 | 141 | |
rfield@1422 | 142 | private File compileOne(Type type) { |
rfield@1422 | 143 | if (this.flags.contains(Flags.USECACHE)) { |
rfield@1422 | 144 | File dir = cache.get(type.getName()); |
rfield@1422 | 145 | if (dir != null) { |
rfield@1422 | 146 | return dir; |
rfield@1422 | 147 | } |
rfield@1422 | 148 | } |
rfield@1422 | 149 | List<JavaFileObject> files = new ArrayList<>(); |
rfield@1422 | 150 | SourceProcessor accum = |
rfield@1422 | 151 | (name, src) -> { files.add(new SourceFile(name, src)); }; |
rfield@1422 | 152 | |
briangoetz@2174 | 153 | Collection<Type> deps = type.typeDependencies(type.isFullCompilation()); |
briangoetz@2174 | 154 | for (Type dep : deps) { |
briangoetz@2174 | 155 | if (type.isFullCompilation()) |
briangoetz@2174 | 156 | dep.generate(accum); |
briangoetz@2174 | 157 | else |
briangoetz@2174 | 158 | dep.generateAsDependency(accum, type.methodDependencies()); |
rfield@1422 | 159 | } |
rfield@1422 | 160 | |
rfield@1422 | 161 | type.generate(accum); |
rfield@1422 | 162 | |
rfield@1422 | 163 | JavacTask ct = (JavacTask)this.systemJavaCompiler.getTask( |
rfield@1422 | 164 | null, this.fm, null, null, null, files); |
rfield@1422 | 165 | File destDir = null; |
rfield@1422 | 166 | do { |
rfield@1422 | 167 | int value = counter.incrementAndGet(); |
rfield@1422 | 168 | destDir = new File(root, Integer.toString(value)); |
rfield@1422 | 169 | } while (destDir.exists()); |
rfield@1422 | 170 | |
rfield@1422 | 171 | if (this.flags.contains(Flags.VERBOSE)) { |
rfield@1422 | 172 | System.out.println("Compilation unit for " + type.getName() + |
rfield@1422 | 173 | " : compiled into " + destDir); |
rfield@1422 | 174 | for (JavaFileObject jfo : files) { |
rfield@1422 | 175 | System.out.println(jfo.toString()); |
rfield@1422 | 176 | } |
rfield@1422 | 177 | } |
rfield@1422 | 178 | |
rfield@1422 | 179 | try { |
rfield@1422 | 180 | destDir.mkdirs(); |
rfield@1422 | 181 | this.fm.setLocation( |
rfield@1422 | 182 | StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir)); |
rfield@1422 | 183 | } catch (IOException e) { |
rfield@1422 | 184 | throw new RuntimeException( |
briangoetz@2174 | 185 | "IOException encountered during compilation", e); |
rfield@1422 | 186 | } |
rfield@1422 | 187 | Boolean result = ct.call(); |
rfield@1422 | 188 | if (result == Boolean.FALSE) { |
rfield@1422 | 189 | throw new RuntimeException( |
rfield@1422 | 190 | "Compilation failure in " + type.getName() + " unit"); |
rfield@1422 | 191 | } |
rfield@1422 | 192 | if (this.flags.contains(Flags.USECACHE)) { |
rfield@1422 | 193 | File existing = cache.putIfAbsent(type.getName(), destDir); |
rfield@1422 | 194 | if (existing != null) { |
rfield@1422 | 195 | deleteDir(destDir); |
rfield@1422 | 196 | return existing; |
rfield@1422 | 197 | } |
rfield@1422 | 198 | } else { |
rfield@1422 | 199 | this.tempDirs.add(destDir); |
rfield@1422 | 200 | } |
rfield@1422 | 201 | return destDir; |
rfield@1422 | 202 | } |
rfield@1422 | 203 | |
rfield@1422 | 204 | private static void deleteDir(File dir) { |
rfield@1422 | 205 | for (File f : dir.listFiles()) { |
rfield@1422 | 206 | f.delete(); |
rfield@1422 | 207 | }; |
rfield@1422 | 208 | dir.delete(); |
rfield@1422 | 209 | } |
rfield@1422 | 210 | |
rfield@1422 | 211 | public void cleanup() { |
rfield@1422 | 212 | if (!this.flags.contains(Flags.USECACHE)) { |
rfield@1422 | 213 | for (File d : tempDirs) { |
rfield@1422 | 214 | deleteDir(d); |
rfield@1422 | 215 | }; |
rfield@1422 | 216 | tempDirs = new ArrayList<>(); |
rfield@1422 | 217 | } |
rfield@1422 | 218 | } |
rfield@1422 | 219 | |
rfield@1422 | 220 | // Removes all of the elements in the cache and deletes the associated |
rfield@1422 | 221 | // output directories. This may not actually empty the cache if there |
rfield@1422 | 222 | // are concurrent users of it. |
rfield@1422 | 223 | public static void purgeCache() { |
rfield@1422 | 224 | for (Map.Entry<String,File> entry : cache.entrySet()) { |
rfield@1422 | 225 | cache.remove(entry.getKey()); |
rfield@1422 | 226 | deleteDir(entry.getValue()); |
rfield@1422 | 227 | } |
rfield@1422 | 228 | } |
rfield@1422 | 229 | } |