OpenJDK / valhalla / valhalla
changeset 59596:c5a6786c46c0 nestmates
Merge
author | mchung |
---|---|
date | Mon, 30 Mar 2020 17:57:23 -0700 |
parents | c964a558522d a41d4b835eab |
children | d30b62c68646 |
files | |
diffstat | 27 files changed, 515 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java Mon Mar 30 17:57:23 2020 -0700 @@ -68,12 +68,14 @@ import com.sun.tools.javac.main.Arguments; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.model.JavacElements; +import com.sun.tools.javac.platform.PlatformDescription; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.LetExpr; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Options; /** * A pool of reusable JavacTasks. When a task is no valid anymore, it is returned to the pool, @@ -252,6 +254,7 @@ drop(JavacTask.class); drop(JavacTrees.class); drop(JavacElements.class); + drop(PlatformDescription.class); if (ht.get(Log.logKey) instanceof ReusableLog) { //log already inited - not first round @@ -266,6 +269,7 @@ Annotate.instance(this).newRound(); CompileStates.instance(this).clear(); MultiTaskListener.instance(this).clear(); + Options.instance(this).clear(); //find if any of the roots have redefined java.* classes Symtab syms = Symtab.instance(this);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java Mon Mar 30 17:57:23 2020 -0700 @@ -1231,10 +1231,14 @@ public static class RootPackageSymbol extends PackageSymbol { public final MissingInfoHandler missingInfoHandler; + public final boolean allowPrivateInvokeVirtual; - public RootPackageSymbol(Name name, Symbol owner, MissingInfoHandler missingInfoHandler) { + public RootPackageSymbol(Name name, Symbol owner, + MissingInfoHandler missingInfoHandler, + boolean allowPrivateInvokeVirtual) { super(name, owner); this.missingInfoHandler = missingInfoHandler; + this.allowPrivateInvokeVirtual = allowPrivateInvokeVirtual; } } @@ -2311,6 +2315,8 @@ } else { if (refSym.isStatic()) { return ClassFile.REF_invokeStatic; + } else if ((refSym.flags() & PRIVATE) != 0 && !allowPrivateInvokeVirtual()) { + return ClassFile.REF_invokeSpecial; } else if (refSym.enclClass().isInterface()) { return ClassFile.REF_invokeInterface; } else { @@ -2320,6 +2326,13 @@ } } + private boolean allowPrivateInvokeVirtual() { + Symbol rootPack = this; + while (rootPack != null && !(rootPack instanceof RootPackageSymbol)) { + rootPack = rootPack.owner; + } + return rootPack != null && ((RootPackageSymbol) rootPack).allowPrivateInvokeVirtual; + } @Override public int poolTag() { return ClassFile.CONSTANT_MethodHandle;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java Mon Mar 30 17:57:23 2020 -0700 @@ -54,6 +54,7 @@ import com.sun.tools.javac.code.Type.UnknownType; import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Modules; +import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Convert; @@ -389,7 +390,10 @@ MissingInfoHandler missingInfoHandler = MissingInfoHandler.instance(context); - rootPackage = new RootPackageSymbol(names.empty, null, missingInfoHandler); + Target target = Target.instance(context); + rootPackage = new RootPackageSymbol(names.empty, null, + missingInfoHandler, + target.runtimeUseNestAccess()); // create the basic builtin symbols unnamedModule = new ModuleSymbol(names.empty, null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Mar 30 17:57:23 2020 -0700 @@ -36,7 +36,6 @@ import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree.TreeTranslator; import com.sun.tools.javac.code.Attribute; -import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; @@ -127,6 +126,9 @@ /** deduplicate lambda implementation methods */ private final boolean deduplicateLambdas; + /** lambda proxy is a dynamic nestmate */ + private final boolean nestmateLambdas; + /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ public static final int FLAG_SERIALIZABLE = 1 << 0; @@ -168,6 +170,7 @@ || options.isSet(Option.G_CUSTOM, "vars"); verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication"); deduplicateLambdas = options.getBoolean("deduplicateLambdas", true); + nestmateLambdas = Target.instance(context).runtimeUseNestAccess(); } // </editor-fold> @@ -2253,6 +2256,20 @@ return tree.ownerAccessible; } + /** + * This method should be called only when target release <= 14 + * where LambdaMetaFactory does not spin nestmate classes. + * + * This method should be removed when --release 14 is not supported. + */ + boolean isPrivateInOtherClass() { + assert !nestmateLambdas; + return (tree.sym.flags() & PRIVATE) != 0 && + !types.isSameType( + types.erasure(tree.sym.enclClass().asType()), + types.erasure(owner.enclClass().asType())); + } + boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage() { return ((tree.sym.flags() & PROTECTED) != 0 && tree.sym.packge() != owner.packge()); @@ -2293,6 +2310,7 @@ isSuper || needsVarArgsConversion() || isArrayOp() || + (!nestmateLambdas && isPrivateInOtherClass()) || isProtectedInSuperClassOfEnclosingClassInOtherPackage() || !receiverAccessible() || (tree.getMode() == ReferenceMode.NEW &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java Mon Mar 30 17:57:23 2020 -0700 @@ -169,6 +169,14 @@ return compareTo(JDK1_11) >= 0; } + /** language runtime uses nest-based access. + * e.g. lambda and string concat spin dynamic proxy class as a nestmate + * of the target class + */ + public boolean runtimeUseNestAccess() { + return compareTo(JDK1_15) >= 0; + } + /** Does the target VM support virtual private invocations? */ public boolean hasVirtualPrivateInvoke() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java Mon Mar 30 19:25:43 2020 -0400 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java Mon Mar 30 17:57:23 2020 -0700 @@ -181,4 +181,9 @@ for (Runnable r: listeners) r.run(); } + + public void clear() { + values.clear(); + listeners = List.nil(); + } }
--- a/test/hotspot/jtreg/runtime/HiddenClasses/CastToParentTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/CastToParentTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @summary Test that a hidden class can be cast to its parent. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main CastToParentTest */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/GCHiddenClass.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/GCHiddenClass.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @summary Test that hidden classes get garbage collected. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main GCHiddenClass */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/HiddenClassStack.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/HiddenClassStack.java Mon Mar 30 17:57:23 2020 -0700 @@ -26,8 +26,7 @@ * @summary Test that stack tracing isn't broken if an exception is thrown * in a hidden class. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main HiddenClassStack */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/HiddenGetModule.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/HiddenGetModule.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @summary Test that a hidden class has the same module as its lookup class. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @compile pkg/HasNamedModule.java * @run main/othervm HiddenGetModule */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/InstantiateHiddenClass.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @summary Test issues with instantiating hidden classes. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main InstantiateHiddenClass */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/NestedHidden.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/NestedHidden.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @summary Creates a hidden class inside of a hidden class. * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main p.NestedHidden */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/StressHiddenClasses.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/StressHiddenClasses.java Mon Mar 30 17:57:23 2020 -0700 @@ -26,8 +26,7 @@ * @summary Stress defining hidden classes. * @requires !vm.graal.enabled * @library /test/lib - * @modules java.compiler - * java.management + * @modules jdk.compiler * @run main/othervm StressHiddenClasses */
--- a/test/hotspot/jtreg/runtime/HiddenClasses/TestHiddenClassUnloading.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/runtime/HiddenClasses/TestHiddenClassUnloading.java Mon Mar 30 17:57:23 2020 -0700 @@ -24,6 +24,7 @@ /* * @test * @summary Test unloading of hidden classes. + * @modules java.management * @library /test/lib / * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderHierarchyTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/serviceability/dcmd/vm/ClassLoaderHierarchyTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -27,8 +27,7 @@ * @summary Test of diagnostic command VM.classloaders * @library /test/lib * @modules java.base/jdk.internal.misc - * java.compiler - * java.management + * jdk.compiler * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassLoaderHierarchyTest */
--- a/test/hotspot/jtreg/serviceability/jvmti/HiddenClass/P/Q/HiddenClassSigTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/hotspot/jtreg/serviceability/jvmti/HiddenClass/P/Q/HiddenClassSigTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -25,8 +25,7 @@ * @test * @library /test/lib * @modules java.base/jdk.internal.misc - * java.compiler - * java.management + * jdk.compiler * @compile HiddenClassSigTest.java * @run main/othervm/native -agentlib:HiddenClassSigTest P.Q.HiddenClassSigTest */
--- a/test/jdk/java/lang/instrument/HiddenClass/HiddenClassAgent.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/instrument/HiddenClass/HiddenClassAgent.java Mon Mar 30 17:57:23 2020 -0700 @@ -24,7 +24,8 @@ /** * @test * @library /test/lib - * @modules java.compiler + * @modules java.instrument + * jdk.compiler * @build jdk.test.lib.compiler.CompilerUtils * jdk.test.lib.Utils * * @run shell ../MakeJAR3.sh HiddenClassAgent 'Can-Retransform-Classes: true'
--- a/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/invoke/defineHiddenClass/BasicTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -23,12 +23,12 @@ /* * @test + * @modules jdk.compiler * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils * BasicTest * @run testng/othervm BasicTest - * @run testng/othervm -Xcomp BasicTest */ import java.io.File;
--- a/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/invoke/defineHiddenClass/LambdaNestedInnerTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ -23,10 +23,9 @@ /* * @test - * @build LambdaNestedInnerTest - * @run testng/othervm p.LambdaNestedInnerTest * @summary define a lambda proxy class whose target class has an invalid * nest membership + * @run testng/othervm p.LambdaNestedInnerTest */ package p;
--- a/test/jdk/java/lang/invoke/defineHiddenClass/SelfReferenceDescriptor.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/invoke/defineHiddenClass/SelfReferenceDescriptor.java Mon Mar 30 17:57:23 2020 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ -23,6 +23,7 @@ /* * @test + * @modules jdk.compiler * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils
--- a/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/invoke/defineHiddenClass/UnloadingTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -24,6 +24,7 @@ /* * @test * @summary verify if the hidden class is unloaded when the class loader is GC'ed + * @modules jdk.compiler * @library /test/lib/ * @build jdk.test.lib.util.ForceGC * @run testng/othervm UnloadingTest @@ -106,7 +107,7 @@ * They can be unloaded even the loader is strongly reachable */ @Test - public void hiddenClassNest2() throws Exception { + public void hiddenClassNest() throws Exception { TestLoader loader = new TestLoader(); Class<?> helper = Class.forName("LookupHelper", true, loader); Method m = helper.getMethod("getLookup"); @@ -115,11 +116,13 @@ // keep a strong reference to the nest member class Class<?> member = unloaders[1].weakRef.get(); + assertTrue(member != null); // nest host and member will not be unloaded assertFalse(unloaders[0].tryUnload()); assertFalse(unloaders[1].tryUnload()); // clear the reference to the nest member + Reference.reachabilityFence(member); member = null; // nest host and member will be unloaded
--- a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/InheritedProtectedMethod.java Mon Mar 30 17:57:23 2020 -0700 @@ -24,6 +24,7 @@ /* * @test * @bug 8239384 + * @modules jdk.compiler * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.compiler.CompilerUtils
--- a/test/jdk/jdk/jfr/event/runtime/TestClassLoaderStatsEvent.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/jdk/jdk/jfr/event/runtime/TestClassLoaderStatsEvent.java Mon Mar 30 17:57:23 2020 -0700 @@ -48,7 +48,8 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @modules java.base/jdk.internal.misc - * java.compiler + * jdk.compiler + * jdk.jfr * @build jdk.jfr.event.runtime.TestClasses * @run main/othervm jdk.jfr.event.runtime.TestClassLoaderStatsEvent */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTargetRelease14Test.java Mon Mar 30 17:57:23 2020 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +/* + * @test + * @bug 8238358 + * @summary Checking ACC_SYNTHETIC flag is generated for bridge method + * generated for lambda expressions and method references when + * compiling with --release 14. + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.classfile + * @library /tools/lib /tools/javac/lib ../lib + * @build toolbox.ToolBox InMemoryFileManager TestResult TestBase + * @build SyntheticTestDriver ExpectedClass ExpectedClasses + * @compile --source 14 -target 14 -XDdeduplicateLambdas=false BridgeMethodsForLambdaTargetRelease14Test.java + * @run main SyntheticTestDriver BridgeMethodsForLambdaTargetRelease14Test + */ + +import java.util.Comparator; +import java.util.stream.IntStream; + +/** + * Synthetic members: + * 1. inner class for Inner1. + * 2. method for () -> {} in Inner1 + * 3. method for () -> {} in Inner2 + * 4. method references to private methods. + * 5. method for super::function() + * 6. method references to private static methods. + * 7. access method for private method function(). + * 8. access method for private static method staticFunction(). + * 9. method reference to vararg method. + * 10. method reference to array's method. + * 11. constructors for Inner1 and Inner2. + */ +@ExpectedClass(className = "BridgeMethodsForLambdaTargetRelease14Test", + expectedMethods = {"<init>()", "<clinit>()", "function(java.lang.Integer[])"}, + expectedNumberOfSyntheticMethods = 6) +@ExpectedClass(className = "BridgeMethodsForLambdaTargetRelease14Test$Inner1", + expectedMethods = {"<init>(BridgeMethodsForLambdaTargetRelease14Test)", "function()", "run()"}, + expectedFields = "lambda1", + expectedNumberOfSyntheticMethods = 1, + expectedNumberOfSyntheticFields = 1) +@ExpectedClass(className = "BridgeMethodsForLambdaTargetRelease14Test$Inner2", + expectedMethods = {"<init>()", "staticFunction()"}, + expectedFields = "lambda1", + expectedNumberOfSyntheticMethods = 1) +@ExpectedClass(className = "BridgeMethodsForLambdaTargetRelease14Test$Inner3", + expectedMethods = {"<init>(BridgeMethodsForLambdaTargetRelease14Test)", "function()"}, + expectedNumberOfSyntheticFields = 1) +@ExpectedClass(className = "BridgeMethodsForLambdaTargetRelease14Test$Inner4", + expectedMethods = {"<init>(BridgeMethodsForLambdaTargetRelease14Test)", "function()"}, + expectedNumberOfSyntheticMethods = 1, + expectedNumberOfSyntheticFields = 1) +public class BridgeMethodsForLambdaTargetRelease14Test { + + private class Inner1 implements Runnable { + private Inner1() { + } + private Runnable lambda1 = () -> { + }; + private void function() { + } + @Override + public void run() { + } + } + + private static class Inner2 { + private Runnable lambda1 = () -> { + }; + private static void staticFunction() { + } + } + + private class Inner3 { + public void function() { + } + } + + private class Inner4 extends Inner3 { + @Override + public void function() { + Runnable r = super::function; + } + } + + private static int function(Integer...vararg) { + return 0; + } + + { + Inner1 inner = new Inner1(); + Runnable l1 = inner::function; + Runnable l2 = Inner1::new; + inner.lambda1 = inner::function; + Comparator<Integer> c = BridgeMethodsForLambdaTargetRelease14Test::function; + IntStream.of(2).mapToObj(int[]::new); + } + + static { + Inner2 inner = new Inner2(); + Runnable l1 = Inner2::staticFunction; + } +}
--- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/BridgeMethodsForLambdaTest.java Mon Mar 30 17:57:23 2020 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8044537 8200301 + * @bug 8044537 8200301 8238358 * @summary Checking ACC_SYNTHETIC flag is generated for bridge method * generated for lambda expressions and method references. * @modules jdk.compiler/com.sun.tools.javac.api
--- a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java Mon Mar 30 19:25:43 2020 -0400 +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java Mon Mar 30 17:57:23 2020 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, 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 @@ -23,8 +23,9 @@ /* * @test - * @bug 8009649 8129962 - * @summary Lambda back-end should generate invokespecial for method handles referring to private instance methods + * @bug 8009649 8129962 8238358 + * @summary Lambda back-end should generate invokevirtual for method handles referring to + * private instance methods as lambda proxy is a nestmate of the target clsas * @library /tools/javac/lib * @modules jdk.jdeps/com.sun.tools.classfile * jdk.compiler/com.sun.tools.javac.api
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java Mon Mar 30 17:57:23 2020 -0700 @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +/* + * @test + * @bug 8238358 + * @summary Lambda back-end should generate invokespecial for method handles referring to + * private instance methods when compiling with --release 14 + * @library /tools/javac/lib + * @modules jdk.jdeps/com.sun.tools.classfile + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.util + * @build combo.ComboTestHelper + * @run main TestLambdaBytecodeTargetRelease14 + */ + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.BootstrapMethods_attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Instruction; +import com.sun.tools.classfile.Method; + +import java.io.IOException; +import java.io.InputStream; + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask.Result; +import combo.ComboTestHelper; + +import javax.tools.JavaFileObject; + +public class TestLambdaBytecodeTargetRelease14 extends ComboInstance<TestLambdaBytecodeTargetRelease14> { + + static final int MF_ARITY = 3; + static final String MH_SIG = "()V"; + + enum ClassKind implements ComboParameter { + CLASS("class"), + INTERFACE("interface"); + + String classStr; + + ClassKind(String classStr) { + this.classStr = classStr; + } + + @Override + public String expand(String optParameter) { + return classStr; + } + } + + enum AccessKind implements ComboParameter { + PUBLIC("public"), + PRIVATE("private"); + + String accessStr; + + AccessKind(String accessStr) { + this.accessStr = accessStr; + } + + @Override + public String expand(String optParameter) { + return accessStr; + } + } + + enum StaticKind implements ComboParameter { + STATIC("static"), + INSTANCE(""); + + String staticStr; + + StaticKind(String staticStr) { + this.staticStr = staticStr; + } + + @Override + public String expand(String optParameter) { + return staticStr; + } + } + + enum DefaultKind implements ComboParameter { + DEFAULT("default"), + NO_DEFAULT(""); + + String defaultStr; + + DefaultKind(String defaultStr) { + this.defaultStr = defaultStr; + } + + @Override + public String expand(String optParameter) { + return defaultStr; + } + } + + static class MethodKind { + ClassKind ck; + AccessKind ak; + StaticKind sk; + DefaultKind dk; + + MethodKind(ClassKind ck, AccessKind ak, StaticKind sk, DefaultKind dk) { + this.ck = ck; + this.ak = ak; + this.sk = sk; + this.dk = dk; + } + + boolean inInterface() { + return ck == ClassKind.INTERFACE; + } + + boolean isPrivate() { + return ak == AccessKind.PRIVATE; + } + + boolean isStatic() { + return sk == StaticKind.STATIC; + } + + boolean isDefault() { + return dk == DefaultKind.DEFAULT; + } + + boolean isOK() { + if (isDefault() && (!inInterface() || isStatic())) { + return false; + } else if (inInterface() && + ((!isStatic() && !isDefault()) || isPrivate())) { + return false; + } else { + return true; + } + } + } + + public static void main(String... args) throws Exception { + new ComboTestHelper<TestLambdaBytecodeTargetRelease14>() + .withDimension("CLASSKIND", (x, ck) -> x.ck = ck, ClassKind.values()) + .withArrayDimension("ACCESS", (x, acc, idx) -> x.accessKinds[idx] = acc, 2, AccessKind.values()) + .withArrayDimension("STATIC", (x, sk, idx) -> x.staticKinds[idx] = sk, 2, StaticKind.values()) + .withArrayDimension("DEFAULT", (x, dk, idx) -> x.defaultKinds[idx] = dk, 2, DefaultKind.values()) + .run(TestLambdaBytecodeTargetRelease14::new, TestLambdaBytecodeTargetRelease14::init); + } + + ClassKind ck; + AccessKind[] accessKinds = new AccessKind[2]; + StaticKind[] staticKinds = new StaticKind[2]; + DefaultKind[] defaultKinds = new DefaultKind[2]; + MethodKind mk1, mk2; + + void init() { + mk1 = new MethodKind(ck, accessKinds[0], staticKinds[0], defaultKinds[0]); + mk2 = new MethodKind(ck, accessKinds[1], staticKinds[1], defaultKinds[1]); + } + + String source_template = + "#{CLASSKIND} Test {\n" + + " #{ACCESS[0]} #{STATIC[0]} #{DEFAULT[0]} void test() { Runnable r = ()->{ target(); }; }\n" + + " #{ACCESS[1]} #{STATIC[1]} #{DEFAULT[1]} void target() { }\n" + + "}\n"; + + @Override + public void doWork() throws IOException { + newCompilationTask() + .withSourceFromTemplate(source_template) + .withOption("--release").withOption("14") + .generate(this::verifyBytecode); + } + + void verifyBytecode(Result<Iterable<? extends JavaFileObject>> res) { + if (res.hasErrors()) { + boolean errorExpected = !mk1.isOK() || !mk2.isOK(); + errorExpected |= mk1.isStatic() && !mk2.isStatic(); + + if (!errorExpected) { + fail("Diags found when compiling instance; " + res.compilationInfo()); + } + return; + } + try (InputStream is = res.get().iterator().next().openInputStream()) { + ClassFile cf = ClassFile.read(is); + Method testMethod = null; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals("test")) { + testMethod = m; + break; + } + } + if (testMethod == null) { + fail("Test method not found"); + return; + } + Code_attribute ea = + (Code_attribute)testMethod.attributes.get(Attribute.Code); + if (testMethod == null) { + fail("Code attribute for test() method not found"); + return; + } + + int bsmIdx = -1; + + for (Instruction i : ea.getInstructions()) { + if (i.getMnemonic().equals("invokedynamic")) { + CONSTANT_InvokeDynamic_info indyInfo = + (CONSTANT_InvokeDynamic_info)cf + .constant_pool.get(i.getShort(1)); + bsmIdx = indyInfo.bootstrap_method_attr_index; + if (!indyInfo.getNameAndTypeInfo().getType().equals(makeIndyType())) { + fail("type mismatch for CONSTANT_InvokeDynamic_info " + + res.compilationInfo() + "\n" + indyInfo.getNameAndTypeInfo().getType() + + "\n" + makeIndyType()); + return; + } + } + } + if (bsmIdx == -1) { + fail("Missing invokedynamic in generated code"); + return; + } + + BootstrapMethods_attribute bsm_attr = + (BootstrapMethods_attribute)cf + .getAttribute(Attribute.BootstrapMethods); + if (bsm_attr.bootstrap_method_specifiers.length != 1) { + fail("Bad number of method specifiers " + + "in BootstrapMethods attribute"); + return; + } + BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec = + bsm_attr.bootstrap_method_specifiers[0]; + + if (bsm_spec.bootstrap_arguments.length != MF_ARITY) { + fail("Bad number of static invokedynamic args " + + "in BootstrapMethod attribute"); + return; + } + + CONSTANT_MethodHandle_info mh = + (CONSTANT_MethodHandle_info)cf.constant_pool.get(bsm_spec.bootstrap_arguments[1]); + + boolean kindOK; + switch (mh.reference_kind) { + case REF_invokeStatic: kindOK = mk2.isStatic(); break; + case REF_invokeSpecial: kindOK = !mk2.isStatic(); break; + case REF_invokeInterface: kindOK = mk2.inInterface(); break; + default: + kindOK = false; + } + + if (!kindOK) { + fail("Bad invoke kind in implementation method handle"); + return; + } + + if (!mh.getCPRefInfo().getNameAndTypeInfo().getType().toString().equals(MH_SIG)) { + fail("Type mismatch in implementation method handle"); + return; + } + } catch (Exception e) { + e.printStackTrace(); + fail("error reading " + res.compilationInfo() + ": " + e); + } + } + + String makeIndyType() { + StringBuilder buf = new StringBuilder(); + buf.append("("); + if (!mk2.isStatic()) { + buf.append("LTest;"); + } + buf.append(")Ljava/lang/Runnable;"); + return buf.toString(); + } +}