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