langtools/test/tools/javac/lambda/TestInvokeDynamic.java
changeset 32454 b0ac04e0fefe
parent 30846 2b3f379840f0
equal deleted inserted replaced
32453:8eebd1f0b8ea 32454:b0ac04e0fefe
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
    24 /*
    24 /*
    25  * @test
    25  * @test
    26  * @bug 7194586 8003280 8006694 8010404
    26  * @bug 7194586 8003280 8006694 8010404 8129962
    27  * @summary Add lambda tests
    27  * @summary Add lambda tests
    28  *  Add back-end support for invokedynamic
    28  *  Add back-end support for invokedynamic
    29  *  temporarily workaround combo tests are causing time out in several platforms
    29  *  temporarily workaround combo tests are causing time out in several platforms
    30  * @library ../lib
    30  * @library /tools/javac/lib
    31  * @modules jdk.jdeps/com.sun.tools.classfile
    31  * @modules jdk.jdeps/com.sun.tools.classfile
    32  *          jdk.compiler/com.sun.tools.javac.api
    32  *          jdk.compiler/com.sun.tools.javac.api
    33  *          jdk.compiler/com.sun.tools.javac.code
    33  *          jdk.compiler/com.sun.tools.javac.code
       
    34  *          jdk.compiler/com.sun.tools.javac.comp
       
    35  *          jdk.compiler/com.sun.tools.javac.main
    34  *          jdk.compiler/com.sun.tools.javac.jvm
    36  *          jdk.compiler/com.sun.tools.javac.jvm
    35  *          jdk.compiler/com.sun.tools.javac.tree
    37  *          jdk.compiler/com.sun.tools.javac.tree
    36  *          jdk.compiler/com.sun.tools.javac.util
    38  *          jdk.compiler/com.sun.tools.javac.util
    37  * @build JavacTestingAbstractThreadedTest
    39  * @build combo.ComboTestHelper
    38  * @run main/othervm TestInvokeDynamic
    40  * @run main TestInvokeDynamic
    39  */
    41  */
    40 
    42 
    41 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047)
    43 import java.io.IOException;
    42 // see JDK-8006746
    44 import java.io.InputStream;
    43 
    45 
    44 import java.io.File;
       
    45 import java.net.URI;
       
    46 import java.util.ArrayList;
       
    47 import java.util.Arrays;
       
    48 import java.util.Locale;
       
    49 
       
    50 import javax.tools.Diagnostic;
       
    51 import javax.tools.JavaFileObject;
    46 import javax.tools.JavaFileObject;
    52 import javax.tools.SimpleJavaFileObject;
       
    53 
    47 
    54 import com.sun.source.tree.MethodInvocationTree;
    48 import com.sun.source.tree.MethodInvocationTree;
    55 import com.sun.source.tree.MethodTree;
    49 import com.sun.source.tree.MethodTree;
    56 import com.sun.source.util.TaskEvent;
    50 import com.sun.source.util.TaskEvent;
    57 import com.sun.source.util.TaskListener;
    51 import com.sun.source.util.TaskListener;
    76 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
    70 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
    77 import com.sun.tools.javac.tree.JCTree.JCIdent;
    71 import com.sun.tools.javac.tree.JCTree.JCIdent;
    78 import com.sun.tools.javac.util.Context;
    72 import com.sun.tools.javac.util.Context;
    79 import com.sun.tools.javac.util.Names;
    73 import com.sun.tools.javac.util.Names;
    80 
    74 
       
    75 import combo.ComboParameter;
       
    76 import combo.ComboTask;
       
    77 import combo.ComboTestHelper;
       
    78 import combo.ComboInstance;
       
    79 import combo.ComboTask.Result;
       
    80 
    81 import static com.sun.tools.javac.jvm.ClassFile.*;
    81 import static com.sun.tools.javac.jvm.ClassFile.*;
    82 
    82 
    83 public class TestInvokeDynamic
    83 public class TestInvokeDynamic extends ComboInstance<TestInvokeDynamic> {
    84     extends JavacTestingAbstractThreadedTest
    84 
    85     implements Runnable {
    85     enum StaticArgumentKind implements ComboParameter {
    86 
       
    87     enum StaticArgumentKind {
       
    88         STRING("Hello!", "String", "Ljava/lang/String;") {
    86         STRING("Hello!", "String", "Ljava/lang/String;") {
    89             @Override
    87             @Override
    90             boolean check(CPInfo cpInfo) throws Exception {
    88             boolean check(CPInfo cpInfo) throws Exception {
    91                 return (cpInfo instanceof CONSTANT_String_info) &&
    89                 return (cpInfo instanceof CONSTANT_String_info) &&
    92                         ((CONSTANT_String_info)cpInfo).getString()
    90                         ((CONSTANT_String_info)cpInfo).getString()
   187                     return syms.arrayCloneMethod.type;
   185                     return syms.arrayCloneMethod.type;
   188                 default:
   186                 default:
   189                     throw new AssertionError();
   187                     throw new AssertionError();
   190             }
   188             }
   191         }
   189         }
   192     }
   190 
   193 
   191         @Override
   194     enum StaticArgumentsArity {
   192         public String expand(String optParameter) {
   195         ZERO(0),
   193             return sourceTypeStr;
   196         ONE(1),
   194         }
   197         TWO(2),
   195     }
   198         THREE(3);
   196 
       
   197     enum StaticArgumentsArity implements ComboParameter {
       
   198         ZERO(0, ""),
       
   199         ONE(1, ",#{SARG[0]} s1"),
       
   200         TWO(2, ",#{SARG[0]} s1, #{SARG[1]} s2"),
       
   201         THREE(3, ",#{SARG[0]} s1, #{SARG[1]} s2, #{SARG[2]} s3");
   199 
   202 
   200         int arity;
   203         int arity;
   201 
   204         String argsTemplate;
   202         StaticArgumentsArity(int arity) {
   205 
       
   206         StaticArgumentsArity(int arity, String argsTemplate) {
   203             this.arity = arity;
   207             this.arity = arity;
       
   208             this.argsTemplate = argsTemplate;
       
   209         }
       
   210 
       
   211         @Override
       
   212         public String expand(String optParameter) {
       
   213             return argsTemplate;
   204         }
   214         }
   205     }
   215     }
   206 
   216 
   207     public static void main(String... args) throws Exception {
   217     public static void main(String... args) throws Exception {
   208         for (StaticArgumentsArity arity : StaticArgumentsArity.values()) {
   218         new ComboTestHelper<TestInvokeDynamic>()
   209             if (arity.arity == 0) {
   219                 .withFilter(TestInvokeDynamic::redundantTestFilter)
   210                 pool.execute(new TestInvokeDynamic(arity));
   220                 .withDimension("SARGS", (x, arity) -> x.arity = arity, StaticArgumentsArity.values())
   211             } else {
   221                 .withArrayDimension("SARG", (x, arg, idx) -> x.saks[idx] = arg, 3, StaticArgumentKind.values())
   212                 for (StaticArgumentKind sak1 : StaticArgumentKind.values()) {
   222                 .run(TestInvokeDynamic::new);
   213                     if (arity.arity == 1) {
       
   214                         pool.execute(new TestInvokeDynamic(arity, sak1));
       
   215                     } else {
       
   216                         for (StaticArgumentKind sak2 : StaticArgumentKind.values()) {
       
   217                             if (arity.arity == 2) {
       
   218                                 pool.execute(new TestInvokeDynamic(arity, sak1, sak2));
       
   219                             } else {
       
   220                                 for (StaticArgumentKind sak3 : StaticArgumentKind.values()) {
       
   221                                     pool.execute(
       
   222                                         new TestInvokeDynamic(arity, sak1, sak2, sak3));
       
   223                                 }
       
   224                             }
       
   225                         }
       
   226                     }
       
   227                 }
       
   228             }
       
   229         }
       
   230 
       
   231         checkAfterExec();
       
   232     }
   223     }
   233 
   224 
   234     StaticArgumentsArity arity;
   225     StaticArgumentsArity arity;
   235     StaticArgumentKind[] saks;
   226     StaticArgumentKind[] saks = new StaticArgumentKind[3];
   236     DiagChecker dc;
   227 
   237 
   228     boolean redundantTestFilter() {
   238     TestInvokeDynamic(StaticArgumentsArity arity, StaticArgumentKind... saks) {
   229         for (int i = arity.arity ; i < saks.length ; i++) {
   239         this.arity = arity;
   230             if (saks[i].ordinal() != 0) {
   240         this.saks = saks;
   231                 return false;
   241         dc = new DiagChecker();
   232             }
   242     }
   233         }
   243 
   234         return true;
   244     public void run() {
   235     }
   245         int id = checkCount.incrementAndGet();
   236 
   246         JavaSource source = new JavaSource(id);
   237     final String source_template =
   247         JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, fm.get(), dc,
   238                 "import java.lang.invoke.*;\n" +
   248                 Arrays.asList("-g"), null, Arrays.asList(source));
   239                 "class Test {\n" +
       
   240                 "   void m() { }\n" +
       
   241                 "   void test() {\n" +
       
   242                 "      Object o = this; // marker statement \n" +
       
   243                 "      m();\n" +
       
   244                 "   }\n" +
       
   245                 "}\n" +
       
   246                 "class Bootstrap {\n" +
       
   247                 "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
       
   248                 "String name, MethodType methodType #{SARGS}) {\n" +
       
   249                 "       return null;\n" +
       
   250                 "   }\n" +
       
   251                 "}";
       
   252 
       
   253     @Override
       
   254     public void doWork() throws IOException {
       
   255         ComboTask comboTask = newCompilationTask()
       
   256                 .withOption("-g")
       
   257                 .withSourceFromTemplate(source_template);
       
   258 
       
   259         JavacTaskImpl ct = (JavacTaskImpl)comboTask.getTask();
   249         Context context = ct.getContext();
   260         Context context = ct.getContext();
   250         Symtab syms = Symtab.instance(context);
   261         Symtab syms = Symtab.instance(context);
   251         Names names = Names.instance(context);
   262         Names names = Names.instance(context);
   252         Types types = Types.instance(context);
   263         Types types = Types.instance(context);
   253         ct.addTaskListener(new Indifier(syms, names, types));
   264         ct.addTaskListener(new Indifier(syms, names, types));
   254         try {
   265         verifyBytecode(comboTask.generate());
   255             ct.generate();
   266     }
   256         } catch (Throwable t) {
   267 
   257             t.printStackTrace();
   268     void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) {
   258             throw new AssertionError(
   269         if (res.hasErrors()) {
   259                     String.format("Error thrown when compiling following code\n%s",
   270             fail("Diags found when compiling instance: " + res.compilationInfo());
   260                     source.source));
   271             return;
   261         }
   272         }
   262         if (dc.diagFound) {
   273         try (InputStream is = res.get().iterator().next().openInputStream()){
   263             throw new AssertionError(
   274             ClassFile cf = ClassFile.read(is);
   264                     String.format("Diags found when compiling following code\n%s\n\n%s",
       
   265                     source.source, dc.printDiags()));
       
   266         }
       
   267         verifyBytecode(id);
       
   268     }
       
   269 
       
   270     void verifyBytecode(int id) {
       
   271         File compiledTest = new File(String.format("Test%d.class", id));
       
   272         try {
       
   273             ClassFile cf = ClassFile.read(compiledTest);
       
   274             Method testMethod = null;
   275             Method testMethod = null;
   275             for (Method m : cf.methods) {
   276             for (Method m : cf.methods) {
   276                 if (m.getName(cf.constant_pool).equals("test")) {
   277                 if (m.getName(cf.constant_pool).equals("test")) {
   277                     testMethod = m;
   278                     testMethod = m;
   278                     break;
   279                     break;
   279                 }
   280                 }
   280             }
   281             }
   281             if (testMethod == null) {
   282             if (testMethod == null) {
   282                 throw new Error("Test method not found");
   283                 fail("Test method not found");
       
   284                 return;
   283             }
   285             }
   284             Code_attribute ea =
   286             Code_attribute ea =
   285                     (Code_attribute)testMethod.attributes.get(Attribute.Code);
   287                     (Code_attribute)testMethod.attributes.get(Attribute.Code);
   286             if (testMethod == null) {
   288             if (testMethod == null) {
   287                 throw new Error("Code attribute for test() method not found");
   289                 fail("Code attribute for test() method not found");
       
   290                 return;
   288             }
   291             }
   289 
   292 
   290             int bsmIdx = -1;
   293             int bsmIdx = -1;
   291 
   294 
   292             for (Instruction i : ea.getInstructions()) {
   295             for (Instruction i : ea.getInstructions()) {
   294                     CONSTANT_InvokeDynamic_info indyInfo =
   297                     CONSTANT_InvokeDynamic_info indyInfo =
   295                          (CONSTANT_InvokeDynamic_info)cf
   298                          (CONSTANT_InvokeDynamic_info)cf
   296                             .constant_pool.get(i.getShort(1));
   299                             .constant_pool.get(i.getShort(1));
   297                     bsmIdx = indyInfo.bootstrap_method_attr_index;
   300                     bsmIdx = indyInfo.bootstrap_method_attr_index;
   298                     if (!indyInfo.getNameAndTypeInfo().getType().equals("()V")) {
   301                     if (!indyInfo.getNameAndTypeInfo().getType().equals("()V")) {
   299                         throw new
   302                         fail("type mismatch for CONSTANT_InvokeDynamic_info");
   300                             AssertionError("type mismatch for CONSTANT_InvokeDynamic_info");
   303                         return;
   301                     }
   304                     }
   302                 }
   305                 }
   303             }
   306             }
   304             if (bsmIdx == -1) {
   307             if (bsmIdx == -1) {
   305                 throw new Error("Missing invokedynamic in generated code");
   308                 fail("Missing invokedynamic in generated code");
       
   309                 return;
   306             }
   310             }
   307 
   311 
   308             BootstrapMethods_attribute bsm_attr =
   312             BootstrapMethods_attribute bsm_attr =
   309                     (BootstrapMethods_attribute)cf
   313                     (BootstrapMethods_attribute)cf
   310                     .getAttribute(Attribute.BootstrapMethods);
   314                     .getAttribute(Attribute.BootstrapMethods);
   311             if (bsm_attr.bootstrap_method_specifiers.length != 1) {
   315             if (bsm_attr.bootstrap_method_specifiers.length != 1) {
   312                 throw new Error("Bad number of method specifiers " +
   316                 fail("Bad number of method specifiers " +
   313                         "in BootstrapMethods attribute");
   317                         "in BootstrapMethods attribute");
       
   318                 return;
   314             }
   319             }
   315             BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
   320             BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec =
   316                     bsm_attr.bootstrap_method_specifiers[0];
   321                     bsm_attr.bootstrap_method_specifiers[0];
   317 
   322 
   318             if (bsm_spec.bootstrap_arguments.length != arity.arity) {
   323             if (bsm_spec.bootstrap_arguments.length != arity.arity) {
   319                 throw new Error("Bad number of static invokedynamic args " +
   324                 fail("Bad number of static invokedynamic args " +
   320                         "in BootstrapMethod attribute");
   325                         "in BootstrapMethod attribute");
   321             }
   326                 return;
   322 
   327             }
   323             int count = 0;
   328 
   324             for (StaticArgumentKind sak : saks) {
   329             for (int i = 0 ; i < arity.arity ; i++) {
   325                 if (!sak.check(cf.constant_pool
   330                 if (!saks[i].check(cf.constant_pool
   326                         .get(bsm_spec.bootstrap_arguments[count]))) {
   331                         .get(bsm_spec.bootstrap_arguments[i]))) {
   327                     throw new Error("Bad static argument value " + sak);
   332                     fail("Bad static argument value " + saks[i]);
       
   333                     return;
   328                 }
   334                 }
   329                 count++;
       
   330             }
   335             }
   331 
   336 
   332             CONSTANT_MethodHandle_info bsm_handle =
   337             CONSTANT_MethodHandle_info bsm_handle =
   333                     (CONSTANT_MethodHandle_info)cf.constant_pool
   338                     (CONSTANT_MethodHandle_info)cf.constant_pool
   334                     .get(bsm_spec.bootstrap_method_ref);
   339                     .get(bsm_spec.bootstrap_method_ref);
   335 
   340 
   336             if (bsm_handle.reference_kind != RefKind.REF_invokeStatic) {
   341             if (bsm_handle.reference_kind != RefKind.REF_invokeStatic) {
   337                 throw new Error("Bad kind on boostrap method handle");
   342                 fail("Bad kind on boostrap method handle");
       
   343                 return;
   338             }
   344             }
   339 
   345 
   340             CONSTANT_Methodref_info bsm_ref =
   346             CONSTANT_Methodref_info bsm_ref =
   341                     (CONSTANT_Methodref_info)cf.constant_pool
   347                     (CONSTANT_Methodref_info)cf.constant_pool
   342                     .get(bsm_handle.reference_index);
   348                     .get(bsm_handle.reference_index);
   343 
   349 
   344             if (!bsm_ref.getClassInfo().getName().equals("Bootstrap")) {
   350             if (!bsm_ref.getClassInfo().getName().equals("Bootstrap")) {
   345                 throw new Error("Bad owner of boostrap method");
   351                 fail("Bad owner of boostrap method");
       
   352                 return;
   346             }
   353             }
   347 
   354 
   348             if (!bsm_ref.getNameAndTypeInfo().getName().equals("bsm")) {
   355             if (!bsm_ref.getNameAndTypeInfo().getName().equals("bsm")) {
   349                 throw new Error("Bad boostrap method name");
   356                 fail("Bad boostrap method name");
       
   357                 return;
   350             }
   358             }
   351 
   359 
   352             if (!bsm_ref.getNameAndTypeInfo()
   360             if (!bsm_ref.getNameAndTypeInfo()
   353                     .getType().equals(asBSMSignatureString())) {
   361                     .getType().equals(asBSMSignatureString())) {
   354                 throw new Error("Bad boostrap method type" +
   362                 fail("Bad boostrap method type" +
   355                         bsm_ref.getNameAndTypeInfo().getType() + " " +
   363                         bsm_ref.getNameAndTypeInfo().getType() + " " +
   356                         asBSMSignatureString());
   364                         asBSMSignatureString());
       
   365                 return;
   357             }
   366             }
   358 
   367 
   359             LineNumberTable_attribute lnt =
   368             LineNumberTable_attribute lnt =
   360                     (LineNumberTable_attribute)ea.attributes.get(Attribute.LineNumberTable);
   369                     (LineNumberTable_attribute)ea.attributes.get(Attribute.LineNumberTable);
   361 
   370 
   362             if (lnt == null) {
   371             if (lnt == null) {
   363                 throw new Error("No LineNumberTable attribute");
   372                 fail("No LineNumberTable attribute");
       
   373                 return;
   364             }
   374             }
   365             if (lnt.line_number_table_length != 3) {
   375             if (lnt.line_number_table_length != 3) {
   366                 throw new Error("Wrong number of entries in LineNumberTable");
   376                 fail("Wrong number of entries in LineNumberTable");
       
   377                 return;
   367             }
   378             }
   368         } catch (Exception e) {
   379         } catch (Exception e) {
   369             e.printStackTrace();
   380             e.printStackTrace();
   370             throw new Error("error reading " + compiledTest +": " + e);
   381             fail("error reading classfile: " + res.compilationInfo());
       
   382             return;
   371         }
   383         }
   372     }
   384     }
   373 
   385 
   374     String asBSMSignatureString() {
   386     String asBSMSignatureString() {
   375         StringBuilder buf = new StringBuilder();
   387         StringBuilder buf = new StringBuilder();
   376         buf.append("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;");
   388         buf.append("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;");
   377         for (StaticArgumentKind sak : saks) {
   389         for (int i = 0 ; i < arity.arity ; i++) {
   378             buf.append(sak.bytecodeTypeStr);
   390             buf.append(saks[i].bytecodeTypeStr);
   379         }
   391         }
   380         buf.append(")Ljava/lang/invoke/CallSite;");
   392         buf.append(")Ljava/lang/invoke/CallSite;");
   381         return buf.toString();
   393         return buf.toString();
   382     }
       
   383 
       
   384     class JavaSource extends SimpleJavaFileObject {
       
   385 
       
   386         static final String source_template = "import java.lang.invoke.*;\n" +
       
   387                 "class Bootstrap {\n" +
       
   388                 "   public static CallSite bsm(MethodHandles.Lookup lookup, " +
       
   389                 "String name, MethodType methodType #SARGS) {\n" +
       
   390                 "       return null;\n" +
       
   391                 "   }\n" +
       
   392                 "}\n" +
       
   393                 "class Test#ID {\n" +
       
   394                 "   void m() { }\n" +
       
   395                 "   void test() {\n" +
       
   396                 "      Object o = this; // marker statement \n" +
       
   397                 "      m();\n" +
       
   398                 "   }\n" +
       
   399                 "}";
       
   400 
       
   401         String source;
       
   402 
       
   403         JavaSource(int id) {
       
   404             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
       
   405             source = source_template.replace("#SARGS", asSignatureString())
       
   406                     .replace("#ID", String.valueOf(id));
       
   407         }
       
   408 
       
   409         @Override
       
   410         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       
   411             return source;
       
   412         }
       
   413 
       
   414         String asSignatureString() {
       
   415             int count = 0;
       
   416             StringBuilder buf = new StringBuilder();
       
   417             for (StaticArgumentKind sak : saks) {
       
   418                 buf.append(",");
       
   419                 buf.append(sak.sourceTypeStr);
       
   420                 buf.append(' ');
       
   421                 buf.append(String.format("x%d", count++));
       
   422             }
       
   423             return buf.toString();
       
   424         }
       
   425     }
   394     }
   426 
   395 
   427     class Indifier extends TreeScanner<Void, Void> implements TaskListener {
   396     class Indifier extends TreeScanner<Void, Void> implements TaskListener {
   428 
   397 
   429         MethodSymbol bsm;
   398         MethodSymbol bsm;
   473                 bsm = ((JCMethodDecl)node).sym;
   442                 bsm = ((JCMethodDecl)node).sym;
   474             }
   443             }
   475             return null;
   444             return null;
   476         }
   445         }
   477     }
   446     }
   478 
       
   479     static class DiagChecker
       
   480         implements javax.tools.DiagnosticListener<JavaFileObject> {
       
   481 
       
   482         boolean diagFound;
       
   483         ArrayList<String> diags = new ArrayList<>();
       
   484 
       
   485         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
       
   486             diags.add(diagnostic.getMessage(Locale.getDefault()));
       
   487             diagFound = true;
       
   488         }
       
   489 
       
   490         String printDiags() {
       
   491             StringBuilder buf = new StringBuilder();
       
   492             for (String s : diags) {
       
   493                 buf.append(s);
       
   494                 buf.append("\n");
       
   495             }
       
   496             return buf.toString();
       
   497         }
       
   498     }
       
   499 
       
   500 }
   447 }