Skip to content

Commit 58ba48b

Browse files
author
Dan Smith
committed
8268192: LambdaMetafactory with invokespecial causes VerificationError
Reviewed-by: psandoz, mchung
1 parent b41f3f8 commit 58ba48b

File tree

3 files changed

+15
-20
lines changed

3 files changed

+15
-20
lines changed

src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,10 @@
154154
this.implClass = implInfo.getDeclaringClass();
155155
this.implIsInstanceMethod = true;
156156

157-
// Classes compiled prior to dynamic nestmate support invokes a private instance
158-
// method with REF_invokeSpecial.
159-
//
160-
// invokespecial should only be used to invoke private nestmate constructors.
161-
// The lambda proxy class will be defined as a nestmate of targetClass.
162-
// If the method to be invoked is an instance method of targetClass, then
163-
// convert to use invokevirtual or invokeinterface.
164-
if (targetClass == implClass && !implInfo.getName().equals("<init>")) {
157+
// Classes compiled prior to dynamic nestmate support invoke a private instance
158+
// method with REF_invokeSpecial. Newer classes use REF_invokeVirtual or
159+
// REF_invokeInterface, and we can use that instruction in the lambda class.
160+
if (targetClass == implClass) {
165161
this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
166162
} else {
167163
this.implKind = REF_invokeSpecial;

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,15 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
180180
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
181181
constructorType = factoryType.changeReturnType(Void.TYPE);
182182
lambdaClassName = lambdaClassName(targetClass);
183-
useImplMethodHandle = !Modifier.isPublic(implInfo.getModifiers()) &&
184-
!VerifyAccess.isSamePackage(implClass, implInfo.getDeclaringClass());
183+
// If the target class invokes a protected method inherited from a
184+
// superclass in a different package, or does 'invokespecial', the
185+
// lambda class has no access to the resolved method. Instead, we need
186+
// to pass the live implementation method handle to the proxy class
187+
// to invoke directly. (javac prefers to avoid this situation by
188+
// generating bridges in the target class)
189+
useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers()) &&
190+
!VerifyAccess.isSamePackage(implClass, implInfo.getDeclaringClass())) ||
191+
implKind == H_INVOKESPECIAL;
185192
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
186193
int parameterCount = factoryType.parameterCount();
187194
if (parameterCount > 0) {
@@ -394,13 +401,6 @@ public Void run() {
394401
// this class is linked at the indy callsite; so define a hidden nestmate
395402
Lookup lookup;
396403
if (useImplMethodHandle) {
397-
// If the target class invokes a method reference this::m which is
398-
// resolved to a protected method inherited from a superclass in a different
399-
// package, the target class does not have a bridge and this method reference
400-
// has been changed from public to protected after the target class was compiled.
401-
// This lambda proxy class has no access to the resolved method.
402-
// So this workaround by passing the live implementation method handle
403-
// to the proxy class to invoke directly.
404404
lookup = caller.defineHiddenClassWithClassData(classBytes, implementation, !disableEagerInitialization,
405405
NESTMATE, STRONG);
406406
} else {

test/jdk/java/lang/invoke/lambda/MetafactoryArgValidationTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,8 @@ public static void testLCE() {
153153
amfSucceed(C.lookup, "m", toI, arr(cToVoid, C.invokeVirtualMH(), cToVoid, flagSer));
154154
mfSucceed(C.lookup, "m", toI, toVoid, C.invokeStaticMH(), toVoid);
155155
amfSucceed(C.lookup, "m", toI, arr(toVoid, C.invokeStaticMH(), toVoid, flagSer));
156-
// 8268192: these fail with a VerifyError, need to fix
157-
//mfSucceed(C.lookup, "m", toI, cToString, C.invokeSpecialMH(), cToString);
158-
//amfSucceed(C.lookup, "m", toI, arr(cToString, C.invokeSpecialMH(), cToString, flagSer));
156+
mfSucceed(C.lookup, "m", toI, cToString, C.invokeSpecialMH(), cToString);
157+
amfSucceed(C.lookup, "m", toI, arr(cToString, C.invokeSpecialMH(), cToString, flagSer));
159158
mfSucceed(C.lookup, "m", toI, toC, C.newInvokeSpecialMH(), toC);
160159
amfSucceed(C.lookup, "m", toI, arr(toC, C.newInvokeSpecialMH(), toC, flagSer));
161160
mfSucceed(C.lookup, "m", toI, cToVoid, C.invokeInterfaceMH(), cToVoid);

0 commit comments

Comments
 (0)