diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index 6feb7afd77337..933f582a2e650 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -119,7 +119,6 @@ protected Types(Context context) { messages = JavacMessages.instance(context); diags = JCDiagnostic.Factory.instance(context); noWarnings = new Warner(null); - qualifiedSymbolCache = new HashMap<>(); } // </editor-fold> @@ -3618,56 +3617,6 @@ public int rank(Type t) { } // </editor-fold> - /** Cache the symbol to reflect the qualifying type. - * key: corresponding type - * value: qualified symbol - */ - private Map<Type, Symbol> qualifiedSymbolCache; - - public void clearQualifiedSymbolCache() { - qualifiedSymbolCache.clear(); - } - - /** Construct a symbol to reflect the qualifying type that should - * appear in the byte code as per JLS 13.1. - * - * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except - * for those cases where we need to work around VM bugs). - * - * For {@literal target <= 1.1}: If qualified variable or method is defined in a - * non-accessible class, clone it with the qualifier class as owner. - * - * @param sym The accessed symbol - * @param site The qualifier's type. - */ - public Symbol binaryQualifier(Symbol sym, Type site) { - - if (site.hasTag(ARRAY)) { - if (sym == syms.lengthVar || - sym.owner != syms.arrayClass) - return sym; - // array clone can be qualified by the array type in later targets - Symbol qualifier; - if ((qualifier = qualifiedSymbolCache.get(site)) == null) { - qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol); - qualifiedSymbolCache.put(site, qualifier); - } - return sym.clone(qualifier); - } - - if (sym.owner == site.tsym || - (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { - return sym; - } - - // leave alone methods inherited from Object - // JLS 13.1. - if (sym.owner == syms.objectType.tsym) - return sym; - - return sym.clone(site.tsym); - } - /** * Helper method for generating a string representation of a given type * accordingly to a given locale diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 7bd195701cf76..90ec561474920 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -518,9 +518,6 @@ public void visitReference(JCMemberReference tree) { throw new InternalError("Should not have an invalid kind"); } - if (init != null) { - refSym = (MethodSymbol) types.binaryQualifier(refSym, init.type); - } List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index ee2974d94786a..6f58c8b4f818c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -131,6 +131,7 @@ protected Gen(Context context) { // ignore cldc because we cannot have both stackmap formats this.stackMap = StackMapFormat.JSR202; annotate = Annotate.instance(context); + qualifiedSymbolCache = new HashMap<>(); } /** Switches @@ -174,6 +175,12 @@ protected Gen(Context context) { Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of(); ListBuffer<int[]> patternMatchingInvocationRanges; + /** Cache the symbol to reflect the qualifying type. + * key: corresponding type + * value: qualified symbol + */ + Map<Type, Symbol> qualifiedSymbolCache; + /** Generate code to load an integer constant. * @param n The integer to be loaded. */ @@ -217,6 +224,46 @@ void emitMinusOne(int tc) { } } + /** Construct a symbol to reflect the qualifying type that should + * appear in the byte code as per JLS 13.1. + * + * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except + * for those cases where we need to work around VM bugs). + * + * For {@literal target <= 1.1}: If qualified variable or method is defined in a + * non-accessible class, clone it with the qualifier class as owner. + * + * @param sym The accessed symbol + * @param site The qualifier's type. + */ + Symbol binaryQualifier(Symbol sym, Type site) { + + if (site.hasTag(ARRAY)) { + if (sym == syms.lengthVar || + sym.owner != syms.arrayClass) + return sym; + // array clone can be qualified by the array type in later targets + Symbol qualifier; + if ((qualifier = qualifiedSymbolCache.get(site)) == null) { + qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol); + qualifiedSymbolCache.put(site, qualifier); + } + return sym.clone(qualifier); + } + + if (sym.owner == site.tsym || + (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { + return sym; + } + + // leave alone methods inherited from Object + // JLS 13.1. + if (sym.owner == syms.objectType.tsym) + return sym; + + return sym.clone(site.tsym); + } + /** Insert a reference to given type in the constant pool, * checking for an array with too many dimensions; * return the reference's index. @@ -2280,11 +2327,11 @@ public void visitIdent(JCIdent tree) { result = items.makeLocalItem((VarSymbol)sym); } else if ((sym.flags() & STATIC) != 0) { if (!isAccessSuper(env.enclMethod)) - sym = types.binaryQualifier(sym, env.enclClass.type); + sym = binaryQualifier(sym, env.enclClass.type); result = items.makeStaticItem(sym); } else { items.makeThisItem().load(); - sym = types.binaryQualifier(sym, env.enclClass.type); + sym = binaryQualifier(sym, env.enclClass.type); result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym)); } } @@ -2337,7 +2384,7 @@ public void visitSelect(JCFieldAccess tree) { result = items.makeDynamicItem(sym); return; } else { - sym = types.binaryQualifier(sym, tree.selected.type); + sym = binaryQualifier(sym, tree.selected.type); } if ((sym.flags() & STATIC) != 0) { if (!selectSuper && (ssym == null || ssym.kind != TYP)) @@ -2443,7 +2490,7 @@ public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) { toplevel = null; endPosTable = null; nerrs = 0; - types.clearQualifiedSymbolCache(); + qualifiedSymbolCache.clear(); } } diff --git a/test/langtools/tools/javac/lambda/methodReference/8059632/MethodRefQualifyingTypeTest.java b/test/langtools/tools/javac/lambda/methodReference/8059632/MethodRefQualifyingTypeTest.java deleted file mode 100644 index f5d0c2f8be04d..0000000000000 --- a/test/langtools/tools/javac/lambda/methodReference/8059632/MethodRefQualifyingTypeTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2022, 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 8059632 - * @summary Method reference compilation uses incorrect qualifying type - * @compile MethodRefQualifyingTypeTest.java - * @compile MethodSupplierImpl.java - * @run main MethodRefQualifyingTypeTest - */ - -import java.lang.reflect.Method; - -public class MethodRefQualifyingTypeTest { - - static abstract class MethodSupplierImpl implements MethodSupplier { - class Inner { - MethodRefQualifyingTypeTest.MyFunctionalInterface createMethodReference() { - return MethodSupplierImpl.this::<Integer>m; - } - } - } - - interface MethodSupplier { - int m(int a); - } - - interface MyFunctionalInterface { - int invokeMethodReference(int a); - } - - static class MethodInvoker { - public static void invoke() { - MyFunctionalInterface instance = null; - MethodSupplierImpl ms = new MethodSupplierImpl() { - public int m(int a) { - return a; - } - }; - instance = ms.new Inner().createMethodReference(); - instance.invokeMethodReference(1); - } - } - - public static void main(String argv[]) throws Exception { - - // Without the fix for JDK-8059632, the invocation below will fail with - // java.lang.invoke.LambdaConversionException: Invalid receiver type class MethodRefQualifyingTypeTest$MethodSupplierImpl; not a subtype of implementation type interface MethodRefQualifyingTypeTest$MethodSupplier - - // With the fix for JDK-8059632, the invocation would succeed since the bootstrap section - // would refer to the type of the receiver and not the type of the declaring interface, - // per JLS 13.1 (see "the qualifying type of the method invocation"). - - Class.forName("MethodRefQualifyingTypeTest$MethodInvoker").getMethod("invoke").invoke(null); - } -} diff --git a/test/langtools/tools/javac/lambda/methodReference/8059632/MethodSupplierImpl.java b/test/langtools/tools/javac/lambda/methodReference/8059632/MethodSupplierImpl.java deleted file mode 100644 index e94ea579daec9..0000000000000 --- a/test/langtools/tools/javac/lambda/methodReference/8059632/MethodSupplierImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2022, 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. - */ - -class MethodRefQualifyingTypeTest$MethodSupplierImpl { - int m(int a) { return a; } -} diff --git a/test/langtools/tools/javac/lambda/methodReference/8059632/TestBootstrapInvocation.java b/test/langtools/tools/javac/lambda/methodReference/8059632/TestBootstrapInvocation.java deleted file mode 100644 index e970811ef7a83..0000000000000 --- a/test/langtools/tools/javac/lambda/methodReference/8059632/TestBootstrapInvocation.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2022, 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 8059632 - * @summary Method reference compilation uses incorrect qualifying type - * @library /tools/javac/lib - * @modules jdk.jdeps/com.sun.tools.classfile - * jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.jvm - */ - -import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Locale; - -import javax.tools.Diagnostic; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; - -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.BootstrapMethods_attribute; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.javac.api.JavacTaskImpl; -import static com.sun.tools.javac.jvm.ClassFile.*; -import com.sun.tools.classfile.ConstantPool.*; - -public class TestBootstrapInvocation { - - public static void main(String... args) throws Exception { - JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); - new TestBootstrapInvocation().run(comp); - } - - DiagChecker dc; - - TestBootstrapInvocation() { - dc = new DiagChecker(); - } - - public void run(JavaCompiler comp) { - JavaSource source = new JavaSource(); - JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc, - Arrays.asList("-g"), null, Arrays.asList(source)); - try { - ct.generate(); - } catch (Throwable t) { - t.printStackTrace(); - throw new AssertionError( - String.format("Error thrown when compiling following code\n%s", - source.source)); - } - if (dc.diagFound) { - throw new AssertionError( - String.format("Diags found when compiling following code\n%s\n\n%s", - source.source, dc.printDiags())); - } - verifyBytecode(); - } - - void verifyBytecode() { - File compiledTest = new File("Test.class"); - try { - ClassFile cf = ClassFile.read(compiledTest); - BootstrapMethods_attribute bsm_attr = - (BootstrapMethods_attribute)cf - .getAttribute(Attribute.BootstrapMethods); - int length = bsm_attr.bootstrap_method_specifiers.length; - if (length != 1) { - throw new Error("Bad number of method specifiers " + - "in BootstrapMethods attribute: " + length); - } - BootstrapMethods_attribute.BootstrapMethodSpecifier bsm_spec = - bsm_attr.bootstrap_method_specifiers[0]; - - if (bsm_spec.bootstrap_arguments.length != 3) { - throw new Error("Bad number of static invokedynamic args " + - "in BootstrapMethod attribute"); - } - CONSTANT_MethodHandle_info mh = - (CONSTANT_MethodHandle_info)cf.constant_pool.get(bsm_spec.bootstrap_arguments[1]); - - if (mh.reference_kind != RefKind.REF_invokeVirtual) { - throw new Error("Bad invoke kind in implementation method handle: " + mh.reference_kind); - } - if (!mh.getCPRefInfo().getClassName().equals("Test$C")) { - throw new Error("Unexpected class name: " + mh.getCPRefInfo().getClassName()); - } - if (!mh.getCPRefInfo().getNameAndTypeInfo().getName().equals("m")) { - throw new Error("Unexpected method referenced in method handle in bootstrap section: " + - mh.getCPRefInfo().getNameAndTypeInfo().getName()); - } - } catch (Exception e) { - e.printStackTrace(); - throw new Error("error reading " + compiledTest +": " + e); - } - } - - class JavaSource extends SimpleJavaFileObject { - - static final String source = - - """ - class Test { - interface I { void m(); } - abstract class C implements I {} - public void test(C arg) { - Runnable r = arg::m; - } - } - """; - - JavaSource() { - super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - static class DiagChecker - implements javax.tools.DiagnosticListener<JavaFileObject> { - - boolean diagFound; - ArrayList<String> diags = new ArrayList<>(); - - public void report(Diagnostic<? extends JavaFileObject> diagnostic) { - diags.add(diagnostic.getMessage(Locale.getDefault())); - diagFound = true; - } - - String printDiags() { - StringBuilder buf = new StringBuilder(); - for (String s : diags) { - buf.append(s); - buf.append("\n"); - } - return buf.toString(); - } - } -}