changeset 16672:95050afa6898

8174226: Test failures after JDK-8033076 Summary: Reverting JDK-8033076 for now Reviewed-by: darcy
author dlsmith
date Wed, 08 Feb 2017 17:28:15 -0700
parents 56a5cee26bbb
children cad3932c20ec
files src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
diffstat 2 files changed, 51 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Wed Feb 08 14:23:59 2017 -0700
+++ b/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/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Wed Feb 08 14:23:59 2017 -0700
+++ b/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));
             }
         }