rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java
branchjdk8-b132
changeset 1646 c880a8a8803b
child 1651 5c990ed353e9
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java	Sat Aug 09 11:11:13 2014 +0200
     1.3 @@ -0,0 +1,561 @@
     1.4 +/*
     1.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.lang.invoke;
    1.30 +
    1.31 +import jdk.internal.org.objectweb.asm.*;
    1.32 +import sun.invoke.util.BytecodeDescriptor;
    1.33 +import sun.misc.Unsafe;
    1.34 +import sun.security.action.GetPropertyAction;
    1.35 +
    1.36 +import java.io.FilePermission;
    1.37 +import java.io.Serializable;
    1.38 +import java.lang.reflect.Constructor;
    1.39 +import java.security.AccessController;
    1.40 +import java.security.PrivilegedAction;
    1.41 +import java.util.LinkedHashSet;
    1.42 +import java.util.concurrent.atomic.AtomicInteger;
    1.43 +import java.util.PropertyPermission;
    1.44 +import java.util.Set;
    1.45 +
    1.46 +import static jdk.internal.org.objectweb.asm.Opcodes.*;
    1.47 +
    1.48 +/**
    1.49 + * Lambda metafactory implementation which dynamically creates an
    1.50 + * inner-class-like class per lambda callsite.
    1.51 + *
    1.52 + * @see LambdaMetafactory
    1.53 + */
    1.54 +/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
    1.55 +    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
    1.56 +
    1.57 +    private static final int CLASSFILE_VERSION = 52;
    1.58 +    private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
    1.59 +    private static final String JAVA_LANG_OBJECT = "java/lang/Object";
    1.60 +    private static final String NAME_CTOR = "<init>";
    1.61 +    private static final String NAME_FACTORY = "get$Lambda";
    1.62 +
    1.63 +    //Serialization support
    1.64 +    private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
    1.65 +    private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
    1.66 +    private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
    1.67 +    private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
    1.68 +    private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
    1.69 +    private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
    1.70 +    private static final String NAME_METHOD_READ_OBJECT = "readObject";
    1.71 +    private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
    1.72 +    private static final String DESCR_CTOR_SERIALIZED_LAMBDA
    1.73 +            = MethodType.methodType(void.class,
    1.74 +                                    Class.class,
    1.75 +                                    String.class, String.class, String.class,
    1.76 +                                    int.class, String.class, String.class, String.class,
    1.77 +                                    String.class,
    1.78 +                                    Object[].class).toMethodDescriptorString();
    1.79 +    private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION
    1.80 +            = MethodType.methodType(void.class, String.class).toMethodDescriptorString();
    1.81 +    private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
    1.82 +
    1.83 +
    1.84 +    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    1.85 +
    1.86 +    // Used to ensure that each spun class name is unique
    1.87 +    private static final AtomicInteger counter = new AtomicInteger(0);
    1.88 +
    1.89 +    // For dumping generated classes to disk, for debugging purposes
    1.90 +    private static final ProxyClassesDumper dumper;
    1.91 +
    1.92 +    static {
    1.93 +        final String key = "jdk.internal.lambda.dumpProxyClasses";
    1.94 +        String path = AccessController.doPrivileged(
    1.95 +                new GetPropertyAction(key), null,
    1.96 +                new PropertyPermission(key , "read"));
    1.97 +        dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
    1.98 +    }
    1.99 +
   1.100 +    // See context values in AbstractValidatingLambdaMetafactory
   1.101 +    private final String implMethodClassName;        // Name of type containing implementation "CC"
   1.102 +    private final String implMethodName;             // Name of implementation method "impl"
   1.103 +    private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
   1.104 +    private final Class<?> implMethodReturnClass;    // class for implementaion method return type "Ljava/lang/String;"
   1.105 +    private final MethodType constructorType;        // Generated class constructor type "(CC)void"
   1.106 +    private final ClassWriter cw;                    // ASM class writer
   1.107 +    private final String[] argNames;                 // Generated names for the constructor arguments
   1.108 +    private final String[] argDescs;                 // Type descriptors for the constructor arguments
   1.109 +    private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
   1.110 +
   1.111 +    /**
   1.112 +     * General meta-factory constructor, supporting both standard cases and
   1.113 +     * allowing for uncommon options such as serialization or bridging.
   1.114 +     *
   1.115 +     * @param caller Stacked automatically by VM; represents a lookup context
   1.116 +     *               with the accessibility privileges of the caller.
   1.117 +     * @param invokedType Stacked automatically by VM; the signature of the
   1.118 +     *                    invoked method, which includes the expected static
   1.119 +     *                    type of the returned lambda object, and the static
   1.120 +     *                    types of the captured arguments for the lambda.  In
   1.121 +     *                    the event that the implementation method is an
   1.122 +     *                    instance method, the first argument in the invocation
   1.123 +     *                    signature will correspond to the receiver.
   1.124 +     * @param samMethodName Name of the method in the functional interface to
   1.125 +     *                      which the lambda or method reference is being
   1.126 +     *                      converted, represented as a String.
   1.127 +     * @param samMethodType Type of the method in the functional interface to
   1.128 +     *                      which the lambda or method reference is being
   1.129 +     *                      converted, represented as a MethodType.
   1.130 +     * @param implMethod The implementation method which should be called (with
   1.131 +     *                   suitable adaptation of argument types, return types,
   1.132 +     *                   and adjustment for captured arguments) when methods of
   1.133 +     *                   the resulting functional interface instance are invoked.
   1.134 +     * @param instantiatedMethodType The signature of the primary functional
   1.135 +     *                               interface method after type variables are
   1.136 +     *                               substituted with their instantiation from
   1.137 +     *                               the capture site
   1.138 +     * @param isSerializable Should the lambda be made serializable?  If set,
   1.139 +     *                       either the target type or one of the additional SAM
   1.140 +     *                       types must extend {@code Serializable}.
   1.141 +     * @param markerInterfaces Additional interfaces which the lambda object
   1.142 +     *                       should implement.
   1.143 +     * @param additionalBridges Method types for additional signatures to be
   1.144 +     *                          bridged to the implementation method
   1.145 +     * @throws LambdaConversionException If any of the meta-factory protocol
   1.146 +     * invariants are violated
   1.147 +     */
   1.148 +    public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
   1.149 +                                       MethodType invokedType,
   1.150 +                                       String samMethodName,
   1.151 +                                       MethodType samMethodType,
   1.152 +                                       MethodHandle implMethod,
   1.153 +                                       MethodType instantiatedMethodType,
   1.154 +                                       boolean isSerializable,
   1.155 +                                       Class<?>[] markerInterfaces,
   1.156 +                                       MethodType[] additionalBridges)
   1.157 +            throws LambdaConversionException {
   1.158 +        super(caller, invokedType, samMethodName, samMethodType,
   1.159 +              implMethod, instantiatedMethodType,
   1.160 +              isSerializable, markerInterfaces, additionalBridges);
   1.161 +        implMethodClassName = implDefiningClass.getName().replace('.', '/');
   1.162 +        implMethodName = implInfo.getName();
   1.163 +        implMethodDesc = implMethodType.toMethodDescriptorString();
   1.164 +        implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
   1.165 +                ? implDefiningClass
   1.166 +                : implMethodType.returnType();
   1.167 +        constructorType = invokedType.changeReturnType(Void.TYPE);
   1.168 +        lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
   1.169 +        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
   1.170 +        int parameterCount = invokedType.parameterCount();
   1.171 +        if (parameterCount > 0) {
   1.172 +            argNames = new String[parameterCount];
   1.173 +            argDescs = new String[parameterCount];
   1.174 +            for (int i = 0; i < parameterCount; i++) {
   1.175 +                argNames[i] = "arg$" + (i + 1);
   1.176 +                argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
   1.177 +            }
   1.178 +        } else {
   1.179 +            argNames = argDescs = EMPTY_STRING_ARRAY;
   1.180 +        }
   1.181 +    }
   1.182 +
   1.183 +    /**
   1.184 +     * Build the CallSite. Generate a class file which implements the functional
   1.185 +     * interface, define the class, if there are no parameters create an instance
   1.186 +     * of the class which the CallSite will return, otherwise, generate handles
   1.187 +     * which will call the class' constructor.
   1.188 +     *
   1.189 +     * @return a CallSite, which, when invoked, will return an instance of the
   1.190 +     * functional interface
   1.191 +     * @throws ReflectiveOperationException
   1.192 +     * @throws LambdaConversionException If properly formed functional interface
   1.193 +     * is not found
   1.194 +     */
   1.195 +    @Override
   1.196 +    CallSite buildCallSite() throws LambdaConversionException {
   1.197 +        final Class<?> innerClass = spinInnerClass();
   1.198 +        if (invokedType.parameterCount() == 0) {
   1.199 +            final Constructor[] ctrs = AccessController.doPrivileged(
   1.200 +                    new PrivilegedAction<Constructor[]>() {
   1.201 +                @Override
   1.202 +                public Constructor[] run() {
   1.203 +                    Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
   1.204 +                    if (ctrs.length == 1) {
   1.205 +                        // The lambda implementing inner class constructor is private, set
   1.206 +                        // it accessible (by us) before creating the constant sole instance
   1.207 +                        ctrs[0].setAccessible(true);
   1.208 +                    }
   1.209 +                    return ctrs;
   1.210 +                }
   1.211 +                    });
   1.212 +            if (ctrs.length != 1) {
   1.213 +                throw new LambdaConversionException("Expected one lambda constructor for "
   1.214 +                        + innerClass.getCanonicalName() + ", got " + ctrs.length);
   1.215 +            }
   1.216 +
   1.217 +            try {
   1.218 +                Object inst = ctrs[0].newInstance();
   1.219 +                return new ConstantCallSite(MethodHandles.constant(samBase, inst));
   1.220 +            }
   1.221 +            catch (ReflectiveOperationException e) {
   1.222 +                throw new LambdaConversionException("Exception instantiating lambda object", e);
   1.223 +            }
   1.224 +        } else {
   1.225 +            try {
   1.226 +                UNSAFE.ensureClassInitialized(innerClass);
   1.227 +                return new ConstantCallSite(
   1.228 +                        MethodHandles.Lookup.IMPL_LOOKUP
   1.229 +                             .findStatic(innerClass, NAME_FACTORY, invokedType));
   1.230 +            }
   1.231 +            catch (ReflectiveOperationException e) {
   1.232 +                throw new LambdaConversionException("Exception finding constructor", e);
   1.233 +            }
   1.234 +        }
   1.235 +    }
   1.236 +
   1.237 +    /**
   1.238 +     * Generate a class file which implements the functional
   1.239 +     * interface, define and return the class.
   1.240 +     *
   1.241 +     * @implNote The class that is generated does not include signature
   1.242 +     * information for exceptions that may be present on the SAM method.
   1.243 +     * This is to reduce classfile size, and is harmless as checked exceptions
   1.244 +     * are erased anyway, no one will ever compile against this classfile,
   1.245 +     * and we make no guarantees about the reflective properties of lambda
   1.246 +     * objects.
   1.247 +     *
   1.248 +     * @return a Class which implements the functional interface
   1.249 +     * @throws LambdaConversionException If properly formed functional interface
   1.250 +     * is not found
   1.251 +     */
   1.252 +    private Class<?> spinInnerClass() throws LambdaConversionException {
   1.253 +        String[] interfaces;
   1.254 +        String samIntf = samBase.getName().replace('.', '/');
   1.255 +        boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
   1.256 +        if (markerInterfaces.length == 0) {
   1.257 +            interfaces = new String[]{samIntf};
   1.258 +        } else {
   1.259 +            // Assure no duplicate interfaces (ClassFormatError)
   1.260 +            Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
   1.261 +            itfs.add(samIntf);
   1.262 +            for (Class<?> markerInterface : markerInterfaces) {
   1.263 +                itfs.add(markerInterface.getName().replace('.', '/'));
   1.264 +                accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
   1.265 +            }
   1.266 +            interfaces = itfs.toArray(new String[itfs.size()]);
   1.267 +        }
   1.268 +
   1.269 +        cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
   1.270 +                 lambdaClassName, null,
   1.271 +                 JAVA_LANG_OBJECT, interfaces);
   1.272 +
   1.273 +        // Generate final fields to be filled in by constructor
   1.274 +        for (int i = 0; i < argDescs.length; i++) {
   1.275 +            FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
   1.276 +                                            argNames[i],
   1.277 +                                            argDescs[i],
   1.278 +                                            null, null);
   1.279 +            fv.visitEnd();
   1.280 +        }
   1.281 +
   1.282 +        generateConstructor();
   1.283 +
   1.284 +        if (invokedType.parameterCount() != 0) {
   1.285 +            generateFactory();
   1.286 +        }
   1.287 +
   1.288 +        // Forward the SAM method
   1.289 +        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
   1.290 +                                          samMethodType.toMethodDescriptorString(), null, null);
   1.291 +        new ForwardingMethodGenerator(mv).generate(samMethodType);
   1.292 +
   1.293 +        // Forward the bridges
   1.294 +        if (additionalBridges != null) {
   1.295 +            for (MethodType mt : additionalBridges) {
   1.296 +                mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
   1.297 +                                    mt.toMethodDescriptorString(), null, null);
   1.298 +                new ForwardingMethodGenerator(mv).generate(mt);
   1.299 +            }
   1.300 +        }
   1.301 +
   1.302 +        if (isSerializable)
   1.303 +            generateSerializationFriendlyMethods();
   1.304 +        else if (accidentallySerializable)
   1.305 +            generateSerializationHostileMethods();
   1.306 +
   1.307 +        cw.visitEnd();
   1.308 +
   1.309 +        // Define the generated class in this VM.
   1.310 +
   1.311 +        final byte[] classBytes = cw.toByteArray();
   1.312 +
   1.313 +        // If requested, dump out to a file for debugging purposes
   1.314 +        if (dumper != null) {
   1.315 +            AccessController.doPrivileged(new PrivilegedAction<Void>() {
   1.316 +                @Override
   1.317 +                public Void run() {
   1.318 +                    dumper.dumpClass(lambdaClassName, classBytes);
   1.319 +                    return null;
   1.320 +                }
   1.321 +            }, null,
   1.322 +            new FilePermission("<<ALL FILES>>", "read, write"),
   1.323 +            // createDirectories may need it
   1.324 +            new PropertyPermission("user.dir", "read"));
   1.325 +        }
   1.326 +
   1.327 +        return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
   1.328 +    }
   1.329 +
   1.330 +    /**
   1.331 +     * Generate the factory method for the class
   1.332 +     */
   1.333 +    private void generateFactory() {
   1.334 +        MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
   1.335 +        m.visitCode();
   1.336 +        m.visitTypeInsn(NEW, lambdaClassName);
   1.337 +        m.visitInsn(Opcodes.DUP);
   1.338 +        int parameterCount = invokedType.parameterCount();
   1.339 +        for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
   1.340 +            Class<?> argType = invokedType.parameterType(typeIndex);
   1.341 +            m.visitVarInsn(getLoadOpcode(argType), varIndex);
   1.342 +            varIndex += getParameterSize(argType);
   1.343 +        }
   1.344 +        m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString());
   1.345 +        m.visitInsn(ARETURN);
   1.346 +        m.visitMaxs(-1, -1);
   1.347 +        m.visitEnd();
   1.348 +    }
   1.349 +
   1.350 +    /**
   1.351 +     * Generate the constructor for the class
   1.352 +     */
   1.353 +    private void generateConstructor() {
   1.354 +        // Generate constructor
   1.355 +        MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
   1.356 +                                            constructorType.toMethodDescriptorString(), null, null);
   1.357 +        ctor.visitCode();
   1.358 +        ctor.visitVarInsn(ALOAD, 0);
   1.359 +        ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
   1.360 +                             METHOD_DESCRIPTOR_VOID);
   1.361 +        int parameterCount = invokedType.parameterCount();
   1.362 +        for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
   1.363 +            ctor.visitVarInsn(ALOAD, 0);
   1.364 +            Class<?> argType = invokedType.parameterType(i);
   1.365 +            ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
   1.366 +            lvIndex += getParameterSize(argType);
   1.367 +            ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
   1.368 +        }
   1.369 +        ctor.visitInsn(RETURN);
   1.370 +        // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   1.371 +        ctor.visitMaxs(-1, -1);
   1.372 +        ctor.visitEnd();
   1.373 +    }
   1.374 +
   1.375 +    /**
   1.376 +     * Generate a writeReplace method that supports serialization
   1.377 +     */
   1.378 +    private void generateSerializationFriendlyMethods() {
   1.379 +        TypeConvertingMethodAdapter mv
   1.380 +                = new TypeConvertingMethodAdapter(
   1.381 +                    cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   1.382 +                    NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
   1.383 +                    null, null));
   1.384 +
   1.385 +        mv.visitCode();
   1.386 +        mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
   1.387 +        mv.visitInsn(DUP);
   1.388 +        mv.visitLdcInsn(Type.getType(targetClass));
   1.389 +        mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
   1.390 +        mv.visitLdcInsn(samMethodName);
   1.391 +        mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
   1.392 +        mv.visitLdcInsn(implInfo.getReferenceKind());
   1.393 +        mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
   1.394 +        mv.visitLdcInsn(implInfo.getName());
   1.395 +        mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
   1.396 +        mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
   1.397 +        mv.iconst(argDescs.length);
   1.398 +        mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
   1.399 +        for (int i = 0; i < argDescs.length; i++) {
   1.400 +            mv.visitInsn(DUP);
   1.401 +            mv.iconst(i);
   1.402 +            mv.visitVarInsn(ALOAD, 0);
   1.403 +            mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
   1.404 +            mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
   1.405 +            mv.visitInsn(AASTORE);
   1.406 +        }
   1.407 +        mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
   1.408 +                DESCR_CTOR_SERIALIZED_LAMBDA);
   1.409 +        mv.visitInsn(ARETURN);
   1.410 +        // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   1.411 +        mv.visitMaxs(-1, -1);
   1.412 +        mv.visitEnd();
   1.413 +    }
   1.414 +
   1.415 +    /**
   1.416 +     * Generate a readObject/writeObject method that is hostile to serialization
   1.417 +     */
   1.418 +    private void generateSerializationHostileMethods() {
   1.419 +        MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   1.420 +                                          NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
   1.421 +                                          null, SER_HOSTILE_EXCEPTIONS);
   1.422 +        mv.visitCode();
   1.423 +        mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
   1.424 +        mv.visitInsn(DUP);
   1.425 +        mv.visitLdcInsn("Non-serializable lambda");
   1.426 +        mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
   1.427 +                           DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
   1.428 +        mv.visitInsn(ATHROW);
   1.429 +        mv.visitMaxs(-1, -1);
   1.430 +        mv.visitEnd();
   1.431 +
   1.432 +        mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   1.433 +                            NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
   1.434 +                            null, SER_HOSTILE_EXCEPTIONS);
   1.435 +        mv.visitCode();
   1.436 +        mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
   1.437 +        mv.visitInsn(DUP);
   1.438 +        mv.visitLdcInsn("Non-serializable lambda");
   1.439 +        mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
   1.440 +                           DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
   1.441 +        mv.visitInsn(ATHROW);
   1.442 +        mv.visitMaxs(-1, -1);
   1.443 +        mv.visitEnd();
   1.444 +    }
   1.445 +
   1.446 +    /**
   1.447 +     * This class generates a method body which calls the lambda implementation
   1.448 +     * method, converting arguments, as needed.
   1.449 +     */
   1.450 +    private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
   1.451 +
   1.452 +        ForwardingMethodGenerator(MethodVisitor mv) {
   1.453 +            super(mv);
   1.454 +        }
   1.455 +
   1.456 +        void generate(MethodType methodType) {
   1.457 +            visitCode();
   1.458 +
   1.459 +            if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
   1.460 +                visitTypeInsn(NEW, implMethodClassName);
   1.461 +                visitInsn(DUP);
   1.462 +            }
   1.463 +            for (int i = 0; i < argNames.length; i++) {
   1.464 +                visitVarInsn(ALOAD, 0);
   1.465 +                visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
   1.466 +            }
   1.467 +
   1.468 +            convertArgumentTypes(methodType);
   1.469 +
   1.470 +            // Invoke the method we want to forward to
   1.471 +            visitMethodInsn(invocationOpcode(), implMethodClassName,
   1.472 +                            implMethodName, implMethodDesc,
   1.473 +                            implDefiningClass.isInterface());
   1.474 +
   1.475 +            // Convert the return value (if any) and return it
   1.476 +            // Note: if adapting from non-void to void, the 'return'
   1.477 +            // instruction will pop the unneeded result
   1.478 +            Class<?> samReturnClass = methodType.returnType();
   1.479 +            convertType(implMethodReturnClass, samReturnClass, samReturnClass);
   1.480 +            visitInsn(getReturnOpcode(samReturnClass));
   1.481 +            // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
   1.482 +            visitMaxs(-1, -1);
   1.483 +            visitEnd();
   1.484 +        }
   1.485 +
   1.486 +        private void convertArgumentTypes(MethodType samType) {
   1.487 +            int lvIndex = 0;
   1.488 +            boolean samIncludesReceiver = implIsInstanceMethod &&
   1.489 +                                                   invokedType.parameterCount() == 0;
   1.490 +            int samReceiverLength = samIncludesReceiver ? 1 : 0;
   1.491 +            if (samIncludesReceiver) {
   1.492 +                // push receiver
   1.493 +                Class<?> rcvrType = samType.parameterType(0);
   1.494 +                visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
   1.495 +                lvIndex += getParameterSize(rcvrType);
   1.496 +                convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
   1.497 +            }
   1.498 +            int samParametersLength = samType.parameterCount();
   1.499 +            int argOffset = implMethodType.parameterCount() - samParametersLength;
   1.500 +            for (int i = samReceiverLength; i < samParametersLength; i++) {
   1.501 +                Class<?> argType = samType.parameterType(i);
   1.502 +                visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
   1.503 +                lvIndex += getParameterSize(argType);
   1.504 +                convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
   1.505 +            }
   1.506 +        }
   1.507 +
   1.508 +        private int invocationOpcode() throws InternalError {
   1.509 +            switch (implKind) {
   1.510 +                case MethodHandleInfo.REF_invokeStatic:
   1.511 +                    return INVOKESTATIC;
   1.512 +                case MethodHandleInfo.REF_newInvokeSpecial:
   1.513 +                    return INVOKESPECIAL;
   1.514 +                 case MethodHandleInfo.REF_invokeVirtual:
   1.515 +                    return INVOKEVIRTUAL;
   1.516 +                case MethodHandleInfo.REF_invokeInterface:
   1.517 +                    return INVOKEINTERFACE;
   1.518 +                case MethodHandleInfo.REF_invokeSpecial:
   1.519 +                    return INVOKESPECIAL;
   1.520 +                default:
   1.521 +                    throw new InternalError("Unexpected invocation kind: " + implKind);
   1.522 +            }
   1.523 +        }
   1.524 +    }
   1.525 +
   1.526 +    static int getParameterSize(Class<?> c) {
   1.527 +        if (c == Void.TYPE) {
   1.528 +            return 0;
   1.529 +        } else if (c == Long.TYPE || c == Double.TYPE) {
   1.530 +            return 2;
   1.531 +        }
   1.532 +        return 1;
   1.533 +    }
   1.534 +
   1.535 +    static int getLoadOpcode(Class<?> c) {
   1.536 +        if(c == Void.TYPE) {
   1.537 +            throw new InternalError("Unexpected void type of load opcode");
   1.538 +        }
   1.539 +        return ILOAD + getOpcodeOffset(c);
   1.540 +    }
   1.541 +
   1.542 +    static int getReturnOpcode(Class<?> c) {
   1.543 +        if(c == Void.TYPE) {
   1.544 +            return RETURN;
   1.545 +        }
   1.546 +        return IRETURN + getOpcodeOffset(c);
   1.547 +    }
   1.548 +
   1.549 +    private static int getOpcodeOffset(Class<?> c) {
   1.550 +        if (c.isPrimitive()) {
   1.551 +            if (c == Long.TYPE) {
   1.552 +                return 1;
   1.553 +            } else if (c == Float.TYPE) {
   1.554 +                return 2;
   1.555 +            } else if (c == Double.TYPE) {
   1.556 +                return 3;
   1.557 +            }
   1.558 +            return 0;
   1.559 +        } else {
   1.560 +            return 4;
   1.561 +        }
   1.562 +    }
   1.563 +
   1.564 +}