test/tools/javac/lambda/bridge/TestMetafactoryBridges.java

Mon, 01 Jun 2015 15:19:54 -0700

author
darcy
date
Mon, 01 Jun 2015 15:19:54 -0700
changeset 3834
45746e46893b
parent 0
959103a6100f
permissions
-rw-r--r--

8075546: Add tiered testing definitions to the langtools repo
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2013, 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  */
    24 /*
    25  * @test
    26  * @bug 8013789
    27  * @summary Compiler should emit bridges in interfaces
    28  */
    30 import com.sun.source.util.JavacTask;
    31 import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
    32 import com.sun.tools.javac.code.Symbol;
    33 import com.sun.tools.javac.util.JCDiagnostic;
    35 import java.io.File;
    36 import java.io.PrintWriter;
    37 import java.net.URI;
    38 import java.util.ArrayList;
    39 import java.util.Arrays;
    40 import java.util.EnumSet;
    41 import java.util.List;
    42 import java.util.Set;
    44 import javax.tools.Diagnostic;
    45 import javax.tools.Diagnostic.Kind;
    46 import javax.tools.JavaCompiler;
    47 import javax.tools.JavaFileObject;
    48 import javax.tools.SimpleJavaFileObject;
    49 import javax.tools.ToolProvider;
    51 public class TestMetafactoryBridges {
    53     static int checkCount = 0;
    55     enum ClasspathKind {
    56         NONE(),
    57         B7(7, ClassKind.B),
    58         A7(7, ClassKind.A),
    59         B8(8, ClassKind.B),
    60         A8(8, ClassKind.A);
    62         int version;
    63         ClassKind ck;
    65         ClasspathKind() {
    66             this(-1, null);
    67         }
    69         ClasspathKind(int version, ClassKind ck) {
    70             this.version = version;
    71             this.ck = ck;
    72         }
    73     }
    75     enum PreferPolicy {
    76         SOURCE("-Xprefer:source"),
    77         NEWER("-Xprefer:newer");
    79         String preferOpt;
    81         PreferPolicy(String preferOpt) {
    82             this.preferOpt = preferOpt;
    83         }
    84     }
    86     enum SourcepathKind {
    87         NONE,
    88         A(ClassKind.A),
    89         B(ClassKind.B),
    90         C(ClassKind.C),
    91         AB(ClassKind.A, ClassKind.B),
    92         BC(ClassKind.B, ClassKind.C),
    93         AC(ClassKind.A, ClassKind.C),
    94         ABC(ClassKind.A, ClassKind.B, ClassKind.C);
    96         List<ClassKind> sources;
    98         SourcepathKind(ClassKind... sources) {
    99             this.sources = Arrays.asList(sources);
   100         }
   101     }
   103     enum SourceSet {
   104         ALL() {
   105             @Override
   106             List<List<ClassKind>> permutations() {
   107                 return Arrays.asList(
   108                     Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
   109                     Arrays.asList(ClassKind.A, ClassKind.B, ClassKind.C),
   110                     Arrays.asList(ClassKind.B, ClassKind.A, ClassKind.C),
   111                     Arrays.asList(ClassKind.B, ClassKind.C, ClassKind.A),
   112                     Arrays.asList(ClassKind.C, ClassKind.A, ClassKind.B),
   113                     Arrays.asList(ClassKind.C, ClassKind.B, ClassKind.A)
   114                 );
   115             }
   116         },
   117         AC() {
   118             @Override
   119             List<List<ClassKind>> permutations() {
   120                 return Arrays.asList(
   121                     Arrays.asList(ClassKind.A, ClassKind.C),
   122                     Arrays.asList(ClassKind.C, ClassKind.A)
   123                 );
   124             }
   125         },
   126         C() {
   127             @Override
   128             List<List<ClassKind>> permutations() {
   129                 return Arrays.asList(Arrays.asList(ClassKind.C));
   130             }
   131         };
   133         abstract List<List<ClassKind>> permutations();
   134     }
   136     enum ClassKind {
   137         A("A", "interface A { Object m(); }"),
   138         B("B", "interface B extends A { Integer m(); }", A),
   139         C("C", "class C { B b = ()->42; }", A, B);
   141         String name;
   142         String source;
   143         ClassKind[] deps;
   145         ClassKind(String name, String source, ClassKind... deps) {
   146             this.name = name;
   147             this.source = source;
   148             this.deps = deps;
   149         }
   150     }
   152     public static void main(String... args) throws Exception {
   153         String SCRATCH_DIR = System.getProperty("user.dir");
   154         //create default shared JavaCompiler - reused across multiple compilations
   155         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   157         int n = 0;
   158         for (SourceSet ss : SourceSet.values()) {
   159             for (List<ClassKind> sources : ss.permutations()) {
   160                 for (SourcepathKind spKind : SourcepathKind.values()) {
   161                     for (ClasspathKind cpKind : ClasspathKind.values()) {
   162                         for (PreferPolicy pp : PreferPolicy.values()) {
   163                             Set<ClassKind> deps = EnumSet.noneOf(ClassKind.class);
   164                             if (cpKind.ck != null) {
   165                                 deps.add(cpKind.ck);
   166                             }
   167                             deps.addAll(sources);
   168                             if (deps.size() < 3) continue;
   169                             File testDir = new File(SCRATCH_DIR, "test" + n);
   170                             testDir.mkdir();
   171                             try (PrintWriter debugWriter = new PrintWriter(new File(testDir, "debug.txt"))) {
   172                                 new TestMetafactoryBridges(testDir, sources, spKind, cpKind, pp, debugWriter).run(comp);
   173                                 n++;
   174                             }
   175                         }
   176                     }
   177                 }
   178             }
   179         }
   180         System.out.println("Total check executed: " + checkCount);
   181     }
   183     File testDir;
   184     List<ClassKind> sources;
   185     SourcepathKind spKind;
   186     ClasspathKind cpKind;
   187     PreferPolicy pp;
   188     PrintWriter debugWriter;
   189     DiagnosticChecker diagChecker;
   191     TestMetafactoryBridges(File testDir, List<ClassKind>sources, SourcepathKind spKind,
   192             ClasspathKind cpKind, PreferPolicy pp, PrintWriter debugWriter) {
   193         this.testDir = testDir;
   194         this.sources = sources;
   195         this.spKind = spKind;
   196         this.cpKind = cpKind;
   197         this.pp = pp;
   198         this.debugWriter = debugWriter;
   199         this.diagChecker = new DiagnosticChecker();
   200     }
   202     class JavaSource extends SimpleJavaFileObject {
   204         final String source;
   206         public JavaSource(ClassKind ck) {
   207             super(URI.create(String.format("myfo:/%s.java", ck.name)), JavaFileObject.Kind.SOURCE);
   208             this.source = ck.source;
   209         }
   211         @Override
   212         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   213             return source;
   214         }
   215     }
   217     void run(JavaCompiler tool) throws Exception {
   218         File classesDir = new File(testDir, "classes");
   219         File outDir = new File(testDir, "out");
   220         File srcDir = new File(testDir, "src");
   221         classesDir.mkdir();
   222         outDir.mkdir();
   223         srcDir.mkdir();
   225         debugWriter.append(testDir.getName() + "\n");
   226         debugWriter.append("sources = " + sources + "\n");
   227         debugWriter.append("spKind = " + spKind  + "\n");
   228         debugWriter.append("cpKind = " + cpKind + "\n");
   229         debugWriter.append("preferPolicy = " + pp.preferOpt + "\n");
   231         //step 1 - prepare sources (older!!)
   232         debugWriter.append("Preparing sources\n");
   233         for (ClassKind ck : spKind.sources) {
   234             //skip sources explicitly provided on command line
   235             if (!sources.contains(ck)) {
   236                 debugWriter.append("Copy " + ck.name + ".java to" + srcDir.getAbsolutePath() + "\n");
   237                 File dest = new File(srcDir, ck.name + ".java");
   238                 PrintWriter pw = new PrintWriter(dest);
   239                 pw.append(ck.source);
   240                 pw.close();
   241             }
   242         }
   244         //step 2 - prepare classes
   245         debugWriter.append("Preparing classes\n");
   246         if (cpKind != ClasspathKind.NONE) {
   247             List<JavaSource> sources = new ArrayList<>();
   248             ClassKind toRemove = null;
   249             sources.add(new JavaSource(cpKind.ck));
   250             if (cpKind.ck.deps.length != 0) {
   251                 //at most only one dependency
   252                 toRemove = cpKind.ck.deps[0];
   253                 sources.add(new JavaSource(toRemove));
   254             }
   255             JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, null,
   256                     Arrays.asList("-d", classesDir.getAbsolutePath(), "-source", String.valueOf(cpKind.version)), null, sources);
   257             try {
   258                 ct.generate();
   259                 if (toRemove != null) {
   260                     debugWriter.append("Remove " + toRemove.name + ".class from" + classesDir.getAbsolutePath() + "\n");
   261                     File fileToRemove = new File(classesDir, toRemove.name + ".class");
   262                     fileToRemove.delete();
   263                 }
   264             } catch (Throwable ex) {
   265                 throw new AssertionError("Error thrown when generating side-classes");
   266             }
   267         }
   269         //step 3 - compile
   270         debugWriter.append("Compiling test\n");
   271         List<JavaSource> sourcefiles = new ArrayList<>();
   272         for (ClassKind ck : sources) {
   273             sourcefiles.add(new JavaSource(ck));
   274         }
   275         JavacTask ct = (JavacTask)tool.getTask(debugWriter, null, diagChecker,
   276                     Arrays.asList("-XDdumpLambdaToMethodStats", "-d", outDir.getAbsolutePath(),
   277                                   "-sourcepath", srcDir.getAbsolutePath(),
   278                                   "-classpath", classesDir.getAbsolutePath(),
   279                                   pp.preferOpt), null, sourcefiles);
   280         try {
   281             ct.generate();
   282         } catch (Throwable ex) {
   283             throw new AssertionError("Error thrown when compiling test case");
   284         }
   285         check();
   286     }
   288     void check() {
   289         checkCount++;
   290         if (diagChecker.errorFound) {
   291             throw new AssertionError("Unexpected compilation failure");
   292         }
   294         boolean altMetafactory =
   295                 cpKind == ClasspathKind.B7 &&
   296                 !sources.contains(ClassKind.B) &&
   297                 (pp == PreferPolicy.NEWER || !spKind.sources.contains(ClassKind.B));
   299         if (altMetafactory != diagChecker.altMetafactory) {
   300             throw new AssertionError("Bad metafactory detected - expected altMetafactory: " + altMetafactory +
   301                     "\ntest: " + testDir);
   302         }
   303     }
   305     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   307         boolean altMetafactory = false;
   308         boolean errorFound = false;
   310         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   311             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   312                 errorFound = true;
   313             } else if (statProcessor.matches(diagnostic)) {
   314                 statProcessor.process(diagnostic);
   315             }
   316         }
   318         abstract class DiagnosticProcessor {
   320             List<String> codes;
   321             Diagnostic.Kind kind;
   323             public DiagnosticProcessor(Kind kind, String... codes) {
   324                 this.codes = Arrays.asList(codes);
   325                 this.kind = kind;
   326             }
   328             abstract void process(Diagnostic<? extends JavaFileObject> diagnostic);
   330             boolean matches(Diagnostic<? extends JavaFileObject> diagnostic) {
   331                 return (codes.isEmpty() || codes.contains(diagnostic.getCode())) &&
   332                         diagnostic.getKind() == kind;
   333             }
   335             JCDiagnostic asJCDiagnostic(Diagnostic<? extends JavaFileObject> diagnostic) {
   336                 if (diagnostic instanceof JCDiagnostic) {
   337                     return (JCDiagnostic)diagnostic;
   338                 } else if (diagnostic instanceof DiagnosticSourceUnwrapper) {
   339                     return ((DiagnosticSourceUnwrapper)diagnostic).d;
   340                 } else {
   341                     throw new AssertionError("Cannot convert diagnostic to JCDiagnostic: " + diagnostic.getClass().getName());
   342                 }
   343             }
   344         }
   346         DiagnosticProcessor statProcessor = new DiagnosticProcessor(Kind.NOTE,
   347                 "compiler.note.lambda.stat",
   348                 "compiler.note.mref.stat",
   349                 "compiler.note.mref.stat.1") {
   350             @Override
   351             void process(Diagnostic<? extends JavaFileObject> diagnostic) {
   352                 JCDiagnostic diag = asJCDiagnostic(diagnostic);
   353                 if ((Boolean)diag.getArgs()[0]) {
   354                     altMetafactory = true;
   355                 }
   356             }
   357         };
   358     }
   359 }

mercurial