test/tools/javac/varargs/7042566/T7042566.java

Tue, 08 Jan 2013 13:47:57 +0000

author
vromero
date
Tue, 08 Jan 2013 13:47:57 +0000
changeset 1482
954541f13717
parent 1006
a2d422d480cb
child 1520
5c956be64b9e
permissions
-rw-r--r--

8005167: execution time of combo tests in javac should be improved
Reviewed-by: jjg, jjh

     1 /*
     2  * Copyright (c) 2011, 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 7042566
    27  * @summary Unambiguous varargs method calls flagged as ambiguous
    28  * @library ../../lib
    29  * @build JavacTestingAbstractThreadedTest
    30  * @run main T7042566
    31  */
    33 import java.io.File;
    34 import java.net.URI;
    35 import java.util.Arrays;
    36 import java.util.Locale;
    37 import java.util.concurrent.atomic.AtomicInteger;
    38 import javax.tools.Diagnostic;
    39 import javax.tools.JavaCompiler;
    40 import javax.tools.JavaFileObject;
    41 import javax.tools.SimpleJavaFileObject;
    42 import javax.tools.ToolProvider;
    44 import com.sun.source.util.JavacTask;
    45 import com.sun.tools.classfile.Instruction;
    46 import com.sun.tools.classfile.Attribute;
    47 import com.sun.tools.classfile.ClassFile;
    48 import com.sun.tools.classfile.Code_attribute;
    49 import com.sun.tools.classfile.ConstantPool.*;
    50 import com.sun.tools.classfile.Method;
    51 import com.sun.tools.javac.util.List;
    53 public class T7042566
    54     extends JavacTestingAbstractThreadedTest
    55     implements Runnable {
    57     VarargsMethod m1;
    58     VarargsMethod m2;
    59     TypeConfiguration actuals;
    61     T7042566(TypeConfiguration m1_conf, TypeConfiguration m2_conf,
    62             TypeConfiguration actuals) {
    63         this.m1 = new VarargsMethod(m1_conf);
    64         this.m2 = new VarargsMethod(m2_conf);
    65         this.actuals = actuals;
    66     }
    68     @Override
    69     public void run() {
    70         int id = checkCount.incrementAndGet();
    71         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
    72         JavaSource source = new JavaSource(id);
    73         ErrorChecker ec = new ErrorChecker();
    74         JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), ec,
    75                 null, null, Arrays.asList(source));
    76         ct.call();
    77         check(source, ec, id);
    78     }
    80     void check(JavaSource source, ErrorChecker ec, int id) {
    81         boolean resolutionError = false;
    82         VarargsMethod selectedMethod = null;
    84         boolean m1_applicable = m1.isApplicable(actuals);
    85         boolean m2_applicable = m2.isApplicable(actuals);
    87         if (!m1_applicable && !m2_applicable) {
    88             resolutionError = true;
    89         } else if (m1_applicable && m2_applicable) {
    90             //most specific
    91             boolean m1_moreSpecific = m1.isMoreSpecificThan(m2);
    92             boolean m2_moreSpecific = m2.isMoreSpecificThan(m1);
    94             resolutionError = m1_moreSpecific == m2_moreSpecific;
    95             selectedMethod = m1_moreSpecific ? m1 : m2;
    96         } else {
    97             selectedMethod = m1_applicable ?
    98                 m1 : m2;
    99         }
   101         if (ec.errorFound != resolutionError) {
   102             throw new Error("invalid diagnostics for source:\n" +
   103                     source.getCharContent(true) +
   104                     "\nExpected resolution error: " + resolutionError +
   105                     "\nFound error: " + ec.errorFound +
   106                     "\nCompiler diagnostics:\n" + ec.printDiags());
   107         } else if (!resolutionError) {
   108             verifyBytecode(selectedMethod, source, id);
   109         }
   110     }
   112     void verifyBytecode(VarargsMethod selected, JavaSource source, int id) {
   113         bytecodeCheckCount.incrementAndGet();
   114         File compiledTest = new File(String.format("Test%d.class", id));
   115         try {
   116             ClassFile cf = ClassFile.read(compiledTest);
   117             Method testMethod = null;
   118             for (Method m : cf.methods) {
   119                 if (m.getName(cf.constant_pool).equals("test")) {
   120                     testMethod = m;
   121                     break;
   122                 }
   123             }
   124             if (testMethod == null) {
   125                 throw new Error("Test method not found");
   126             }
   127             Code_attribute ea =
   128                 (Code_attribute)testMethod.attributes.get(Attribute.Code);
   129             if (testMethod == null) {
   130                 throw new Error("Code attribute for test() method not found");
   131             }
   133             for (Instruction i : ea.getInstructions()) {
   134                 if (i.getMnemonic().equals("invokevirtual")) {
   135                     int cp_entry = i.getUnsignedShort(1);
   136                     CONSTANT_Methodref_info methRef =
   137                         (CONSTANT_Methodref_info)cf.constant_pool.get(cp_entry);
   138                     String type = methRef.getNameAndTypeInfo().getType();
   139                     String sig = selected.parameterTypes.bytecodeSigStr;
   140                     if (!type.contains(sig)) {
   141                         throw new Error("Unexpected type method call: " +
   142                                         type + "" +
   143                                         "\nfound: " + sig +
   144                                         "\n" + source.getCharContent(true));
   145                     }
   146                     break;
   147                 }
   148             }
   149         } catch (Exception e) {
   150             e.printStackTrace();
   151             throw new Error("error reading " + compiledTest +": " + e);
   152         }
   153     }
   155     class JavaSource extends SimpleJavaFileObject {
   157         static final String source_template = "class Test#ID {\n" +
   158                 "   #V1\n" +
   159                 "   #V2\n" +
   160                 "   void test() { m(#E); }\n" +
   161                 "}";
   163         String source;
   165         public JavaSource(int id) {
   166             super(URI.create(String.format("myfo:/Test%d.java", id)),
   167                     JavaFileObject.Kind.SOURCE);
   168             source = source_template.replaceAll("#V1", m1.toString())
   169                     .replaceAll("#V2", m2.toString())
   170                     .replaceAll("#E", actuals.expressionListStr)
   171                     .replaceAll("#ID", String.valueOf(id));
   172         }
   174         @Override
   175         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   176             return source;
   177         }
   178     }
   180     public static void main(String... args) throws Exception {
   181         for (TypeConfiguration tconf1 : TypeConfiguration.values()) {
   182             for (TypeConfiguration tconf2 : TypeConfiguration.values()) {
   183                 for (TypeConfiguration tconf3 : TypeConfiguration.values()) {
   184                     pool.execute(new T7042566(tconf1, tconf2, tconf3));
   185                 }
   186             }
   187         }
   189         outWriter.println("Bytecode checks made: " + bytecodeCheckCount.get());
   190         checkAfterExec();
   191     }
   193     enum TypeKind {
   194         OBJECT("Object", "(Object)null", "Ljava/lang/Object;"),
   195         STRING("String", "(String)null", "Ljava/lang/String;");
   197         String typeString;
   198         String valueString;
   199         String bytecodeString;
   201         TypeKind(String typeString, String valueString, String bytecodeString) {
   202             this.typeString = typeString;
   203             this.valueString = valueString;
   204             this.bytecodeString = bytecodeString;
   205         }
   207         boolean isSubtypeOf(TypeKind that) {
   208             return that == OBJECT ||
   209                     (that == STRING && this == STRING);
   210         }
   211     }
   213     enum TypeConfiguration {
   214         A(TypeKind.OBJECT),
   215         B(TypeKind.STRING),
   216         AA(TypeKind.OBJECT, TypeKind.OBJECT),
   217         AB(TypeKind.OBJECT, TypeKind.STRING),
   218         BA(TypeKind.STRING, TypeKind.OBJECT),
   219         BB(TypeKind.STRING, TypeKind.STRING),
   220         AAA(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.OBJECT),
   221         AAB(TypeKind.OBJECT, TypeKind.OBJECT, TypeKind.STRING),
   222         ABA(TypeKind.OBJECT, TypeKind.STRING, TypeKind.OBJECT),
   223         ABB(TypeKind.OBJECT, TypeKind.STRING, TypeKind.STRING),
   224         BAA(TypeKind.STRING, TypeKind.OBJECT, TypeKind.OBJECT),
   225         BAB(TypeKind.STRING, TypeKind.OBJECT, TypeKind.STRING),
   226         BBA(TypeKind.STRING, TypeKind.STRING, TypeKind.OBJECT),
   227         BBB(TypeKind.STRING, TypeKind.STRING, TypeKind.STRING);
   229         List<TypeKind> typeKindList;
   230         String expressionListStr;
   231         String parameterListStr;
   232         String bytecodeSigStr;
   234         private TypeConfiguration(TypeKind... typeKindList) {
   235             this.typeKindList = List.from(typeKindList);
   236             expressionListStr = asExpressionList();
   237             parameterListStr = asParameterList();
   238             bytecodeSigStr = asBytecodeString();
   239         }
   241         private String asExpressionList() {
   242             StringBuilder buf = new StringBuilder();
   243             String sep = "";
   244             for (TypeKind tk : typeKindList) {
   245                 buf.append(sep);
   246                 buf.append(tk.valueString);
   247                 sep = ",";
   248             }
   249             return buf.toString();
   250         }
   252         private String asParameterList() {
   253             StringBuilder buf = new StringBuilder();
   254             String sep = "";
   255             int count = 0;
   256             for (TypeKind arg : typeKindList) {
   257                 buf.append(sep);
   258                 buf.append(arg.typeString);
   259                 if (count == (typeKindList.size() - 1)) {
   260                     buf.append("...");
   261                 }
   262                 buf.append(" ");
   263                 buf.append("arg" + count++);
   264                 sep = ",";
   265             }
   266             return buf.toString();
   267         }
   269         private String asBytecodeString() {
   270             StringBuilder buf = new StringBuilder();
   271             int count = 0;
   272             for (TypeKind arg : typeKindList) {
   273                 if (count == (typeKindList.size() - 1)) {
   274                     buf.append("[");
   275                 }
   276                 buf.append(arg.bytecodeString);
   277                 count++;
   278             }
   279             return buf.toString();
   280         }
   281     }
   283     static class VarargsMethod {
   284         TypeConfiguration parameterTypes;
   286         public VarargsMethod(TypeConfiguration parameterTypes) {
   287             this.parameterTypes = parameterTypes;
   288         }
   290         @Override
   291         public String toString() {
   292             return "void m( " + parameterTypes.parameterListStr + ") {}";
   293         }
   295         boolean isApplicable(TypeConfiguration that) {
   296             List<TypeKind> actuals = that.typeKindList;
   297             List<TypeKind> formals = parameterTypes.typeKindList;
   298             if ((actuals.size() - formals.size()) < -1)
   299                 return false; //not enough args
   300             for (TypeKind actual : actuals) {
   301                 if (!actual.isSubtypeOf(formals.head))
   302                     return false; //type mismatch
   303                 formals = formals.tail.isEmpty() ?
   304                     formals :
   305                     formals.tail;
   306             }
   307             return true;
   308         }
   310         boolean isMoreSpecificThan(VarargsMethod that) {
   311             List<TypeKind> actuals = parameterTypes.typeKindList;
   312             List<TypeKind> formals = that.parameterTypes.typeKindList;
   313             int checks = 0;
   314             int expectedCheck = Math.max(actuals.size(), formals.size());
   315             while (checks < expectedCheck) {
   316                 if (!actuals.head.isSubtypeOf(formals.head))
   317                     return false; //type mismatch
   318                 formals = formals.tail.isEmpty() ?
   319                     formals :
   320                     formals.tail;
   321                 actuals = actuals.tail.isEmpty() ?
   322                     actuals :
   323                     actuals.tail;
   324                 checks++;
   325             }
   326             return true;
   327         }
   328     }
   330     static class ErrorChecker
   331         implements javax.tools.DiagnosticListener<JavaFileObject> {
   333         boolean errorFound;
   334         List<String> errDiags = List.nil();
   336         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   337             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   338                 errDiags = errDiags
   339                         .append(diagnostic.getMessage(Locale.getDefault()));
   340                 errorFound = true;
   341             }
   342         }
   344         String printDiags() {
   345             StringBuilder buf = new StringBuilder();
   346             for (String s : errDiags) {
   347                 buf.append(s);
   348                 buf.append("\n");
   349             }
   350             return buf.toString();
   351         }
   352     }
   354     //number of bytecode checks made while running combo tests
   355     static AtomicInteger bytecodeCheckCount = new AtomicInteger();
   357 }

mercurial