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 +}