changeset 7050:ca8730a515e5

roll forward missing changesets changeset: 6888:054174178911 changeset: 6849:bde4cb561b72
author mduigou
date Thu, 10 Jan 2013 16:54:38 -0800
parents cf94c0668cf1
children ed7fd1baaab2
files src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java src/share/classes/java/lang/invoke/SerializedLambda.java test-ng/build.xml
diffstat 3 files changed, 66 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Thu Jan 10 19:19:26 2013 -0500
+++ b/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Thu Jan 10 16:54:38 2013 -0800
@@ -24,7 +24,6 @@
  */
 package java.lang.invoke;
 
-import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -305,11 +304,10 @@
      */
     class MethodAnalyzer {
         private final Method[] methods = samBase.getMethods();
-        private final List<Method> methodsFound = new ArrayList<>(methods.length);
 
         private Method samMethod = null;
         private final List<Method> methodsToBridge = new ArrayList<>(methods.length);
-        private boolean defaultMethodFound = false;
+        private boolean conflictFoundBetweenDefaultAndBridge = false;
 
         MethodAnalyzer() {
             String samMethodName = samInfo.getName();
@@ -317,30 +315,34 @@
             int samParamLength = samParamTypes.length;
             Class<?> samReturnType = samMethodType.returnType();
             Class<?> objectClass = Object.class;
+            List<Method> defaultMethods = new ArrayList<>(methods.length);
 
             for (Method m : methods) {
                 if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
                     Class<?>[] mParamTypes = m.getParameterTypes();
                     if (mParamTypes.length == samParamLength) {
+                        // Method matches name and parameter length -- and is not Object
                         if (Modifier.isAbstract(m.getModifiers())) {
-                            // Exclude methods with duplicate signatures
-                            if (methodUnique(m)) {
+                            // Method is abstract
                                 if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) {
                                     // Exact match, this is the SAM method signature
                                     samMethod = m;
-                                } else {
+                            } else if (! hasMatchingBridgeSignature(m)) {
+                                // Record bridges, exclude methods with duplicate signatures
                                     methodsToBridge.add(m);
                                 }
+                        } else {
+                            // Record default methods for conflict testing
+                            defaultMethods.add(m);
                             }
-                        } else {
-                            // This is a default method, flag for special processing
-                            defaultMethodFound = true;
-                            // Ignore future matching abstracts.
-                            // Note, due to reabstraction, this is really a punt, hence pass-off to VM
-                            methodUnique(m);
                         }
                     }
                 }
+            for (Method dm : defaultMethods) {
+                if (hasMatchingBridgeSignature(dm)) {
+                    conflictFoundBetweenDefaultAndBridge = true;
+                    break;
+                }
             }
         }
 
@@ -352,27 +354,26 @@
             return methodsToBridge;
         }
 
-        boolean wasDefaultMethodFound() {
-            return defaultMethodFound;
+        boolean conflictFoundBetweenDefaultAndBridge() {
+            return conflictFoundBetweenDefaultAndBridge;
         }
 
         /**
-         * Search the list of previously found methods to determine if there is a method with the same signature
-         * (return and parameter types) as the specified method. If it wasn't found before, add to the found list.
+         * Search the list of previously found bridge methods to determine if there is a method with the same signature
+         * (return and parameter types) as the specified method.
          *
          * @param m The method to match
-         * @return False if the method was found, True otherwise
+         * @return True if the method was found, False otherwise
          */
-        private boolean methodUnique(Method m) {
+        private boolean hasMatchingBridgeSignature(Method m) {
             Class<?>[] ptypes = m.getParameterTypes();
             Class<?> rtype = m.getReturnType();
-            for (Method md : methodsFound) {
+            for (Method md : methodsToBridge) {
                 if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
+                    return true;
+                }
+            }
                     return false;
                 }
             }
-            methodsFound.add(m);
-            return true;
-        }
-    }
 }
--- a/src/share/classes/java/lang/invoke/SerializedLambda.java	Thu Jan 10 19:19:26 2013 -0500
+++ b/src/share/classes/java/lang/invoke/SerializedLambda.java	Thu Jan 10 16:54:38 2013 -0800
@@ -25,6 +25,10 @@
 package java.lang.invoke;
 
 import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Objects;
 
 /**
@@ -87,6 +91,19 @@
         this.implMethodSignature = implMethodSignature;
         this.instantiatedMethodType = instantiatedMethodType;
         this.capturedArgs = Objects.requireNonNull(capturedArgs).clone();
+        /***
+        System.err.printf("====================\n");
+        System.err.printf("capturingClass: '%s'\n", capturingClass);
+        System.err.printf("functionalInterfaceMethodKind: %d\n", functionalInterfaceMethodKind);
+        System.err.printf("functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
+        System.err.printf("functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
+        System.err.printf("functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
+        System.err.printf("implMethodKind: %d\n", implMethodKind);
+        System.err.printf("implClass: '%s'\n", implClass);
+        System.err.printf("implMethodName: '%s'\n", implMethodName);
+        System.err.printf("implMethodSignature: '%s'\n", implMethodSignature);
+        System.err.printf("instantiatedMethodType: '%s'\n", instantiatedMethodType);
+        ***/
     }
 
     public String getCapturingClass() {
@@ -133,15 +150,30 @@
         return capturedArgs;
     }
 
-    private Object readResolve() {
-        // @@@
-        //  - load capturingClass
-        //  - reflectively find $deserialize$ on it
-        //  - pass 'this' (or unpacked fields of this) to $deserialize$
-        //    - needs some privileged magic, since it is private
-        //    - most promising is Method.setAccessible(true), in a doPrivilege block
-        //  - return whatever that returns
-        return null; // remove me
+    private Object readResolve() throws ReflectiveOperationException {
+        try {
+            Method deserialize = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
+                @Override
+                public Method run() throws Exception {
+                    Class<?> clazz = Class.forName(capturingClass.replace('/', '.'), true,
+                                                   Thread.currentThread().getContextClassLoader());
+                    Method m = clazz.getDeclaredMethod("$deserialize$", SerializedLambda.class);
+                    m.setAccessible(true);
+                    return m;
+                }
+            });
+
+            return deserialize.invoke(null, this);
+        }
+        catch (PrivilegedActionException e) {
+            Exception cause = e.getException();
+            if (cause instanceof ReflectiveOperationException)
+                throw (ReflectiveOperationException) cause;
+            else if (cause instanceof RuntimeException)
+                throw (RuntimeException) cause;
+            else
+                throw new RuntimeException("Exception in SerializedLambda.readResolve", e);
+        }
     }
 
 /*
--- a/test-ng/build.xml	Thu Jan 10 19:19:26 2013 -0500
+++ b/test-ng/build.xml	Thu Jan 10 16:54:38 2013 -0800
@@ -36,7 +36,7 @@
     <property name="lambda.metafactory" value="" />
     <property name="generated.dir" value="gen-separate"/>
 
-    <property name="lib.testng.jar" value="${lib.dir}/testng-6.7.jar"/>
+    <property name="lib.testng.jar" value="${lib.dir}/testng.jar"/>
     <property name="lib.tools.jar" value="${java.home}/../lib/tools.jar"/>
 
     <path id="test.class.path">