8174226: Test failures after JDK-8033076
Summary: Reverting JDK-8033076 for now
Reviewed-by: darcy
--- a/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Feb 08 14:23:59 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Feb 08 17:28:15 2017 -0700
@@ -56,11 +56,11 @@
final String samMethodName; // Name of the SAM method "foo"
final MethodType samMethodType; // Type of the SAM method "(Object)Object"
final MethodHandle implMethod; // Raw method handle for the implementation method
- final MethodType implMethodType; // Type of the implMethod MethodHandle "(CC,int)String"
final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
final int implKind; // Invocation kind for implementation "5"=invokevirtual
final boolean implIsInstanceMethod; // Is the implementation an instance method "true"
- final Class<?> implClass; // Class for referencing the implementation method "class CC"
+ final Class<?> implDefiningClass; // Type defining the implementation "class CC"
+ final MethodType implMethodType; // Type of the implementation method "(int)String"
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
final boolean isSerializable; // Should the returned instance be serializable
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
@@ -128,15 +128,14 @@
this.samMethodType = samMethodType;
this.implMethod = implMethod;
- this.implMethodType = implMethod.type();
this.implInfo = caller.revealDirect(implMethod);
this.implKind = implInfo.getReferenceKind();
this.implIsInstanceMethod =
implKind == MethodHandleInfo.REF_invokeVirtual ||
implKind == MethodHandleInfo.REF_invokeSpecial ||
implKind == MethodHandleInfo.REF_invokeInterface;
- // JDK-8172817: statics should also use referenced class here, but API doesn't support it for now
- this.implClass = implIsInstanceMethod ? implMethodType.parameterType(0) : implInfo.getDeclaringClass();
+ this.implDefiningClass = implInfo.getDeclaringClass();
+ this.implMethodType = implInfo.getMethodType();
this.instantiatedMethodType = instantiatedMethodType;
this.isSerializable = isSerializable;
this.markerInterfaces = markerInterfaces;
@@ -197,10 +196,11 @@
// Check arity: optional-receiver + captured + SAM == impl
final int implArity = implMethodType.parameterCount();
+ final int receiverArity = implIsInstanceMethod ? 1 : 0;
final int capturedArity = invokedType.parameterCount();
final int samArity = samMethodType.parameterCount();
final int instantiatedArity = instantiatedMethodType.parameterCount();
- if (implArity != capturedArity + samArity) {
+ if (implArity + receiverArity != capturedArity + samArity) {
throw new LambdaConversionException(
String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface method parameters, %d implementation parameters",
implIsInstanceMethod ? "instance" : "static", implInfo,
@@ -221,8 +221,8 @@
}
// If instance: first captured arg (receiver) must be subtype of class where impl method is defined
- final int capturedStart; // index of first non-receiver capture parameter in implMethodType
- final int samStart; // index of first non-receiver sam parameter in implMethodType
+ final int capturedStart;
+ final int samStart;
if (implIsInstanceMethod) {
final Class<?> receiverClass;
@@ -235,36 +235,45 @@
} else {
// receiver is a captured variable
capturedStart = 1;
- samStart = capturedArity;
+ samStart = 0;
receiverClass = invokedType.parameterType(0);
}
// check receiver type
- if (!implClass.isAssignableFrom(receiverClass)) {
+ if (!implDefiningClass.isAssignableFrom(receiverClass)) {
throw new LambdaConversionException(
String.format("Invalid receiver type %s; not a subtype of implementation type %s",
- receiverClass, implClass));
+ receiverClass, implDefiningClass));
+ }
+
+ Class<?> implReceiverClass = implMethod.type().parameterType(0);
+ if (implReceiverClass != implDefiningClass && !implReceiverClass.isAssignableFrom(receiverClass)) {
+ throw new LambdaConversionException(
+ String.format("Invalid receiver type %s; not a subtype of implementation receiver type %s",
+ receiverClass, implReceiverClass));
}
} else {
// no receiver
capturedStart = 0;
- samStart = capturedArity;
+ samStart = 0;
}
// Check for exact match on non-receiver captured arguments
- for (int i=capturedStart; i<capturedArity; i++) {
+ final int implFromCaptured = capturedArity - capturedStart;
+ for (int i=0; i<implFromCaptured; i++) {
Class<?> implParamType = implMethodType.parameterType(i);
- Class<?> capturedParamType = invokedType.parameterType(i);
+ Class<?> capturedParamType = invokedType.parameterType(i + capturedStart);
if (!capturedParamType.equals(implParamType)) {
throw new LambdaConversionException(
String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s",
i, capturedParamType, implParamType));
}
}
- // Check for adaptation match on non-receiver SAM arguments
- for (int i=samStart; i<implArity; i++) {
+ // Check for adaptation match on SAM arguments
+ final int samOffset = samStart - implFromCaptured;
+ for (int i=implFromCaptured; i<implArity; i++) {
Class<?> implParamType = implMethodType.parameterType(i);
- Class<?> instantiatedParamType = instantiatedMethodType.parameterType(i - capturedArity);
+ Class<?> instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset);
if (!isAdaptableTo(instantiatedParamType, implParamType, true)) {
throw new LambdaConversionException(
String.format("Type mismatch for lambda argument %d: %s is not convertible to %s",
@@ -274,7 +283,10 @@
// Adaptation match: return type
Class<?> expectedType = instantiatedMethodType.returnType();
- Class<?> actualReturnType = implMethodType.returnType();
+ Class<?> actualReturnType =
+ (implKind == MethodHandleInfo.REF_newInvokeSpecial)
+ ? implDefiningClass
+ : implMethodType.returnType();
if (!isAdaptableToAsReturn(actualReturnType, expectedType)) {
throw new LambdaConversionException(
String.format("Type mismatch for lambda return: %s is not convertible to %s",
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Feb 08 14:23:59 2017 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Feb 08 17:28:15 2017 -0700
@@ -96,6 +96,7 @@
private final String implMethodClassName; // Name of type containing implementation "CC"
private final String implMethodName; // Name of implementation method "impl"
private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;"
+ private final Class<?> implMethodReturnClass; // class for implementation method return type "Ljava/lang/String;"
private final MethodType constructorType; // Generated class constructor type "(CC)void"
private final ClassWriter cw; // ASM class writer
private final String[] argNames; // Generated names for the constructor arguments
@@ -152,9 +153,12 @@
super(caller, invokedType, samMethodName, samMethodType,
implMethod, instantiatedMethodType,
isSerializable, markerInterfaces, additionalBridges);
- implMethodClassName = implClass.getName().replace('.', '/');
+ implMethodClassName = implDefiningClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
- implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
+ implMethodDesc = implMethodType.toMethodDescriptorString();
+ implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
+ ? implDefiningClass
+ : implMethodType.returnType();
constructorType = invokedType.changeReturnType(Void.TYPE);
lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
@@ -463,14 +467,13 @@
// Invoke the method we want to forward to
visitMethodInsn(invocationOpcode(), implMethodClassName,
implMethodName, implMethodDesc,
- implClass.isInterface());
+ implDefiningClass.isInterface());
// Convert the return value (if any) and return it
// Note: if adapting from non-void to void, the 'return'
// instruction will pop the unneeded result
- Class<?> implReturnClass = implMethodType.returnType();
Class<?> samReturnClass = methodType.returnType();
- convertType(implReturnClass, samReturnClass, samReturnClass);
+ convertType(implMethodReturnClass, samReturnClass, samReturnClass);
visitInsn(getReturnOpcode(samReturnClass));
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
visitMaxs(-1, -1);
@@ -479,13 +482,23 @@
private void convertArgumentTypes(MethodType samType) {
int lvIndex = 0;
+ boolean samIncludesReceiver = implIsInstanceMethod &&
+ invokedType.parameterCount() == 0;
+ int samReceiverLength = samIncludesReceiver ? 1 : 0;
+ if (samIncludesReceiver) {
+ // push receiver
+ Class<?> rcvrType = samType.parameterType(0);
+ visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
+ lvIndex += getParameterSize(rcvrType);
+ convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
+ }
int samParametersLength = samType.parameterCount();
- int captureArity = invokedType.parameterCount();
- for (int i = 0; i < samParametersLength; i++) {
+ int argOffset = implMethodType.parameterCount() - samParametersLength;
+ for (int i = samReceiverLength; i < samParametersLength; i++) {
Class<?> argType = samType.parameterType(i);
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
lvIndex += getParameterSize(argType);
- convertType(argType, implMethodType.parameterType(captureArity + i), instantiatedMethodType.parameterType(i));
+ convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
}
}