Skip to content

Commit 544e317

Browse files
author
Srikanth Adayapalam
committed
8059632: Method reference compilation uses incorrect qualifying type
Reviewed-by: mcimadamore
1 parent 651e547 commit 544e317

File tree

6 files changed

+329
-51
lines changed

6 files changed

+329
-51
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ protected Types(Context context) {
119119
messages = JavacMessages.instance(context);
120120
diags = JCDiagnostic.Factory.instance(context);
121121
noWarnings = new Warner(null);
122+
qualifiedSymbolCache = new HashMap<>();
122123
}
123124
// </editor-fold>
124125

@@ -3617,6 +3618,56 @@ public int rank(Type t) {
36173618
}
36183619
// </editor-fold>
36193620

3621+
/** Cache the symbol to reflect the qualifying type.
3622+
* key: corresponding type
3623+
* value: qualified symbol
3624+
*/
3625+
private Map<Type, Symbol> qualifiedSymbolCache;
3626+
3627+
public void clearQualifiedSymbolCache() {
3628+
qualifiedSymbolCache.clear();
3629+
}
3630+
3631+
/** Construct a symbol to reflect the qualifying type that should
3632+
* appear in the byte code as per JLS 13.1.
3633+
*
3634+
* For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except
3635+
* for those cases where we need to work around VM bugs).
3636+
*
3637+
* For {@literal target <= 1.1}: If qualified variable or method is defined in a
3638+
* non-accessible class, clone it with the qualifier class as owner.
3639+
*
3640+
* @param sym The accessed symbol
3641+
* @param site The qualifier's type.
3642+
*/
3643+
public Symbol binaryQualifier(Symbol sym, Type site) {
3644+
3645+
if (site.hasTag(ARRAY)) {
3646+
if (sym == syms.lengthVar ||
3647+
sym.owner != syms.arrayClass)
3648+
return sym;
3649+
// array clone can be qualified by the array type in later targets
3650+
Symbol qualifier;
3651+
if ((qualifier = qualifiedSymbolCache.get(site)) == null) {
3652+
qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol);
3653+
qualifiedSymbolCache.put(site, qualifier);
3654+
}
3655+
return sym.clone(qualifier);
3656+
}
3657+
3658+
if (sym.owner == site.tsym ||
3659+
(sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
3660+
return sym;
3661+
}
3662+
3663+
// leave alone methods inherited from Object
3664+
// JLS 13.1.
3665+
if (sym.owner == syms.objectType.tsym)
3666+
return sym;
3667+
3668+
return sym.clone(site.tsym);
3669+
}
3670+
36203671
/**
36213672
* Helper method for generating a string representation of a given type
36223673
* accordingly to a given locale

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ public void visitReference(JCMemberReference tree) {
518518
throw new InternalError("Should not have an invalid kind");
519519
}
520520

521+
if (init != null) {
522+
refSym = (MethodSymbol) types.binaryQualifier(refSym, init.type);
523+
}
521524
List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
522525

523526

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ protected Gen(Context context) {
130130
// ignore cldc because we cannot have both stackmap formats
131131
this.stackMap = StackMapFormat.JSR202;
132132
annotate = Annotate.instance(context);
133-
qualifiedSymbolCache = new HashMap<>();
134133
}
135134

136135
/** Switches
@@ -172,12 +171,6 @@ protected Gen(Context context) {
172171
List<LocalItem> stackBeforeSwitchExpression;
173172
LocalItem switchResult;
174173

175-
/** Cache the symbol to reflect the qualifying type.
176-
* key: corresponding type
177-
* value: qualified symbol
178-
*/
179-
Map<Type, Symbol> qualifiedSymbolCache;
180-
181174
/** Generate code to load an integer constant.
182175
* @param n The integer to be loaded.
183176
*/
@@ -221,46 +214,6 @@ void emitMinusOne(int tc) {
221214
}
222215
}
223216

224-
/** Construct a symbol to reflect the qualifying type that should
225-
* appear in the byte code as per JLS 13.1.
226-
*
227-
* For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except
228-
* for those cases where we need to work around VM bugs).
229-
*
230-
* For {@literal target <= 1.1}: If qualified variable or method is defined in a
231-
* non-accessible class, clone it with the qualifier class as owner.
232-
*
233-
* @param sym The accessed symbol
234-
* @param site The qualifier's type.
235-
*/
236-
Symbol binaryQualifier(Symbol sym, Type site) {
237-
238-
if (site.hasTag(ARRAY)) {
239-
if (sym == syms.lengthVar ||
240-
sym.owner != syms.arrayClass)
241-
return sym;
242-
// array clone can be qualified by the array type in later targets
243-
Symbol qualifier;
244-
if ((qualifier = qualifiedSymbolCache.get(site)) == null) {
245-
qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol);
246-
qualifiedSymbolCache.put(site, qualifier);
247-
}
248-
return sym.clone(qualifier);
249-
}
250-
251-
if (sym.owner == site.tsym ||
252-
(sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
253-
return sym;
254-
}
255-
256-
// leave alone methods inherited from Object
257-
// JLS 13.1.
258-
if (sym.owner == syms.objectType.tsym)
259-
return sym;
260-
261-
return sym.clone(site.tsym);
262-
}
263-
264217
/** Insert a reference to given type in the constant pool,
265218
* checking for an array with too many dimensions;
266219
* return the reference's index.
@@ -2280,11 +2233,11 @@ public void visitIdent(JCIdent tree) {
22802233
result = items.makeLocalItem((VarSymbol)sym);
22812234
} else if ((sym.flags() & STATIC) != 0) {
22822235
if (!isAccessSuper(env.enclMethod))
2283-
sym = binaryQualifier(sym, env.enclClass.type);
2236+
sym = types.binaryQualifier(sym, env.enclClass.type);
22842237
result = items.makeStaticItem(sym);
22852238
} else {
22862239
items.makeThisItem().load();
2287-
sym = binaryQualifier(sym, env.enclClass.type);
2240+
sym = types.binaryQualifier(sym, env.enclClass.type);
22882241
result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
22892242
}
22902243
}
@@ -2337,7 +2290,7 @@ public void visitSelect(JCFieldAccess tree) {
23372290
result = items.makeDynamicItem(sym);
23382291
return;
23392292
} else {
2340-
sym = binaryQualifier(sym, tree.selected.type);
2293+
sym = types.binaryQualifier(sym, tree.selected.type);
23412294
}
23422295
if ((sym.flags() & STATIC) != 0) {
23432296
if (!selectSuper && (ssym == null || ssym.kind != TYP))
@@ -2443,7 +2396,7 @@ public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
24432396
toplevel = null;
24442397
endPosTable = null;
24452398
nerrs = 0;
2446-
qualifiedSymbolCache.clear();
2399+
types.clearQualifiedSymbolCache();
24472400
}
24482401
}
24492402

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2022, 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+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8059632
27+
* @summary Method reference compilation uses incorrect qualifying type
28+
* @compile MethodRefQualifyingTypeTest.java
29+
* @compile MethodSupplierImpl.java
30+
* @run main MethodRefQualifyingTypeTest
31+
*/
32+
33+
import java.lang.reflect.Method;
34+
35+
public class MethodRefQualifyingTypeTest {
36+
37+
static abstract class MethodSupplierImpl implements MethodSupplier {
38+
class Inner {
39+
MethodRefQualifyingTypeTest.MyFunctionalInterface createMethodReference() {
40+
return MethodSupplierImpl.this::<Integer>m;
41+
}
42+
}
43+
}
44+
45+
interface MethodSupplier {
46+
int m(int a);
47+
}
48+
49+
interface MyFunctionalInterface {
50+
int invokeMethodReference(int a);
51+
}
52+
53+
static class MethodInvoker {
54+
public static void invoke() {
55+
MyFunctionalInterface instance = null;
56+
MethodSupplierImpl ms = new MethodSupplierImpl() {
57+
public int m(int a) {
58+
return a;
59+
}
60+
};
61+
instance = ms.new Inner().createMethodReference();
62+
instance.invokeMethodReference(1);
63+
}
64+
}
65+
66+
public static void main(String argv[]) throws Exception {
67+
68+
// Without the fix for JDK-8059632, the invocation below will fail with
69+
// java.lang.invoke.LambdaConversionException: Invalid receiver type class MethodRefQualifyingTypeTest$MethodSupplierImpl; not a subtype of implementation type interface MethodRefQualifyingTypeTest$MethodSupplier
70+
71+
// With the fix for JDK-8059632, the invocation would succeed since the bootstrap section
72+
// would refer to the type of the receiver and not the type of the declaring interface,
73+
// per JLS 13.1 (see "the qualifying type of the method invocation").
74+
75+
Class.forName("MethodRefQualifyingTypeTest$MethodInvoker").getMethod("invoke").invoke(null);
76+
}
77+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2022, 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+
*/
23+
24+
class MethodRefQualifyingTypeTest$MethodSupplierImpl {
25+
int m(int a) { return a; }
26+
}

0 commit comments

Comments
 (0)