8268192: LambdaMetafactory with invokespecial causes VerificationError

Reviewed-by: psandoz, mchung
This commit is contained in:
Dan Smith 2021-06-09 23:57:41 +00:00
parent b41f3f8ed5
commit 58ba48b7b8
3 changed files with 15 additions and 20 deletions

View File

@ -154,14 +154,10 @@ import static sun.invoke.util.Wrapper.isWrapperType;
this.implClass = implInfo.getDeclaringClass();
this.implIsInstanceMethod = true;
// Classes compiled prior to dynamic nestmate support invokes a private instance
// method with REF_invokeSpecial.
//
// invokespecial should only be used to invoke private nestmate constructors.
// The lambda proxy class will be defined as a nestmate of targetClass.
// If the method to be invoked is an instance method of targetClass, then
// convert to use invokevirtual or invokeinterface.
if (targetClass == implClass && !implInfo.getName().equals("<init>")) {
// Classes compiled prior to dynamic nestmate support invoke a private instance
// method with REF_invokeSpecial. Newer classes use REF_invokeVirtual or
// REF_invokeInterface, and we can use that instruction in the lambda class.
if (targetClass == implClass) {
this.implKind = implClass.isInterface() ? REF_invokeInterface : REF_invokeVirtual;
} else {
this.implKind = REF_invokeSpecial;

View File

@ -180,8 +180,15 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = factoryType.changeReturnType(Void.TYPE);
lambdaClassName = lambdaClassName(targetClass);
useImplMethodHandle = !Modifier.isPublic(implInfo.getModifiers()) &&
!VerifyAccess.isSamePackage(implClass, implInfo.getDeclaringClass());
// If the target class invokes a protected method inherited from a
// superclass in a different package, or does 'invokespecial', the
// lambda class has no access to the resolved method. Instead, we need
// to pass the live implementation method handle to the proxy class
// to invoke directly. (javac prefers to avoid this situation by
// generating bridges in the target class)
useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers()) &&
!VerifyAccess.isSamePackage(implClass, implInfo.getDeclaringClass())) ||
implKind == H_INVOKESPECIAL;
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
int parameterCount = factoryType.parameterCount();
if (parameterCount > 0) {
@ -394,13 +401,6 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
// this class is linked at the indy callsite; so define a hidden nestmate
Lookup lookup;
if (useImplMethodHandle) {
// If the target class invokes a method reference this::m which is
// resolved to a protected method inherited from a superclass in a different
// package, the target class does not have a bridge and this method reference
// has been changed from public to protected after the target class was compiled.
// This lambda proxy class has no access to the resolved method.
// So this workaround by passing the live implementation method handle
// to the proxy class to invoke directly.
lookup = caller.defineHiddenClassWithClassData(classBytes, implementation, !disableEagerInitialization,
NESTMATE, STRONG);
} else {

View File

@ -153,9 +153,8 @@ public class MetafactoryArgValidationTest {
amfSucceed(C.lookup, "m", toI, arr(cToVoid, C.invokeVirtualMH(), cToVoid, flagSer));
mfSucceed(C.lookup, "m", toI, toVoid, C.invokeStaticMH(), toVoid);
amfSucceed(C.lookup, "m", toI, arr(toVoid, C.invokeStaticMH(), toVoid, flagSer));
// 8268192: these fail with a VerifyError, need to fix
//mfSucceed(C.lookup, "m", toI, cToString, C.invokeSpecialMH(), cToString);
//amfSucceed(C.lookup, "m", toI, arr(cToString, C.invokeSpecialMH(), cToString, flagSer));
mfSucceed(C.lookup, "m", toI, cToString, C.invokeSpecialMH(), cToString);
amfSucceed(C.lookup, "m", toI, arr(cToString, C.invokeSpecialMH(), cToString, flagSer));
mfSucceed(C.lookup, "m", toI, toC, C.newInvokeSpecialMH(), toC);
amfSucceed(C.lookup, "m", toI, arr(toC, C.newInvokeSpecialMH(), toC, flagSer));
mfSucceed(C.lookup, "m", toI, cToVoid, C.invokeInterfaceMH(), cToVoid);