changeset 5893:a3394c993428

Restructure lambda metafactories to share data and implementation between validation, and the two implementations. Also, misc clean-up and documentation
author Robert Field <Robert.Field@oracle.com>
date Sun, 02 Sep 2012 22:05:39 -0700
parents c2506fb31e41
children 2da52ed16327
files src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java src/share/classes/java/lang/invoke/InnerClassGenerator.java src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java src/share/classes/java/lang/invoke/LambdaMetafactory.java src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java
diffstat 5 files changed, 633 insertions(+), 579 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Sun Sep 02 22:05:39 2012 -0700
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Abstract implementation of a meta-factory which provides parameter unrolling
+ * and input validation.
+ *
+ * @author Robert Field
+ */
+abstract class AbstractValidatingLambdaMetafactory {
+
+    final Class<?> targetClass;
+    final MethodType invokedType;
+    final Class<?> samBase;
+    final boolean isSerializable;
+    final MethodHandleInfo samInfo;
+    final Class<?> samClass;
+    final MethodType samMethodType;
+    final MethodHandleInfo implInfo;
+    final boolean implIsInstanceMethod;
+    final MethodType implMethodType;
+    final Class<?> implDefiningClass;
+    final MethodType functionDescType;
+
+    AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
+                                       MethodType invokedType,
+                                       MethodHandle samMethod,
+                                       MethodHandle implMethod,
+                                       MethodType functionDescType)
+            throws ReflectiveOperationException {
+        this.targetClass = caller.lookupClass();
+        this.invokedType = invokedType;
+
+        this.samBase = invokedType.returnType();
+        this.isSerializable = Serializable.class.isAssignableFrom(samBase);
+        
+        this.samInfo = new MethodHandleInfo(samMethod);
+        this.samClass = samInfo.getDeclaringClass();
+        this.samMethodType  = samInfo.getMethodType();
+        
+        this.implInfo = new MethodHandleInfo(implMethod);
+        this.implIsInstanceMethod = 
+                implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeVirtual ||
+                implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeInterface;
+        this.implDefiningClass = implInfo.getDeclaringClass();
+        this.implMethodType = implInfo.getMethodType();
+        
+        this.functionDescType = functionDescType;
+    }
+    
+    abstract CallSite buildCallSite() throws ReflectiveOperationException;
+
+    private static final Map<Class<?>, Set<Class<?>>> assignableTo = new HashMap<>();
+    private static final Map<Class<?>, Class<?>> boxesTo = new HashMap<>();
+    private static final Map<Class<?>, Class<?>> unboxesTo = new HashMap<>();
+    static {
+        assignableTo.put(byte.class, new HashSet<>(Arrays.<Class<?>>asList(byte.class, short.class, int.class,
+                                                                           long.class, float.class, double.class)));
+        assignableTo.put(short.class, new HashSet<>(Arrays.<Class<?>>asList(short.class, int.class, long.class,
+                                                                            float.class, double.class)));
+        assignableTo.put(char.class, new HashSet<>(Arrays.<Class<?>>asList(char.class, short.class, int.class, long.class,
+                                                                           float.class, double.class)));
+        assignableTo.put(int.class, new HashSet<>(Arrays.<Class<?>>asList(int.class, long.class, float.class, double.class)));
+        assignableTo.put(long.class, new HashSet<>(Arrays.<Class<?>>asList(long.class, float.class, double.class)));
+        assignableTo.put(float.class, new HashSet<>(Arrays.<Class<?>>asList(float.class, double.class)));
+        assignableTo.put(double.class, new HashSet<>(Arrays.<Class<?>>asList(double.class)));
+        assignableTo.put(boolean.class, new HashSet<>(Arrays.<Class<?>>asList(boolean.class)));
+        assignableTo.put(void.class, new HashSet<>(Arrays.<Class<?>>asList(void.class)));
+
+        boxesTo.put(byte.class, Byte.class);
+        boxesTo.put(short.class, Short.class);
+        boxesTo.put(char.class, Character.class);
+        boxesTo.put(int.class, Integer.class);
+        boxesTo.put(long.class, Long.class);
+        boxesTo.put(float.class, Float.class);
+        boxesTo.put(double.class, Double.class);
+        boxesTo.put(boolean.class, Boolean.class);
+
+        for (Map.Entry<Class<?>, Class<?>> e : boxesTo.entrySet()) {
+            unboxesTo.put(e.getValue(), e.getKey());
+        }
+    }
+
+    void validateMetafactoryArgs() {
+        // @@@ Validate SAM-ness
+
+        // Check target type is a subtype of class where SAM method is defined
+        if (!samClass.isAssignableFrom(samBase)) {
+            throw new LambdaConversionException(String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s",
+                    samBase.getName(), samClass.getName()));
+        }
+
+        // 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();
+        if (implArity + receiverArity != capturedArity + samArity) {
+            throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method; %d captured parameters, %d functional interface parameters, %d implementation parameters",
+                                                              implIsInstanceMethod ? "instance" : "static",
+                                                              capturedArity, samArity, implArity));
+        }
+
+        // If instance: first captured arg (receiver) must be subtype of class where impl method is defined
+        final int capturedStart;
+        final int samStart;
+        if (implIsInstanceMethod) {
+            final Class<?> receiverClass;
+
+            // implementation is an instance method, adjust for receiver in captured variables / SAM arguments
+            if (capturedArity == 0) {
+                // receiver is function parameter
+                capturedStart = 0;
+                samStart = 1;
+                receiverClass = functionDescType.parameterType(0);
+            } else {
+                // receiver is a captured variable
+                capturedStart = 1;
+                samStart = 0;
+                receiverClass = invokedType.parameterType(0);
+            }
+
+            // check receiver type
+            if (!implDefiningClass.isAssignableFrom(receiverClass)) {
+                throw new LambdaConversionException(String.format("Invalid receiver type %s; not a subtype of implementation type %s",
+                                                                  receiverClass, implDefiningClass));
+            }
+        } else {
+            // no receiver
+            capturedStart = 0;
+            samStart = 0;
+        }
+
+        // Check for exact match on non-receiver captured arguments
+        final int implFromCaptured = capturedArity - capturedStart;
+        for (int i=0; i<implFromCaptured; i++) {
+            Class<?> implParamType = implMethodType.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 SAM arguments
+        final int samOffset = samStart - implFromCaptured;
+        for (int i=implFromCaptured; i<implArity; i++) {
+            Class<?> implParamType = implMethodType.parameterType(i);
+            Class<?> samParamType = samMethodType.parameterType(i + samOffset);
+            if (!isAdaptableTo(samParamType, implParamType)) {
+                throw new LambdaConversionException(
+                        String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, samParamType, implParamType));
+            }
+        }
+
+        // Adaptation match: return type
+        Class<?> expectedType = samMethodType.returnType();
+        Class<?> actualReturnType =
+                (implInfo.getReferenceKind() == 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", actualReturnType, expectedType));
+        }
+    }
+
+    private boolean isAdaptableTo(Class<?> fromType, Class<?> toType) {
+        if (fromType.equals(toType)) {
+            return true;
+        }
+        boolean fromIsPrimitive = fromType.isPrimitive();
+        boolean toIsPrimitive = toType.isPrimitive();
+        if (fromIsPrimitive) {
+            if (toIsPrimitive) {
+                // widening
+                Set<Class<?>> classes = assignableTo.get(fromType);
+                return classes != null && classes.contains(toType);
+            }
+            else {
+                // boxing
+                return toType.isAssignableFrom(boxesTo.get(fromType));
+            }
+        }
+        else {
+            if (toIsPrimitive) {
+                // unboxing
+                Class<?> unboxedFrom = unboxesTo.get(fromType);
+                if (unboxedFrom != null) {
+                    // fromType is a primitive wrapper; unbox+widen
+                    Set<Class<?>> classes = assignableTo.get(unboxedFrom);
+                    return classes != null && classes.contains(toType);
+                }
+                else {
+                    // cast to wrapper for toType, and unbox
+                    return true;
+                }
+            }
+            else {
+                // blind cast to toType
+                return true;
+            }
+        }
+    }
+
+    private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
+        return toType.equals(void.class)
+               || !fromType.equals(void.class) && isAdaptableTo(fromType, toType);
+    }
+
+}
--- a/src/share/classes/java/lang/invoke/InnerClassGenerator.java	Sun Sep 02 09:52:16 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,350 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang.invoke;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.openjdk.org.objectweb.asm.*;
-import static org.openjdk.org.objectweb.asm.Opcodes.*;
-import sun.misc.Unsafe;
-
-/**
- * InnerClassGenerator
- */
-class InnerClassGenerator {
-    private static final int CLASSFILE_VERSION = 51;
-    private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
-    private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
-    private static final Type TYPE_VOID = Type.getType(void.class);
-    private static final String NAME_OBJECT = "java/lang/Object";
-    private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
-    private static final String NAME_SERIALIZABLE = "java/io/Serializable";
-    private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl";
-    private static final String NAME_CTOR = "<init>";
-
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
-
-    // Used to ensure that each spun class name is unique
-    private static final AtomicInteger counter = new AtomicInteger(0);
-
-    private final Class<?> targetClass;
-    private final int implKind;
-    private final Class<?> implMethodClass;
-    private final String implMethodClassName;
-    private final String implMethodName;
-    private final String implMethodDesc;
-    private final Type implMethodType;
-    private final boolean implIsInstanceMethod;
-    private final ClassWriter cw;
-    private final String[] argNames;
-    private final Type[] argTypes;
-    private final String lambdaClassName;
-    private final String constructorDesc;
-    
-    public InnerClassGenerator(         MethodType constructorType,
-                                                        MethodHandleInfo implInfo,
-                                                        boolean implIsInstanceMethod,
-                                                        Class<?> targetClass) {
-        this.targetClass = targetClass;
-        this.implIsInstanceMethod = implIsInstanceMethod;
-        implKind = implInfo.getReferenceKind();
-        implMethodClass = implInfo.getDeclaringClass();
-        implMethodClassName = implMethodClass.getName().replace('.', '/');
-        implMethodName = implInfo.getName();
-        implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
-        implMethodType = Type.getMethodType(implMethodDesc);
-        constructorDesc = constructorType.toMethodDescriptorString();
-        lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
-        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-        argTypes = Type.getArgumentTypes(constructorDesc);
-        argNames = new String[argTypes.length];
-        for (int i = 0; i < argTypes.length; i++) {
-            argNames[i] = "arg$" + (i + 1);
-        } 
-    }
-
-    public <T> Class<? extends T> spinInnerClass(Class<T> samClass,
-                                                        MethodHandleInfo samInfo,
-                                                        MethodType functionDescType,
-                                                        boolean serializable) {
-        String samMethodName = samInfo.getName();
-        String functionalMethodDesc = functionDescType.toMethodDescriptorString();
- 
-        Method[] methods = samClass.getMethods(); 
-        String samName = samClass.getName().replace('.', '/');
-        Type samType = Type.getType(samClass);
-
-        cw.visit(CLASSFILE_VERSION, ACC_PUBLIC + ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL,
-                 serializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName});
-
-        // Generate fields
-        for (int i = 0; i < argTypes.length; i++) {
-            FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(), null, null);
-            fv.visitEnd();
-        }
-        
-        generateConstructor(constructorDesc);
-
-        // Generate methods
-        MethodType samMethodType = samInfo.getMethodType();
-        Class<?>[] samParamTypes = samMethodType.parameterArray();
-        int samParamLength = samParamTypes.length;
-        Class<?> samReturnType = samMethodType.returnType();
-        boolean defaultMethodFound = false;
-        Method samMethod = null;
-        List<Method> methodsFound = new ArrayList<>(methods.length);
-        List<Method> methodsToBridge = new ArrayList<>(methods.length);
-        Class<?> objectClass = Object.class;
-
-        // Find the SAM method and corresponding methods which should be bridged.
-        // SAM method and those to be bridged will have the same name and number of parameters.
-        // Check for default methods (non-abstract), they should not be bridged-over and indicate a complex bridging situation.
-        for (Method m : methods) {
-            if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
-                Class<?>[] mParamTypes = m.getParameterTypes();
-                if (mParamTypes.length == samParamLength) {
-                    if (Modifier.isAbstract(m.getModifiers())) {
-                        // Exclude methods with duplicate signatures
-                        if (!matchesAnyMethod(m, methodsFound)) {
-                            methodsFound.add(m);
-                            if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) {
-                                // Exact match, this is the SAM method signature
-                                samMethod = m;
-                            } else {
-                                methodsToBridge.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
-                        if (!matchesAnyMethod(m, methodsFound)) {
-                            methodsFound.add(m);
-                        }
-                    }
-                }
-            }
-        }
-
-        // Forward the SAM method
-        if (samMethod == null) {
-            throw new LambdaConversionException(String.format("SAM method not found: %s", samMethodType));
-        } else {
-            generateForwardingMethod(samMethod, functionalMethodDesc, false);
-        }
-
-        // Forward the bridges
-        // @@@ Once the VM can do fail-over, uncomment the default method test
-        if (!methodsToBridge.isEmpty() /* && !defaultMethodFound*/) {
-            for (Method m : methodsToBridge) {
-                generateForwardingMethod(m, functionalMethodDesc, true);
-
-            }
-        }
-
-        if (serializable) {
-            generateSerializationMethod(samInfo, samType, samMethodName);
-        }
-
-        cw.visitEnd();
-
-        return defineGeneratedClass(cw.toByteArray());
-    }
-
-    private <T> Class<? extends T> defineGeneratedClass(final byte[] classBytes) {
-        if (System.getProperty("debug.dump.generated") != null) {
-            System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length);
-            try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
-                fos.write(classBytes);
-            } catch (IOException ex) {
-                Logger.getLogger(InnerClassGenerator.class.getName()).log(Level.SEVERE, null, ex);
-            }
-        }
-        
-        ClassLoader loader = targetClass.getClassLoader();
-        ProtectionDomain pd = (loader == null)? null : targetClass.getProtectionDomain();
-        return (Class <? extends T>) unsafe.defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd);
-    }
-    
-    private static boolean matchesAnyMethod(Method m, List<Method> methods) {
-        Class<?>[] ptypes = m.getParameterTypes();
-        Class<?> rtype = m.getReturnType();
-        for (Method md : methods) {
-            if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void generateConstructor(String constructorDesc) {
-        // Generate constructor
-        MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, NAME_CTOR, constructorDesc, null, null);
-        ctor.visitCode();
-        ctor.visitVarInsn(ALOAD, 0);
-        ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, Type.getMethodDescriptor(Type.VOID_TYPE));
-        int lvIndex = 0;
-        for (int i = 0; i < argTypes.length; i++) {
-            ctor.visitVarInsn(ALOAD, 0);
-            ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
-            lvIndex += argTypes[i].getSize();
-            ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
-        }
-        ctor.visitInsn(RETURN);
-        ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
-        ctor.visitEnd();
-    }
-
-    private void generateSerializationMethod(MethodHandleInfo samInfo, Type samType, String samMethodName) {
-        String samMethodDesc = samInfo.getMethodType().toMethodDescriptorString();
-        TypeConvertingMethodAdapter mv = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, null, null));
-
-        mv.visitCode();
-        mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
-        mv.dup();
-        mv.visitLdcInsn(samType);
-        mv.visitLdcInsn(samMethodName);
-        mv.visitLdcInsn(samMethodDesc);
-        mv.visitLdcInsn(Type.getType(implMethodClass));
-        mv.visitLdcInsn(implMethodName);
-        mv.visitLdcInsn(implMethodDesc);
-
-        mv.iconst(argTypes.length);
-        mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT);
-        for (int i = 0; i < argTypes.length; i++) {
-            mv.dup();
-            mv.iconst(i);
-            mv.visitVarInsn(ALOAD, 0);
-            mv.getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
-            mv.boxIfPrimitive(argTypes[i]);
-            mv.visitInsn(AASTORE);
-        }
-        mv.invokespecial(NAME_SERIALIZED_LAMBDA, NAME_CTOR,
-                           "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V");
-        mv.visitInsn(ARETURN);
-        mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
-        mv.visitEnd();
-    }
-
-    private void generateForwardingMethod(Method m, String functionalMethodDesc, boolean isBridge) throws InternalError {
-        Class<?>[] exceptionTypes = m.getExceptionTypes();
-        String[] exceptionNames = new String[exceptionTypes.length];
-        for (int i = 0; i < exceptionTypes.length; i++) {
-            exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
-        }
-        String methodDescriptor = Type.getMethodDescriptor(m);
-        int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
-        MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
-        new ForwardingMethodGenerator(mv).generate(m, functionalMethodDesc);
-    }
-
-    private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
-
-        ForwardingMethodGenerator(MethodVisitor mv) {
-            super(mv);
-        }
-
-        void generate(Method m, String functionalMethodDesc) throws InternalError {
-            visitCode();
-
-            if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
-                visitTypeInsn(NEW, implMethodClassName);
-                dup();
-            }
-            for (int i = 0; i < argTypes.length; i++) {
-                visitVarInsn(ALOAD, 0);
-                getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
-            }
-
-            convertArgumentTypes(Type.getArgumentTypes(m), Type.getArgumentTypes(functionalMethodDesc));
-
-            // Invoke the method we want to forward to
-            visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
-
-            // Convert the return value (if any) and return it
-            // @@@ if adapting from non-void to void, need to pop result off stack
-            Type samReturnType = Type.getReturnType(m);
-            if (!samReturnType.equals(TYPE_VOID)) {
-                convertType(implMethodType.getReturnType(), samReturnType, samReturnType);
-            }
-            areturn(samReturnType);
-
-            visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
-            visitEnd();
-        }
-
-        void convertArgumentTypes(Type[] samArgumentTypes, Type[] functionalArgumentTypes) {
-            int lvIndex = 0;
-            boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0;
-            int samReceiverLength = samIncludesReceiver ? 1 : 0;
-            if (samIncludesReceiver) {
-                // push receiver
-                Type rcvrType = samArgumentTypes[0];
-                Type functionalType = functionalArgumentTypes[0];
-
-                load(lvIndex + 1, rcvrType);
-                lvIndex += rcvrType.getSize();
-                convertType(rcvrType, Type.getType(implMethodClass), functionalType);
-            }
-            Type[] implArgumentTypes = implMethodType.getArgumentTypes();
-            int argOffset = implArgumentTypes.length - samArgumentTypes.length;
-            for (int i = samReceiverLength; i < samArgumentTypes.length; i++) {
-                Type argType = samArgumentTypes[i];
-                Type targetType = implArgumentTypes[argOffset + i];
-                Type functionalType = functionalArgumentTypes[i];
-
-                load(lvIndex + 1, argType);
-                lvIndex += argType.getSize();
-                convertType(argType, targetType, functionalType);
-            }
-        }
-
-        int invocationOpcode() throws InternalError {
-            switch (implKind) {
-                case MethodHandleInfo.REF_invokeStatic:
-                    return INVOKESTATIC;
-                case MethodHandleInfo.REF_newInvokeSpecial:
-                    return INVOKESPECIAL;
-                 case MethodHandleInfo.REF_invokeVirtual:
-                    return INVOKEVIRTUAL;
-                case MethodHandleInfo.REF_invokeInterface:
-                    return INVOKEINTERFACE;
-                default:
-                    throw new InternalError("Unexpected invocation kind: " + implKind);
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Sun Sep 02 22:05:39 2012 -0700
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.openjdk.org.objectweb.asm.*;
+import static org.openjdk.org.objectweb.asm.Opcodes.*;
+import sun.misc.Unsafe;
+
+/**
+ * InnerClassLambdaMetafactory
+ */
+class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
+    private static final int CLASSFILE_VERSION = 51;
+    private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
+    private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
+    private static final Type TYPE_VOID = Type.getType(void.class);
+    private static final String NAME_OBJECT = "java/lang/Object";
+    private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
+    private static final String NAME_SERIALIZABLE = "java/io/Serializable";
+    private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl";
+    private static final String NAME_CTOR = "<init>";
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // Used to ensure that each spun class name is unique
+    private static final AtomicInteger counter = new AtomicInteger(0);
+
+    private final int implKind;
+    private final String implMethodClassName;
+    private final String implMethodName;
+    private final String implMethodDesc;
+    private final Type implMethodAsmType;
+    private final MethodType constructorType;
+    private final ClassWriter cw;
+    private final String[] argNames;
+    private final Type[] argTypes;
+    private final String lambdaClassName;
+    private final String constructorDesc;
+    
+    public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
+                                       MethodType invokedType,
+                                       MethodHandle samMethod,
+                                       MethodHandle implMethod,
+                                       MethodType functionDescType)
+            throws ReflectiveOperationException {
+        super(caller, invokedType, samMethod, implMethod, functionDescType);
+        implKind = implInfo.getReferenceKind();
+        implMethodClassName = implDefiningClass.getName().replace('.', '/');
+        implMethodName = implInfo.getName();
+        implMethodDesc = implMethodType.toMethodDescriptorString();
+        implMethodAsmType = Type.getMethodType(implMethodDesc);
+        constructorType = invokedType.changeReturnType(Void.TYPE);
+        constructorDesc = constructorType.toMethodDescriptorString();
+        lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
+        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        argTypes = Type.getArgumentTypes(constructorDesc);
+        argNames = new String[argTypes.length];
+        for (int i = 0; i < argTypes.length; i++) {
+            argNames[i] = "arg$" + (i + 1);
+        } 
+    }
+
+    @Override
+    CallSite buildCallSite() throws ReflectiveOperationException {
+        final Class<?> innerClass = spinInnerClass();
+        if (invokedType.parameterCount() == 0) {
+            return new ConstantCallSite(MethodHandles.constant(samBase, innerClass.newInstance()));
+        } else {
+            return new ConstantCallSite(
+                    MethodHandles.Lookup.IMPL_LOOKUP
+                    .findConstructor(innerClass, constructorType)
+                    .asType(constructorType.changeReturnType(samBase)));
+        }
+    }
+
+    private <T> Class<? extends T> spinInnerClass() {
+        String samMethodName = samInfo.getName();
+        String functionalMethodDesc = functionDescType.toMethodDescriptorString();
+ 
+        Method[] methods = samBase.getMethods();
+        String samName = samBase.getName().replace('.', '/');
+        Type samType = Type.getType(samBase);
+
+        cw.visit(CLASSFILE_VERSION, ACC_PUBLIC + ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL,
+                 isSerializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName});
+
+        // Generate fields
+        for (int i = 0; i < argTypes.length; i++) {
+            FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(), null, null);
+            fv.visitEnd();
+        }
+        
+        generateConstructor(constructorDesc);
+
+        // Generate methods
+        Class<?>[] samParamTypes = samMethodType.parameterArray();
+        int samParamLength = samParamTypes.length;
+        Class<?> samReturnType = samMethodType.returnType();
+        boolean defaultMethodFound = false;
+        Method samMethod = null;
+        List<Method> methodsFound = new ArrayList<>(methods.length);
+        List<Method> methodsToBridge = new ArrayList<>(methods.length);
+        Class<?> objectClass = Object.class;
+
+        // Find the SAM method and corresponding methods which should be bridged.
+        // SAM method and those to be bridged will have the same name and number of parameters.
+        // Check for default methods (non-abstract), they should not be bridged-over and indicate a complex bridging situation.
+        for (Method m : methods) {
+            if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
+                Class<?>[] mParamTypes = m.getParameterTypes();
+                if (mParamTypes.length == samParamLength) {
+                    if (Modifier.isAbstract(m.getModifiers())) {
+                        // Exclude methods with duplicate signatures
+                        if (!matchesAnyMethod(m, methodsFound)) {
+                            methodsFound.add(m);
+                            if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) {
+                                // Exact match, this is the SAM method signature
+                                samMethod = m;
+                            } else {
+                                methodsToBridge.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
+                        if (!matchesAnyMethod(m, methodsFound)) {
+                            methodsFound.add(m);
+                        }
+                    }
+                }
+            }
+        }
+
+        // Forward the SAM method
+        if (samMethod == null) {
+            throw new LambdaConversionException(String.format("SAM method not found: %s", samMethodType));
+        } else {
+            generateForwardingMethod(samMethod, functionalMethodDesc, false);
+        }
+
+        // Forward the bridges
+        // @@@ Once the VM can do fail-over, uncomment the default method test
+        if (!methodsToBridge.isEmpty() /* && !defaultMethodFound*/) {
+            for (Method m : methodsToBridge) {
+                generateForwardingMethod(m, functionalMethodDesc, true);
+
+            }
+        }
+
+        if (isSerializable) {
+            generateSerializationMethod(samInfo, samType, samMethodName);
+        }
+
+        cw.visitEnd();
+
+        return defineGeneratedClass(cw.toByteArray());
+    }
+
+    private <T> Class<? extends T> defineGeneratedClass(final byte[] classBytes) {
+        if (System.getProperty("debug.dump.generated") != null) {
+            System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length);
+            try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
+                fos.write(classBytes);
+            } catch (IOException ex) {
+                Logger.getLogger(InnerClassLambdaMetafactory.class.getName()).log(Level.SEVERE, null, ex);
+            }
+        }
+        
+        ClassLoader loader = targetClass.getClassLoader();
+        ProtectionDomain pd = (loader == null)? null : targetClass.getProtectionDomain();
+        return (Class <? extends T>) unsafe.defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd);
+    }
+    
+    private static boolean matchesAnyMethod(Method m, List<Method> methods) {
+        Class<?>[] ptypes = m.getParameterTypes();
+        Class<?> rtype = m.getReturnType();
+        for (Method md : methods) {
+            if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void generateConstructor(String constructorDesc) {
+        // Generate constructor
+        MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, NAME_CTOR, constructorDesc, null, null);
+        ctor.visitCode();
+        ctor.visitVarInsn(ALOAD, 0);
+        ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, Type.getMethodDescriptor(Type.VOID_TYPE));
+        int lvIndex = 0;
+        for (int i = 0; i < argTypes.length; i++) {
+            ctor.visitVarInsn(ALOAD, 0);
+            ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
+            lvIndex += argTypes[i].getSize();
+            ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+        }
+        ctor.visitInsn(RETURN);
+        ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
+        ctor.visitEnd();
+    }
+
+    private void generateSerializationMethod(MethodHandleInfo samInfo, Type samType, String samMethodName) {
+        String samMethodDesc = samInfo.getMethodType().toMethodDescriptorString();
+        TypeConvertingMethodAdapter mv = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, null, null));
+
+        mv.visitCode();
+        mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
+        mv.dup();
+        mv.visitLdcInsn(samType);
+        mv.visitLdcInsn(samMethodName);
+        mv.visitLdcInsn(samMethodDesc);
+        mv.visitLdcInsn(Type.getType(implDefiningClass));
+        mv.visitLdcInsn(implMethodName);
+        mv.visitLdcInsn(implMethodDesc);
+
+        mv.iconst(argTypes.length);
+        mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT);
+        for (int i = 0; i < argTypes.length; i++) {
+            mv.dup();
+            mv.iconst(i);
+            mv.visitVarInsn(ALOAD, 0);
+            mv.getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+            mv.boxIfPrimitive(argTypes[i]);
+            mv.visitInsn(AASTORE);
+        }
+        mv.invokespecial(NAME_SERIALIZED_LAMBDA, NAME_CTOR,
+                           "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V");
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
+        mv.visitEnd();
+    }
+
+    private void generateForwardingMethod(Method m, String functionalMethodDesc, boolean isBridge) throws InternalError {
+        Class<?>[] exceptionTypes = m.getExceptionTypes();
+        String[] exceptionNames = new String[exceptionTypes.length];
+        for (int i = 0; i < exceptionTypes.length; i++) {
+            exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
+        }
+        String methodDescriptor = Type.getMethodDescriptor(m);
+        int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
+        MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
+        new ForwardingMethodGenerator(mv).generate(m, functionalMethodDesc);
+    }
+
+    private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
+
+        ForwardingMethodGenerator(MethodVisitor mv) {
+            super(mv);
+        }
+
+        void generate(Method m, String functionalMethodDesc) throws InternalError {
+            visitCode();
+
+            if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
+                visitTypeInsn(NEW, implMethodClassName);
+                dup();
+            }
+            for (int i = 0; i < argTypes.length; i++) {
+                visitVarInsn(ALOAD, 0);
+                getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor());
+            }
+
+            convertArgumentTypes(Type.getArgumentTypes(m), Type.getArgumentTypes(functionalMethodDesc));
+
+            // Invoke the method we want to forward to
+            visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
+
+            // Convert the return value (if any) and return it
+            // @@@ if adapting from non-void to void, need to pop result off stack
+            Type samReturnType = Type.getReturnType(m);
+            if (!samReturnType.equals(TYPE_VOID)) {
+                convertType(implMethodAsmType.getReturnType(), samReturnType, samReturnType);
+            }
+            areturn(samReturnType);
+
+            visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
+            visitEnd();
+        }
+
+        void convertArgumentTypes(Type[] samArgumentTypes, Type[] functionalArgumentTypes) {
+            int lvIndex = 0;
+            boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0;
+            int samReceiverLength = samIncludesReceiver ? 1 : 0;
+            if (samIncludesReceiver) {
+                // push receiver
+                Type rcvrType = samArgumentTypes[0];
+                Type functionalType = functionalArgumentTypes[0];
+
+                load(lvIndex + 1, rcvrType);
+                lvIndex += rcvrType.getSize();
+                convertType(rcvrType, Type.getType(implDefiningClass), functionalType);
+            }
+            Type[] implArgumentTypes = implMethodAsmType.getArgumentTypes();
+            int argOffset = implArgumentTypes.length - samArgumentTypes.length;
+            for (int i = samReceiverLength; i < samArgumentTypes.length; i++) {
+                Type argType = samArgumentTypes[i];
+                Type targetType = implArgumentTypes[argOffset + i];
+                Type functionalType = functionalArgumentTypes[i];
+
+                load(lvIndex + 1, argType);
+                lvIndex += argType.getSize();
+                convertType(argType, targetType, functionalType);
+            }
+        }
+
+        int invocationOpcode() throws InternalError {
+            switch (implKind) {
+                case MethodHandleInfo.REF_invokeStatic:
+                    return INVOKESTATIC;
+                case MethodHandleInfo.REF_newInvokeSpecial:
+                    return INVOKESPECIAL;
+                 case MethodHandleInfo.REF_invokeVirtual:
+                    return INVOKEVIRTUAL;
+                case MethodHandleInfo.REF_invokeInterface:
+                    return INVOKEINTERFACE;
+                default:
+                    throw new InternalError("Unexpected invocation kind: " + implKind);
+            }
+        }
+    }
+}
--- a/src/share/classes/java/lang/invoke/LambdaMetafactory.java	Sun Sep 02 09:52:16 2012 -0700
+++ b/src/share/classes/java/lang/invoke/LambdaMetafactory.java	Sun Sep 02 22:05:39 2012 -0700
@@ -25,9 +25,6 @@
 
 package java.lang.invoke;
 
-import java.io.Serializable;
-import java.util.*;
-
 /**
  * <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
  *
@@ -40,7 +37,7 @@
  * for lambda expressions, the implementation method is produced by the compiler based on the body of the lambda
  * expression.  The methods in this file are the bootstrap methods for those invokedynamic call sites, called
  * lambda factories, and the bootstrap methods responsible for linking the lambda factories are called lambda
- * metafactories.
+ * meta-factories.
  *
  * <p>The bootstrap methods in this class take the information about the functional interface, the implementation
  * method, and the static types of the captured lambda arguments, and link a call site which, when invoked,
@@ -51,7 +48,7 @@
  * of these methods on the lambda object will result in invoking the implementation method.
  *
  * <p>The argument list of the implementation method and the argument list of the functional interface method(s)
- * may differ in several ways.  The implementation methods may have additional arguments to accomodate arguments
+ * may differ in several ways.  The implementation methods may have additional arguments to accommodate arguments
  * captured by the lambda expression; there may also be differences resulting from permitted adaptations of
  * arguments, such as casting, boxing, unboxing, and primitive widening.
  *
@@ -75,14 +72,14 @@
  *     <ul>
  *         <li>K + N = M</li>
  *         <li>For i=1..K, Di = Ai</li>
- *         <li>For i=1..N, Ti is adaptible to Aj, where j=i+k</li>
+ *         <li>For i=1..N, Ti is adaptable to Aj, where j=i+k</li>
  *     </ul></li>
  *     <li>If the implementation method is an instance method:
  *     <ul>
  *         <li>K + N = M + 1</li>
  *         <li>D1 must be a subtype of the enclosing class for the implementation method</li>
  *         <li>For i=2..K, Di = Aj, where j=i-1</li>
- *         <li>For i=1..N, Ti is adaptible to Aj, where j=i+k-1</li>
+ *         <li>For i=1..N, Ti is adaptable to Aj, where j=i+k-1</li>
  *     </ul></li>
  *     <li>The return type Rf is void, or the return type Ri is not void and is adaptable to Rf</li>
  * </ul>
@@ -102,7 +99,7 @@
  *     </tr>
  *     <tr>
  *         <td>Reference</td><td>Primitive</td>
- *         <td>If T is a preimitive wrapper, check that Primitive(T) can be widened to U</td>
+ *         <td>If T is a primitive wrapper, check that Primitive(T) can be widened to U</td>
  *         <td>If T is not a primitive wrapper, cast T to Wrapper(U)</td>
  *     </tr>
  *     <tr>
@@ -116,36 +113,6 @@
  */
 public class LambdaMetafactory {
     
-    private static Map<Class<?>, Set<Class<?>>> assignableTo = new HashMap<>();
-    private static Map<Class<?>, Class<?>> boxesTo = new HashMap<>();
-    private static Map<Class<?>, Class<?>> unboxesTo = new HashMap<>();
-    static {
-        assignableTo.put(byte.class, new HashSet<>(Arrays.<Class<?>>asList(byte.class, short.class, int.class,
-                                                                           long.class, float.class, double.class)));
-        assignableTo.put(short.class, new HashSet<>(Arrays.<Class<?>>asList(short.class, int.class, long.class,
-                                                                            float.class, double.class)));
-        assignableTo.put(char.class, new HashSet<>(Arrays.<Class<?>>asList(char.class, short.class, int.class, long.class,
-                                                                           float.class, double.class)));
-        assignableTo.put(int.class, new HashSet<>(Arrays.<Class<?>>asList(int.class, long.class, float.class, double.class)));
-        assignableTo.put(long.class, new HashSet<>(Arrays.<Class<?>>asList(long.class, float.class, double.class)));
-        assignableTo.put(float.class, new HashSet<>(Arrays.<Class<?>>asList(float.class, double.class)));
-        assignableTo.put(double.class, new HashSet<>(Arrays.<Class<?>>asList(double.class)));
-        assignableTo.put(boolean.class, new HashSet<>(Arrays.<Class<?>>asList(boolean.class)));
-        assignableTo.put(void.class, new HashSet<>(Arrays.<Class<?>>asList(void.class)));
-
-        boxesTo.put(byte.class, Byte.class);
-        boxesTo.put(short.class, Short.class);
-        boxesTo.put(char.class, Character.class);
-        boxesTo.put(int.class, Integer.class);
-        boxesTo.put(long.class, Long.class);
-        boxesTo.put(float.class, Float.class);
-        boxesTo.put(double.class, Double.class);
-        boxesTo.put(boolean.class, Boolean.class);
-
-        for (Map.Entry<Class<?>, Class<?>> e : boxesTo.entrySet())
-            unboxesTo.put(e.getValue(), e.getKey());
-    }
-
     // @@@ For developement only -- remove for production
     private static final String whichMetafactory;
     static {
@@ -154,11 +121,8 @@
     }
     // -- dev-only --
 
-    private static final MethodType MT_VOID = MethodType.fromMethodDescriptorString("()V", null);
-
     /**
-     * Standard metafactory for conversion of lambda expressions or method references to functional interfaces.
-     *
+     * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces.
      *
      * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
      *               of the caller.
@@ -174,9 +138,9 @@
      *                   types, return types, and adjustment for captured arguments) when methods of the resulting
      *                   functional interface instance are invoked.
      * @param functionDescType The signature of the SAM method from the target type's perspective
-     * @return
+     * @return a CallSite, which, when invoked, will return an instance of the functional interface
      * @throws ReflectiveOperationException
-     * @throws LambdaConversionException If any of the metafactory protocol invariants are violated
+     * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
      */
     public static CallSite metaFactory(MethodHandles.Lookup caller,
                                        String invokedName,
@@ -185,190 +149,18 @@
                                        MethodHandle implMethod,
                                        MethodType functionDescType)
                    throws ReflectiveOperationException, LambdaConversionException {
-        final MethodHandleInfo samInfo = new MethodHandleInfo(samMethod);
-        final MethodHandleInfo implInfo = new MethodHandleInfo(implMethod);
-        final boolean implIsInstanceMethod = 
-                implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeVirtual ||
-                implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeInterface;
-
-        validateMetafactoryArgs(implIsInstanceMethod, invokedType, samInfo, implInfo, functionDescType);
-
+        AbstractValidatingLambdaMetafactory mf;
         switch (whichMetafactory) {
             case "innerClass":
-                return innerClassMetafactory(implIsInstanceMethod, caller, invokedType, samInfo, implInfo, functionDescType);
+                mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, functionDescType);
+                break;
             case "mhProxy":
-                return MethodHandleProxyLambdaMetafactory.mhProxyMetafactory(caller, invokedType, implMethod);
+                mf = new MethodHandleProxyLambdaMetafactory(caller, invokedType, samMethod, implMethod, functionDescType);
+                break;
             default:
                 throw new Error("Unknown metafactory");
         }
-    }
-
-    private static void validateMetafactoryArgs(final boolean implIsInstanceMethod,
-                                                MethodType invokedType,
-                                                MethodHandleInfo samInfo,
-                                                MethodHandleInfo implInfo,
-                                                MethodType functionDescType) {
-        {
-            final Class<?> samClass = samInfo.getDeclaringClass();
-            final Class<?> samBase = invokedType.returnType();
-
-            // @@@ Validate SAM-ness
-
-            // Check target type is a subtype of class where SAM method is defined
-            if (!samClass.isAssignableFrom(samBase)) {
-                throw new LambdaConversionException(String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s",
-                        samBase.getName(), samClass.getName()));
-            }
-        }
-        
-        final MethodType samType  = samInfo.getMethodType();
-        final MethodType implType = implInfo.getMethodType();
-        final Class<?> implDefiningClass = implInfo.getDeclaringClass();
-
-        // Check arity: optional-receiver + captured + SAM == impl
-        final int implArity = implType.parameterCount();
-        final int receiverArity = implIsInstanceMethod ? 1 : 0;
-        final int capturedArity = invokedType.parameterCount();
-        final int samArity = samType.parameterCount();
-        if (implArity + receiverArity != capturedArity + samArity) {
-            throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method; %d captured parameters, %d functional interface parameters, %d implementation parameters",
-                                                              implIsInstanceMethod ? "instance" : "static",
-                                                              capturedArity, samArity, implArity));
-        }
-
-        // If instance: first captured arg (receiver) must be subtype of class where impl method is defined
-        final int capturedStart;
-        final int samStart;
-        if (implIsInstanceMethod) {
-            final Class<?> receiverClass;
-            
-            // implementation is an instance method, adjust for receiver in captured variables / SAM arguments
-            if (capturedArity == 0) {
-                // receiver is function parameter
-                capturedStart = 0;
-                samStart = 1;
-                receiverClass = functionDescType.parameterType(0);
-            } else {
-                // receiver is a captured variable
-                capturedStart = 1;
-                samStart = 0;
-                receiverClass = invokedType.parameterType(0);
-            }
-            
-            // check receiver type
-            if (!implDefiningClass.isAssignableFrom(receiverClass))
-                throw new LambdaConversionException(String.format("Invalid receiver type %s; not a subtype of implementation type %s",
-                                                                  receiverClass, implDefiningClass));
-        } else {
-            // no receiver
-            capturedStart = 0;
-            samStart = 0;
-        }
-
-        // Check for exact match on non-receiver captured arguments
-        final int implFromCaptured = capturedArity - capturedStart;
-        for (int i=0; i<implFromCaptured; i++) {
-            Class<?> implParamType = implType.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 SAM arguments
-        final int samOffset = samStart - implFromCaptured;
-        for (int i=implFromCaptured; i<implArity; i++) {
-            Class<?> implParamType = implType.parameterType(i);
-            Class<?> samParamType = samType.parameterType(i + samOffset);
-            if (!isAdaptableTo(samParamType, implParamType)) {
-                throw new LambdaConversionException(
-                        String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, samParamType, implParamType));
-            }
-        }
-
-        // Adaptation match: return type
-        Class<?> expectedType = samType.returnType();
-        Class<?> actualReturnType =
-                (implInfo.getReferenceKind() == MethodHandleInfo.REF_newInvokeSpecial)
-                  ? implDefiningClass
-                  : implType.returnType();
-        if (!isAdaptableToAsReturn(actualReturnType, expectedType)) {
-            throw new LambdaConversionException(
-                    String.format("Type mismatch for lambda return: %s is not convertible to %s", actualReturnType, expectedType));
-        }
-    }
-
-    /**
-     * Implementation of Lambda by dynamic inner-class generation
-     */
-    private static CallSite innerClassMetafactory(final boolean implIsInstanceMethod,
-                                                  final MethodHandles.Lookup caller,
-                                                  final MethodType invokedType,
-                                                  final MethodHandleInfo samInfo,
-                                                  final MethodHandleInfo implInfo,
-                                                  final MethodType functionDescType)
-            throws ReflectiveOperationException {
-        final MethodType constructorType = invokedType.changeReturnType(Void.TYPE);
-
-        final Class<?> samBase = invokedType.returnType();
-
-        final InnerClassGenerator icg = new InnerClassGenerator(constructorType, 
-                                                                 implInfo,
-                                                                 implIsInstanceMethod,
-                                                                 caller.lookupClass());
-        final Class<?> innerClass = icg.spinInnerClass(samBase, samInfo, functionDescType,
-                                                                 Serializable.class.isAssignableFrom(samBase));
-        if (invokedType.parameterCount() == 0) {
-            return new ConstantCallSite(MethodHandles.constant(samBase, innerClass.newInstance()));
-        }
-        else {
-            return new ConstantCallSite(
-                    MethodHandles.Lookup.IMPL_LOOKUP
-                            .findConstructor(innerClass, constructorType)
-                            .asType(constructorType.changeReturnType(samBase)));
-        }
-    }
-
-    private static boolean isAdaptableTo(Class<?> fromType, Class<?> toType) {
-        if (fromType.equals(toType))
-            return true;
-        boolean fromIsPrimitive = fromType.isPrimitive();
-        boolean toIsPrimitive = toType.isPrimitive();
-        if (fromIsPrimitive) {
-            if (toIsPrimitive) {
-                // widening
-                Set<Class<?>> classes = assignableTo.get(fromType);
-                return classes != null && classes.contains(toType);
-            }
-            else {
-                // boxing
-                return toType.isAssignableFrom(boxesTo.get(fromType));
-            }
-        }
-        else {
-            if (toIsPrimitive) {
-                // unboxing
-                Class<?> unboxedFrom = unboxesTo.get(fromType);
-                if (unboxedFrom != null) {
-                    // fromType is a primitive wrapper; unbox+widen
-                    Set<Class<?>> classes = assignableTo.get(unboxedFrom);
-                    return classes != null && classes.contains(toType);
-                }
-                else {
-                    // cast to wrapper for toType, and unbox
-                    return true;
-                }
-            }
-            else {
-                // blind cast to toType
-                return true;
-            }
-        }
-    }
-
-    private static boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
-        return toType.equals(void.class)
-               || !fromType.equals(void.class) && isAdaptableTo(fromType, toType);
+        mf.validateMetafactoryArgs();
+        return mf.buildCallSite();
     }
 }
-
--- a/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java	Sun Sep 02 09:52:16 2012 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleProxyLambdaMetafactory.java	Sun Sep 02 22:05:39 2012 -0700
@@ -30,12 +30,18 @@
 
 /**
  * MethodHandleProxyLambdaMetafactory
+ *
+ * @author Brian Goetz
  */
-class MethodHandleProxyLambdaMetafactory {
+class MethodHandleProxyLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
+
+    private final MethodHandle implMethod;
+
     // @@@ For debugging only -- delete before shipping
     static Executor logPool = Executors.newSingleThreadExecutor();
     private static void log(final String s) {
         logPool.execute(new Runnable() {
+            @Override
             public void run() {
                 System.out.println(s);
             }
@@ -43,6 +49,7 @@
     }
     private static void log(final String s, final Throwable e) {
         logPool.execute(new Runnable() {
+            @Override
             public void run() {
                 System.out.println(s);
                 e.printStackTrace(System.out);
@@ -51,20 +58,27 @@
     }
     // -- dev-only --
 
-    static CallSite mhProxyMetafactory(MethodHandles.Lookup caller,
+    MethodHandleProxyLambdaMetafactory(MethodHandles.Lookup caller,
                                        MethodType invokedType,
-                                       MethodHandle impl) {
-        Class<?> samBase = invokedType.returnType();
+                                       MethodHandle samMethod,
+                                       MethodHandle implMethod,
+                                       MethodType functionDescType)
+            throws ReflectiveOperationException {
+        super(caller, invokedType, samMethod, implMethod, functionDescType);
+        this.implMethod = implMethod;
+    }
 
+    @Override
+    CallSite buildCallSite() {
         // @@@ Special bindTo case for count=1 && isInstance
 
         if (invokedType.parameterCount() == 0) {
             return new ConstantCallSite(MethodHandles.constant(samBase,
-                                                               MethodHandleProxies.asInterfaceInstance(samBase, impl)));
+                MethodHandleProxies.asInterfaceInstance(samBase, implMethod)));
         }
         else {
             try {
-                return new MhMetafactoryCallSite(impl, invokedType, samBase);
+                return new MhMetafactoryCallSite(implMethod, invokedType, samBase);
             }
             catch (Throwable e) {
                 log("Exception constructing Lambda factory callsite", e);