1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import jdk.internal.org.objectweb.asm.*;
  29 import sun.invoke.util.BytecodeDescriptor;
  30 import jdk.internal.misc.Unsafe;
  31 import sun.security.action.GetBooleanAction;
  32 import sun.security.action.GetPropertyAction;
  33 
  34 import java.io.FilePermission;
  35 import java.io.Serializable;
  36 import java.security.AccessController;
  37 import java.security.PrivilegedAction;
  38 import java.util.LinkedHashSet;
  39 import java.util.concurrent.atomic.AtomicInteger;
  40 import java.util.PropertyPermission;
  41 import java.util.Set;
  42 
  43 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  44 
  45 /**
  46  * Lambda metafactory implementation which dynamically creates an
  47  * inner-class-like class per lambda callsite.
  48  *
  49  * @see LambdaMetafactory
  50  */
  51 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  52     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  53 
  54     private static final int CLASSFILE_VERSION = 52;
  55     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  56     private static final String JAVA_LANG_OBJECT = "java/lang/Object";
  57     private static final String NAME_CTOR = "<init>";
  58     private static final String NAME_FACTORY = "get$Lambda";
  59     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
  60 
  61     //Serialization support
  62     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  63     private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
  64     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  65     private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
  66     private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
  67     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  68     private static final String NAME_METHOD_READ_OBJECT = "readObject";
  69     private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
  70 
  71     private static final String DESCR_CLASS = "Ljava/lang/Class;";
  72     private static final String DESCR_STRING = "Ljava/lang/String;";
  73     private static final String DESCR_OBJECT = "Ljava/lang/Object;";
  74     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  75             = "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
  76             + DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
  77 
  78     private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
  79     private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
  80 
  81     private static final String DESCR_HIDDEN = "Ljdk/internal/vm/annotation/Hidden;";
  82 
  83     private static final String[] EMPTY_STRING_ARRAY = new String[0];
  84 
  85     // Used to ensure that each spun class name is unique
  86     private static final AtomicInteger counter = new AtomicInteger(0);
  87 
  88     // For dumping generated classes to disk, for debugging purposes
  89     private static final ProxyClassesDumper dumper;
  90 
  91     // disable optimization that eagerly initializes lambdas
  92     private static final boolean disableEagerInitialization;
  93 
  94     static {
  95         final String dumpKey = "jdk.internal.lambda.dumpProxyClasses";
  96         String path = GetPropertyAction.privilegedGetProperty(dumpKey);
  97         dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
  98 
  99         final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
 100         disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
 101     }
 102 
 103     // See context values in AbstractValidatingLambdaMetafactory
 104     private final String implMethodClassName;        // Name of type containing implementation "CC"
 105     private final String implMethodName;             // Name of implementation method "impl"
 106     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
 107     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
 108     private final ClassWriter cw;                    // ASM class writer
 109     private final String[] argNames;                 // Generated names for the constructor arguments
 110     private final String[] argDescs;                 // Type descriptors for the constructor arguments
 111     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
 112 
 113     /**
 114      * General meta-factory constructor, supporting both standard cases and
 115      * allowing for uncommon options such as serialization or bridging.
 116      *
 117      * @param caller Stacked automatically by VM; represents a lookup context
 118      *               with the accessibility privileges of the caller.
 119      * @param invokedType Stacked automatically by VM; the signature of the
 120      *                    invoked method, which includes the expected static
 121      *                    type of the returned lambda object, and the static
 122      *                    types of the captured arguments for the lambda.  In
 123      *                    the event that the implementation method is an
 124      *                    instance method, the first argument in the invocation
 125      *                    signature will correspond to the receiver.
 126      * @param samMethodName Name of the method in the functional interface to
 127      *                      which the lambda or method reference is being
 128      *                      converted, represented as a String.
 129      * @param samMethodType Type of the method in the functional interface to
 130      *                      which the lambda or method reference is being
 131      *                      converted, represented as a MethodType.
 132      * @param implMethod The implementation method which should be called (with
 133      *                   suitable adaptation of argument types, return types,
 134      *                   and adjustment for captured arguments) when methods of
 135      *                   the resulting functional interface instance are invoked.
 136      * @param instantiatedMethodType The signature of the primary functional
 137      *                               interface method after type variables are
 138      *                               substituted with their instantiation from
 139      *                               the capture site
 140      * @param isSerializable Should the lambda be made serializable?  If set,
 141      *                       either the target type or one of the additional SAM
 142      *                       types must extend {@code Serializable}.
 143      * @param markerInterfaces Additional interfaces which the lambda object
 144      *                       should implement.
 145      * @param additionalBridges Method types for additional signatures to be
 146      *                          bridged to the implementation method
 147      * @throws LambdaConversionException If any of the meta-factory protocol
 148      * invariants are violated
 149      */
 150     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
 151                                        MethodType invokedType,
 152                                        String samMethodName,
 153                                        MethodType samMethodType,
 154                                        MethodHandle implMethod,
 155                                        MethodType instantiatedMethodType,
 156                                        boolean isSerializable,
 157                                        Class<?>[] markerInterfaces,
 158                                        MethodType[] additionalBridges)
 159             throws LambdaConversionException {
 160         super(caller, invokedType, samMethodName, samMethodType,
 161               implMethod, instantiatedMethodType,
 162               isSerializable, markerInterfaces, additionalBridges);
 163         implMethodClassName = implClass.getName().replace('.', '/');
 164         implMethodName = implInfo.getName();
 165         implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
 166         constructorType = invokedType.changeReturnType(Void.TYPE);
 167         lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
 168         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
 169         int parameterCount = invokedType.parameterCount();
 170         if (parameterCount > 0) {
 171             argNames = new String[parameterCount];
 172             argDescs = new String[parameterCount];
 173             for (int i = 0; i < parameterCount; i++) {
 174                 argNames[i] = "arg$" + (i + 1);
 175                 argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
 176             }
 177         } else {
 178             argNames = argDescs = EMPTY_STRING_ARRAY;
 179         }
 180     }
 181 
 182     /**
 183      * Build the CallSite. Generate a class file which implements the functional
 184      * interface, define the class, if there are no parameters create an instance
 185      * of the class which the CallSite will return, otherwise, generate handles
 186      * which will call the class' constructor.
 187      *
 188      * @return a CallSite, which, when invoked, will return an instance of the
 189      * functional interface
 190      * @throws LambdaConversionException If properly formed functional interface
 191      * is not found
 192      */
 193     @Override
 194     CallSite buildCallSite() throws LambdaConversionException {
 195         final Class<?> innerClass = spinInnerClass();
 196         try {
 197             if (!disableEagerInitialization) {
 198                 UNSAFE.ensureClassInitialized(innerClass);
 199             }
 200             MethodHandle lambdaHandle = invokedType.parameterCount() == 0
 201                     ? MethodHandles.Lookup.IMPL_LOOKUP.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD, invokedType.returnType())
 202                     : MethodHandles.Lookup.IMPL_LOOKUP.findStatic(innerClass, NAME_FACTORY, invokedType);
 203 
 204             return new ConstantCallSite(lambdaHandle);
 205         }
 206         catch (ReflectiveOperationException e) {
 207             throw new LambdaConversionException("Exception finding lambda ", e);
 208         }
 209     }
 210 
 211     /**
 212      * Generate a class file which implements the functional
 213      * interface, define and return the class.
 214      *
 215      * @implNote The class that is generated does not include signature
 216      * information for exceptions that may be present on the SAM method.
 217      * This is to reduce classfile size, and is harmless as checked exceptions
 218      * are erased anyway, no one will ever compile against this classfile,
 219      * and we make no guarantees about the reflective properties of lambda
 220      * objects.
 221      *
 222      * @return a Class which implements the functional interface
 223      * @throws LambdaConversionException If properly formed functional interface
 224      * is not found
 225      */
 226     private Class<?> spinInnerClass() throws LambdaConversionException {
 227         String[] interfaces;
 228         String samIntf = samBase.getName().replace('.', '/');
 229         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
 230         if (markerInterfaces.length == 0) {
 231             interfaces = new String[]{samIntf};
 232         } else {
 233             // Assure no duplicate interfaces (ClassFormatError)
 234             Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
 235             itfs.add(samIntf);
 236             for (Class<?> markerInterface : markerInterfaces) {
 237                 itfs.add(markerInterface.getName().replace('.', '/'));
 238                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
 239             }
 240             interfaces = itfs.toArray(new String[itfs.size()]);
 241         }
 242 
 243         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 244                  lambdaClassName, null,
 245                  JAVA_LANG_OBJECT, interfaces);
 246 
 247         // Generate final fields to be filled in by constructor
 248         for (int i = 0; i < argDescs.length; i++) {
 249             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
 250                                             argNames[i],
 251                                             argDescs[i],
 252                                             null, null);
 253             fv.visitEnd();
 254         }
 255 
 256         generateConstructor();
 257         if (invokedType.parameterCount() == 0) {
 258             generateStaticField();
 259         } else {
 260             generateFactory();
 261         }
 262 
 263         // Forward the SAM method
 264         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
 265                                           samMethodType.toMethodDescriptorString(), null, null);
 266         mv.visitAnnotation(DESCR_HIDDEN, true);
 267         new ForwardingMethodGenerator(mv).generate(samMethodType);
 268 
 269         // Forward the bridges
 270         if (additionalBridges != null) {
 271             for (MethodType mt : additionalBridges) {
 272                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
 273                                     mt.toMethodDescriptorString(), null, null);
 274                 mv.visitAnnotation(DESCR_HIDDEN, true);
 275                 new ForwardingMethodGenerator(mv).generate(mt);
 276             }
 277         }
 278 
 279         if (isSerializable)
 280             generateSerializationFriendlyMethods();
 281         else if (accidentallySerializable)
 282             generateSerializationHostileMethods();
 283 
 284         cw.visitEnd();
 285 
 286         // Define the generated class in this VM.
 287 
 288         final byte[] classBytes = cw.toByteArray();
 289 
 290         // If requested, dump out to a file for debugging purposes
 291         if (dumper != null) {
 292             AccessController.doPrivileged(new PrivilegedAction<>() {
 293                 @Override
 294                 public Void run() {
 295                     dumper.dumpClass(lambdaClassName, classBytes);
 296                     return null;
 297                 }
 298             }, null,
 299             new FilePermission("<<ALL FILES>>", "read, write"),
 300             // createDirectories may need it
 301             new PropertyPermission("user.dir", "read"));
 302         }
 303 
 304         return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
 305     }
 306 
 307     /**
 308      * Generate a static field that contains the singleton instance of the lambda
 309      */
 310     private void generateStaticField() {
 311         String lambdaTypeDescriptor = BytecodeDescriptor.unparse(invokedType.returnType());
 312 
 313         // Generate the static final field that holds the lambda singleton
 314         FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, null, null);
 315         fv.visitEnd();
 316 
 317         // Instantiate the lambda and store it to the static final field
 318         MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
 319         clinit.visitCode();
 320 
 321         instantiateLambda(clinit);
 322         clinit.visitFieldInsn(PUTSTATIC, lambdaClassName, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor);
 323 
 324         clinit.visitInsn(RETURN);
 325         clinit.visitMaxs(-1, -1);
 326         clinit.visitEnd();
 327     }
 328 
 329     /**
 330      * Generate the factory method for the class
 331      */
 332     private void generateFactory() {
 333         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
 334         m.visitCode();
 335 
 336         instantiateLambda(m);
 337         m.visitInsn(ARETURN);
 338 
 339         m.visitMaxs(-1, -1);
 340         m.visitEnd();
 341     }
 342 
 343     private void instantiateLambda(MethodVisitor m) {
 344         m.visitTypeInsn(NEW, lambdaClassName);
 345         m.visitInsn(Opcodes.DUP);
 346         for (int typeIndex = 0, varIndex = 0; typeIndex < invokedType.parameterCount(); typeIndex++) {
 347             Class<?> argType = invokedType.parameterType(typeIndex);
 348             m.visitVarInsn(getLoadOpcode(argType), varIndex);
 349             varIndex += getParameterSize(argType);
 350         }
 351         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
 352     }
 353 
 354     /**
 355      * Generate the constructor for the class
 356      */
 357     private void generateConstructor() {
 358         // Generate constructor
 359         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
 360                                             constructorType.toMethodDescriptorString(), null, null);
 361         ctor.visitCode();
 362         ctor.visitVarInsn(ALOAD, 0);
 363         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
 364                              METHOD_DESCRIPTOR_VOID, false);
 365         int parameterCount = invokedType.parameterCount();
 366         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
 367             ctor.visitVarInsn(ALOAD, 0);
 368             Class<?> argType = invokedType.parameterType(i);
 369             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
 370             lvIndex += getParameterSize(argType);
 371             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
 372         }
 373         ctor.visitInsn(RETURN);
 374         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 375         ctor.visitMaxs(-1, -1);
 376         ctor.visitEnd();
 377     }
 378 
 379     /**
 380      * Generate a writeReplace method that supports serialization
 381      */
 382     private void generateSerializationFriendlyMethods() {
 383         TypeConvertingMethodAdapter mv
 384                 = new TypeConvertingMethodAdapter(
 385                     cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
 386                     NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
 387                     null, null));
 388 
 389         mv.visitCode();
 390         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
 391         mv.visitInsn(DUP);
 392         mv.visitLdcInsn(Type.getType(targetClass));
 393         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
 394         mv.visitLdcInsn(samMethodName);
 395         mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
 396         mv.visitLdcInsn(implInfo.getReferenceKind());
 397         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
 398         mv.visitLdcInsn(implInfo.getName());
 399         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
 400         mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
 401         mv.iconst(argDescs.length);
 402         mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
 403         for (int i = 0; i < argDescs.length; i++) {
 404             mv.visitInsn(DUP);
 405             mv.iconst(i);
 406             mv.visitVarInsn(ALOAD, 0);
 407             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
 408             mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
 409             mv.visitInsn(AASTORE);
 410         }
 411         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
 412                 DESCR_CTOR_SERIALIZED_LAMBDA, false);
 413         mv.visitInsn(ARETURN);
 414         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 415         mv.visitMaxs(-1, -1);
 416         mv.visitEnd();
 417     }
 418 
 419     /**
 420      * Generate a readObject/writeObject method that is hostile to serialization
 421      */
 422     private void generateSerializationHostileMethods() {
 423         MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
 424                                           NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
 425                                           null, SER_HOSTILE_EXCEPTIONS);
 426         mv.visitCode();
 427         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
 428         mv.visitInsn(DUP);
 429         mv.visitLdcInsn("Non-serializable lambda");
 430         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
 431                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
 432         mv.visitInsn(ATHROW);
 433         mv.visitMaxs(-1, -1);
 434         mv.visitEnd();
 435 
 436         mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
 437                             NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
 438                             null, SER_HOSTILE_EXCEPTIONS);
 439         mv.visitCode();
 440         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
 441         mv.visitInsn(DUP);
 442         mv.visitLdcInsn("Non-serializable lambda");
 443         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
 444                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
 445         mv.visitInsn(ATHROW);
 446         mv.visitMaxs(-1, -1);
 447         mv.visitEnd();
 448     }
 449 
 450     /**
 451      * This class generates a method body which calls the lambda implementation
 452      * method, converting arguments, as needed.
 453      */
 454     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
 455 
 456         ForwardingMethodGenerator(MethodVisitor mv) {
 457             super(mv);
 458         }
 459 
 460         void generate(MethodType methodType) {
 461             visitCode();
 462 
 463             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
 464                 visitTypeInsn(NEW, implMethodClassName);
 465                 visitInsn(DUP);
 466             }
 467             for (int i = 0; i < argNames.length; i++) {
 468                 visitVarInsn(ALOAD, 0);
 469                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
 470             }
 471 
 472             convertArgumentTypes(methodType);
 473 
 474             // Invoke the method we want to forward to
 475             visitMethodInsn(invocationOpcode(), implMethodClassName,
 476                             implMethodName, implMethodDesc,
 477                             implClass.isInterface());
 478 
 479             // Convert the return value (if any) and return it
 480             // Note: if adapting from non-void to void, the 'return'
 481             // instruction will pop the unneeded result
 482             Class<?> implReturnClass = implMethodType.returnType();
 483             Class<?> samReturnClass = methodType.returnType();
 484             convertType(implReturnClass, samReturnClass, samReturnClass);
 485             visitInsn(getReturnOpcode(samReturnClass));
 486             // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
 487             visitMaxs(-1, -1);
 488             visitEnd();
 489         }
 490 
 491         private void convertArgumentTypes(MethodType samType) {
 492             int lvIndex = 0;
 493             int samParametersLength = samType.parameterCount();
 494             int captureArity = invokedType.parameterCount();
 495             for (int i = 0; i < samParametersLength; i++) {
 496                 Class<?> argType = samType.parameterType(i);
 497                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
 498                 lvIndex += getParameterSize(argType);
 499                 convertType(argType, implMethodType.parameterType(captureArity + i), instantiatedMethodType.parameterType(i));
 500             }
 501         }
 502 
 503         private int invocationOpcode() throws InternalError {
 504             switch (implKind) {
 505                 case MethodHandleInfo.REF_invokeStatic:
 506                     return INVOKESTATIC;
 507                 case MethodHandleInfo.REF_newInvokeSpecial:
 508                     return INVOKESPECIAL;
 509                  case MethodHandleInfo.REF_invokeVirtual:
 510                     return INVOKEVIRTUAL;
 511                 case MethodHandleInfo.REF_invokeInterface:
 512                     return INVOKEINTERFACE;
 513                 case MethodHandleInfo.REF_invokeSpecial:
 514                     return INVOKESPECIAL;
 515                 default:
 516                     throw new InternalError("Unexpected invocation kind: " + implKind);
 517             }
 518         }
 519     }
 520 
 521     static int getParameterSize(Class<?> c) {
 522         if (c == Void.TYPE) {
 523             return 0;
 524         } else if (c == Long.TYPE || c == Double.TYPE) {
 525             return 2;
 526         }
 527         return 1;
 528     }
 529 
 530     static int getLoadOpcode(Class<?> c) {
 531         if(c == Void.TYPE) {
 532             throw new InternalError("Unexpected void type of load opcode");
 533         }
 534         return ILOAD + getOpcodeOffset(c);
 535     }
 536 
 537     static int getReturnOpcode(Class<?> c) {
 538         if(c == Void.TYPE) {
 539             return RETURN;
 540         }
 541         return IRETURN + getOpcodeOffset(c);
 542     }
 543 
 544     private static int getOpcodeOffset(Class<?> c) {
 545         if (c.isPrimitive()) {
 546             if (c == Long.TYPE) {
 547                 return 1;
 548             } else if (c == Float.TYPE) {
 549                 return 2;
 550             } else if (c == Double.TYPE) {
 551                 return 3;
 552             }
 553             return 0;
 554         } else {
 555             return 4;
 556         }
 557     }
 558 
 559 }