--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/Compiler.java Tue Nov 20 09:58:55 2012 -0800
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.openjdk.tests.separate;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.ConcurrentHashMap;
+import java.io.*;
+import java.net.URI;
+import javax.tools.*;
+
+import com.sun.source.util.JavacTask;
+
+import static org.openjdk.tests.separate.SourceModel.Type;
+import static org.openjdk.tests.separate.SourceModel.Class;
+import static org.openjdk.tests.separate.SourceModel.Extends;
+import static org.openjdk.tests.separate.SourceModel.SourceProcessor;
+
+public class Compiler {
+
+ public enum Flags {
+ VERBOSE, // Prints out files as they are compiled
+ USECACHE // Keeps results around for reuse. Only use this is
+ // you're sure that each compilation name maps to the
+ // same source code
+ };
+
+ private static final AtomicInteger counter = new AtomicInteger();
+ private static final String targetDir = "gen-separate";
+ private static final File root = new File(targetDir);
+ private static ConcurrentHashMap<String,File> cache =
+ new ConcurrentHashMap<>();
+
+ Set<Flags> flags;
+
+ private JavaCompiler systemJavaCompiler;
+ private StandardJavaFileManager fm;
+ private List<File> tempDirs;
+ private List<ClassFilePreprocessor> postprocessors;
+
+ private static class SourceFile extends SimpleJavaFileObject {
+ private final String content;
+
+ public SourceFile(String name, String content) {
+ super(URI.create("myfo:/" + name + ".java"), Kind.SOURCE);
+ this.content = content;
+ }
+
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return toString();
+ }
+
+ public String toString() { return this.content; }
+ }
+
+ public Compiler(Flags ... flags) {
+ setFlags(flags);
+ this.tempDirs = new ArrayList<>();
+ this.postprocessors = new ArrayList<>();
+ this.systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
+ this.fm = systemJavaCompiler.getStandardFileManager(null, null, null);
+ }
+
+ public void setFlags(Flags ... flags) {
+ this.flags = new HashSet<Flags>(Arrays.asList(flags));
+ }
+
+ public void addPostprocessor(ClassFilePreprocessor cfp) {
+ this.postprocessors.add(cfp);
+ }
+
+ /**
+ * Compile hierarchies starting with each of the 'types' and return
+ * a ClassLoader that can be used to load the compiled classes.
+ */
+ public ClassLoader compile(Type ... types) {
+ ClassFilePreprocessor[] cfps = this.postprocessors.toArray(
+ new ClassFilePreprocessor[0]);
+
+ DirectedClassLoader dcl = new DirectedClassLoader(cfps);
+
+ for (Type t : types) {
+ for (Map.Entry<String,File> each : compileHierarchy(t).entrySet()) {
+ dcl.setLocationFor(each.getKey(), each.getValue());
+ }
+ }
+ return dcl;
+ }
+
+ /**
+ * Compiles and loads a hierarchy, starting at 'type'
+ */
+ public java.lang.Class<?> compileAndLoad(Type type)
+ throws ClassNotFoundException {
+
+ ClassLoader loader = compile(type);
+ return java.lang.Class.forName(type.getName(), false, loader);
+ }
+
+ /**
+ * Compiles a hierarchy, starting at 'type' and return a mapping of the
+ * name to the location where the classfile for that type resides.
+ */
+ private Map<String,File> compileHierarchy(Type type) {
+ HashMap<String,File> outputDirs = new HashMap<>();
+
+ File outDir = compileOne(type);
+ outputDirs.put(type.getName(), outDir);
+
+ Class superClass = type.getSuperclass();
+ if (superClass != null) {
+ for( Map.Entry<String,File> each : compileHierarchy(superClass).entrySet()) {
+ outputDirs.put(each.getKey(), each.getValue());
+ }
+ }
+ for (Extends ext : type.getSupertypes()) {
+ Type iface = ext.getType();
+ for( Map.Entry<String,File> each : compileHierarchy(iface).entrySet()) {
+ outputDirs.put(each.getKey(), each.getValue());
+ }
+ }
+
+ return outputDirs;
+ }
+
+ private File compileOne(Type type) {
+ if (this.flags.contains(Flags.USECACHE)) {
+ File dir = cache.get(type.getName());
+ if (dir != null) {
+ return dir;
+ }
+ }
+ List<JavaFileObject> files = new ArrayList<>();
+ SourceProcessor accum =
+ (name, src) -> { files.add(new SourceFile(name, src)); };
+
+ for (Type dep : type.typeDependencies()) {
+ dep.generateAsDependency(accum, type.methodDependencies());
+ }
+
+ type.generate(accum);
+
+ JavacTask ct = (JavacTask)this.systemJavaCompiler.getTask(
+ null, this.fm, null, null, null, files);
+ File destDir = null;
+ do {
+ int value = counter.incrementAndGet();
+ destDir = new File(root, Integer.toString(value));
+ } while (destDir.exists());
+
+ if (this.flags.contains(Flags.VERBOSE)) {
+ System.out.println("Compilation unit for " + type.getName() +
+ " : compiled into " + destDir);
+ for (JavaFileObject jfo : files) {
+ System.out.println(jfo.toString());
+ }
+ }
+
+ try {
+ destDir.mkdirs();
+ this.fm.setLocation(
+ StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "IOException encountered during compilation");
+ }
+ Boolean result = ct.call();
+ if (result == Boolean.FALSE) {
+ throw new RuntimeException(
+ "Compilation failure in " + type.getName() + " unit");
+ }
+ if (this.flags.contains(Flags.USECACHE)) {
+ File existing = cache.putIfAbsent(type.getName(), destDir);
+ if (existing != null) {
+ deleteDir(destDir);
+ return existing;
+ }
+ } else {
+ this.tempDirs.add(destDir);
+ }
+ return destDir;
+ }
+
+ private static void deleteDir(File dir) {
+ for (File f : dir.listFiles()) {
+ f.delete();
+ };
+ dir.delete();
+ }
+
+ public void cleanup() {
+ if (!this.flags.contains(Flags.USECACHE)) {
+ for (File d : tempDirs) {
+ deleteDir(d);
+ };
+ tempDirs = new ArrayList<>();
+ }
+ }
+
+ // Removes all of the elements in the cache and deletes the associated
+ // output directories. This may not actually empty the cache if there
+ // are concurrent users of it.
+ public static void purgeCache() {
+ for (Map.Entry<String,File> entry : cache.entrySet()) {
+ cache.remove(entry.getKey());
+ deleteDir(entry.getValue());
+ }
+ }
+}