rt/emul/compact/src/main/java/java/lang/invoke/InnerClassLambdaMetafactory.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 11:11:13 +0200
branchjdk8-b132
changeset 1646 c880a8a8803b
child 1651 5c990ed353e9
permissions -rw-r--r--
Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
     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 sun.misc.Unsafe;
    31 import sun.security.action.GetPropertyAction;
    32 
    33 import java.io.FilePermission;
    34 import java.io.Serializable;
    35 import java.lang.reflect.Constructor;
    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 
    60     //Serialization support
    61     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
    62     private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
    63     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
    64     private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
    65     private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
    66     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
    67     private static final String NAME_METHOD_READ_OBJECT = "readObject";
    68     private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
    69     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
    70             = MethodType.methodType(void.class,
    71                                     Class.class,
    72                                     String.class, String.class, String.class,
    73                                     int.class, String.class, String.class, String.class,
    74                                     String.class,
    75                                     Object[].class).toMethodDescriptorString();
    76     private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION
    77             = MethodType.methodType(void.class, String.class).toMethodDescriptorString();
    78     private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
    79 
    80 
    81     private static final String[] EMPTY_STRING_ARRAY = new String[0];
    82 
    83     // Used to ensure that each spun class name is unique
    84     private static final AtomicInteger counter = new AtomicInteger(0);
    85 
    86     // For dumping generated classes to disk, for debugging purposes
    87     private static final ProxyClassesDumper dumper;
    88 
    89     static {
    90         final String key = "jdk.internal.lambda.dumpProxyClasses";
    91         String path = AccessController.doPrivileged(
    92                 new GetPropertyAction(key), null,
    93                 new PropertyPermission(key , "read"));
    94         dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
    95     }
    96 
    97     // See context values in AbstractValidatingLambdaMetafactory
    98     private final String implMethodClassName;        // Name of type containing implementation "CC"
    99     private final String implMethodName;             // Name of implementation method "impl"
   100     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
   101     private final Class<?> implMethodReturnClass;    // class for implementaion method return type "Ljava/lang/String;"
   102     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
   103     private final ClassWriter cw;                    // ASM class writer
   104     private final String[] argNames;                 // Generated names for the constructor arguments
   105     private final String[] argDescs;                 // Type descriptors for the constructor arguments
   106     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
   107 
   108     /**
   109      * General meta-factory constructor, supporting both standard cases and
   110      * allowing for uncommon options such as serialization or bridging.
   111      *
   112      * @param caller Stacked automatically by VM; represents a lookup context
   113      *               with the accessibility privileges of the caller.
   114      * @param invokedType Stacked automatically by VM; the signature of the
   115      *                    invoked method, which includes the expected static
   116      *                    type of the returned lambda object, and the static
   117      *                    types of the captured arguments for the lambda.  In
   118      *                    the event that the implementation method is an
   119      *                    instance method, the first argument in the invocation
   120      *                    signature will correspond to the receiver.
   121      * @param samMethodName Name of the method in the functional interface to
   122      *                      which the lambda or method reference is being
   123      *                      converted, represented as a String.
   124      * @param samMethodType Type of the method in the functional interface to
   125      *                      which the lambda or method reference is being
   126      *                      converted, represented as a MethodType.
   127      * @param implMethod The implementation method which should be called (with
   128      *                   suitable adaptation of argument types, return types,
   129      *                   and adjustment for captured arguments) when methods of
   130      *                   the resulting functional interface instance are invoked.
   131      * @param instantiatedMethodType The signature of the primary functional
   132      *                               interface method after type variables are
   133      *                               substituted with their instantiation from
   134      *                               the capture site
   135      * @param isSerializable Should the lambda be made serializable?  If set,
   136      *                       either the target type or one of the additional SAM
   137      *                       types must extend {@code Serializable}.
   138      * @param markerInterfaces Additional interfaces which the lambda object
   139      *                       should implement.
   140      * @param additionalBridges Method types for additional signatures to be
   141      *                          bridged to the implementation method
   142      * @throws LambdaConversionException If any of the meta-factory protocol
   143      * invariants are violated
   144      */
   145     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
   146                                        MethodType invokedType,
   147                                        String samMethodName,
   148                                        MethodType samMethodType,
   149                                        MethodHandle implMethod,
   150                                        MethodType instantiatedMethodType,
   151                                        boolean isSerializable,
   152                                        Class<?>[] markerInterfaces,
   153                                        MethodType[] additionalBridges)
   154             throws LambdaConversionException {
   155         super(caller, invokedType, samMethodName, samMethodType,
   156               implMethod, instantiatedMethodType,
   157               isSerializable, markerInterfaces, additionalBridges);
   158         implMethodClassName = implDefiningClass.getName().replace('.', '/');
   159         implMethodName = implInfo.getName();
   160         implMethodDesc = implMethodType.toMethodDescriptorString();
   161         implMethodReturnClass = (implKind == MethodHandleInfo.REF_newInvokeSpecial)
   162                 ? implDefiningClass
   163                 : implMethodType.returnType();
   164         constructorType = invokedType.changeReturnType(Void.TYPE);
   165         lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
   166         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
   167         int parameterCount = invokedType.parameterCount();
   168         if (parameterCount > 0) {
   169             argNames = new String[parameterCount];
   170             argDescs = new String[parameterCount];
   171             for (int i = 0; i < parameterCount; i++) {
   172                 argNames[i] = "arg$" + (i + 1);
   173                 argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
   174             }
   175         } else {
   176             argNames = argDescs = EMPTY_STRING_ARRAY;
   177         }
   178     }
   179 
   180     /**
   181      * Build the CallSite. Generate a class file which implements the functional
   182      * interface, define the class, if there are no parameters create an instance
   183      * of the class which the CallSite will return, otherwise, generate handles
   184      * which will call the class' constructor.
   185      *
   186      * @return a CallSite, which, when invoked, will return an instance of the
   187      * functional interface
   188      * @throws ReflectiveOperationException
   189      * @throws LambdaConversionException If properly formed functional interface
   190      * is not found
   191      */
   192     @Override
   193     CallSite buildCallSite() throws LambdaConversionException {
   194         final Class<?> innerClass = spinInnerClass();
   195         if (invokedType.parameterCount() == 0) {
   196             final Constructor[] ctrs = AccessController.doPrivileged(
   197                     new PrivilegedAction<Constructor[]>() {
   198                 @Override
   199                 public Constructor[] run() {
   200                     Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
   201                     if (ctrs.length == 1) {
   202                         // The lambda implementing inner class constructor is private, set
   203                         // it accessible (by us) before creating the constant sole instance
   204                         ctrs[0].setAccessible(true);
   205                     }
   206                     return ctrs;
   207                 }
   208                     });
   209             if (ctrs.length != 1) {
   210                 throw new LambdaConversionException("Expected one lambda constructor for "
   211                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
   212             }
   213 
   214             try {
   215                 Object inst = ctrs[0].newInstance();
   216                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
   217             }
   218             catch (ReflectiveOperationException e) {
   219                 throw new LambdaConversionException("Exception instantiating lambda object", e);
   220             }
   221         } else {
   222             try {
   223                 UNSAFE.ensureClassInitialized(innerClass);
   224                 return new ConstantCallSite(
   225                         MethodHandles.Lookup.IMPL_LOOKUP
   226                              .findStatic(innerClass, NAME_FACTORY, invokedType));
   227             }
   228             catch (ReflectiveOperationException e) {
   229                 throw new LambdaConversionException("Exception finding constructor", e);
   230             }
   231         }
   232     }
   233 
   234     /**
   235      * Generate a class file which implements the functional
   236      * interface, define and return the class.
   237      *
   238      * @implNote The class that is generated does not include signature
   239      * information for exceptions that may be present on the SAM method.
   240      * This is to reduce classfile size, and is harmless as checked exceptions
   241      * are erased anyway, no one will ever compile against this classfile,
   242      * and we make no guarantees about the reflective properties of lambda
   243      * objects.
   244      *
   245      * @return a Class which implements the functional interface
   246      * @throws LambdaConversionException If properly formed functional interface
   247      * is not found
   248      */
   249     private Class<?> spinInnerClass() throws LambdaConversionException {
   250         String[] interfaces;
   251         String samIntf = samBase.getName().replace('.', '/');
   252         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
   253         if (markerInterfaces.length == 0) {
   254             interfaces = new String[]{samIntf};
   255         } else {
   256             // Assure no duplicate interfaces (ClassFormatError)
   257             Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
   258             itfs.add(samIntf);
   259             for (Class<?> markerInterface : markerInterfaces) {
   260                 itfs.add(markerInterface.getName().replace('.', '/'));
   261                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
   262             }
   263             interfaces = itfs.toArray(new String[itfs.size()]);
   264         }
   265 
   266         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
   267                  lambdaClassName, null,
   268                  JAVA_LANG_OBJECT, interfaces);
   269 
   270         // Generate final fields to be filled in by constructor
   271         for (int i = 0; i < argDescs.length; i++) {
   272             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
   273                                             argNames[i],
   274                                             argDescs[i],
   275                                             null, null);
   276             fv.visitEnd();
   277         }
   278 
   279         generateConstructor();
   280 
   281         if (invokedType.parameterCount() != 0) {
   282             generateFactory();
   283         }
   284 
   285         // Forward the SAM method
   286         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
   287                                           samMethodType.toMethodDescriptorString(), null, null);
   288         new ForwardingMethodGenerator(mv).generate(samMethodType);
   289 
   290         // Forward the bridges
   291         if (additionalBridges != null) {
   292             for (MethodType mt : additionalBridges) {
   293                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
   294                                     mt.toMethodDescriptorString(), null, null);
   295                 new ForwardingMethodGenerator(mv).generate(mt);
   296             }
   297         }
   298 
   299         if (isSerializable)
   300             generateSerializationFriendlyMethods();
   301         else if (accidentallySerializable)
   302             generateSerializationHostileMethods();
   303 
   304         cw.visitEnd();
   305 
   306         // Define the generated class in this VM.
   307 
   308         final byte[] classBytes = cw.toByteArray();
   309 
   310         // If requested, dump out to a file for debugging purposes
   311         if (dumper != null) {
   312             AccessController.doPrivileged(new PrivilegedAction<Void>() {
   313                 @Override
   314                 public Void run() {
   315                     dumper.dumpClass(lambdaClassName, classBytes);
   316                     return null;
   317                 }
   318             }, null,
   319             new FilePermission("<<ALL FILES>>", "read, write"),
   320             // createDirectories may need it
   321             new PropertyPermission("user.dir", "read"));
   322         }
   323 
   324         return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
   325     }
   326 
   327     /**
   328      * Generate the factory method for the class
   329      */
   330     private void generateFactory() {
   331         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
   332         m.visitCode();
   333         m.visitTypeInsn(NEW, lambdaClassName);
   334         m.visitInsn(Opcodes.DUP);
   335         int parameterCount = invokedType.parameterCount();
   336         for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
   337             Class<?> argType = invokedType.parameterType(typeIndex);
   338             m.visitVarInsn(getLoadOpcode(argType), varIndex);
   339             varIndex += getParameterSize(argType);
   340         }
   341         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString());
   342         m.visitInsn(ARETURN);
   343         m.visitMaxs(-1, -1);
   344         m.visitEnd();
   345     }
   346 
   347     /**
   348      * Generate the constructor for the class
   349      */
   350     private void generateConstructor() {
   351         // Generate constructor
   352         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
   353                                             constructorType.toMethodDescriptorString(), null, null);
   354         ctor.visitCode();
   355         ctor.visitVarInsn(ALOAD, 0);
   356         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
   357                              METHOD_DESCRIPTOR_VOID);
   358         int parameterCount = invokedType.parameterCount();
   359         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
   360             ctor.visitVarInsn(ALOAD, 0);
   361             Class<?> argType = invokedType.parameterType(i);
   362             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
   363             lvIndex += getParameterSize(argType);
   364             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
   365         }
   366         ctor.visitInsn(RETURN);
   367         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   368         ctor.visitMaxs(-1, -1);
   369         ctor.visitEnd();
   370     }
   371 
   372     /**
   373      * Generate a writeReplace method that supports serialization
   374      */
   375     private void generateSerializationFriendlyMethods() {
   376         TypeConvertingMethodAdapter mv
   377                 = new TypeConvertingMethodAdapter(
   378                     cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   379                     NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
   380                     null, null));
   381 
   382         mv.visitCode();
   383         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
   384         mv.visitInsn(DUP);
   385         mv.visitLdcInsn(Type.getType(targetClass));
   386         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
   387         mv.visitLdcInsn(samMethodName);
   388         mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
   389         mv.visitLdcInsn(implInfo.getReferenceKind());
   390         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
   391         mv.visitLdcInsn(implInfo.getName());
   392         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
   393         mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
   394         mv.iconst(argDescs.length);
   395         mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
   396         for (int i = 0; i < argDescs.length; i++) {
   397             mv.visitInsn(DUP);
   398             mv.iconst(i);
   399             mv.visitVarInsn(ALOAD, 0);
   400             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
   401             mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
   402             mv.visitInsn(AASTORE);
   403         }
   404         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
   405                 DESCR_CTOR_SERIALIZED_LAMBDA);
   406         mv.visitInsn(ARETURN);
   407         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   408         mv.visitMaxs(-1, -1);
   409         mv.visitEnd();
   410     }
   411 
   412     /**
   413      * Generate a readObject/writeObject method that is hostile to serialization
   414      */
   415     private void generateSerializationHostileMethods() {
   416         MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   417                                           NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
   418                                           null, SER_HOSTILE_EXCEPTIONS);
   419         mv.visitCode();
   420         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
   421         mv.visitInsn(DUP);
   422         mv.visitLdcInsn("Non-serializable lambda");
   423         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
   424                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
   425         mv.visitInsn(ATHROW);
   426         mv.visitMaxs(-1, -1);
   427         mv.visitEnd();
   428 
   429         mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
   430                             NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
   431                             null, SER_HOSTILE_EXCEPTIONS);
   432         mv.visitCode();
   433         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
   434         mv.visitInsn(DUP);
   435         mv.visitLdcInsn("Non-serializable lambda");
   436         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
   437                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION);
   438         mv.visitInsn(ATHROW);
   439         mv.visitMaxs(-1, -1);
   440         mv.visitEnd();
   441     }
   442 
   443     /**
   444      * This class generates a method body which calls the lambda implementation
   445      * method, converting arguments, as needed.
   446      */
   447     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
   448 
   449         ForwardingMethodGenerator(MethodVisitor mv) {
   450             super(mv);
   451         }
   452 
   453         void generate(MethodType methodType) {
   454             visitCode();
   455 
   456             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
   457                 visitTypeInsn(NEW, implMethodClassName);
   458                 visitInsn(DUP);
   459             }
   460             for (int i = 0; i < argNames.length; i++) {
   461                 visitVarInsn(ALOAD, 0);
   462                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
   463             }
   464 
   465             convertArgumentTypes(methodType);
   466 
   467             // Invoke the method we want to forward to
   468             visitMethodInsn(invocationOpcode(), implMethodClassName,
   469                             implMethodName, implMethodDesc,
   470                             implDefiningClass.isInterface());
   471 
   472             // Convert the return value (if any) and return it
   473             // Note: if adapting from non-void to void, the 'return'
   474             // instruction will pop the unneeded result
   475             Class<?> samReturnClass = methodType.returnType();
   476             convertType(implMethodReturnClass, samReturnClass, samReturnClass);
   477             visitInsn(getReturnOpcode(samReturnClass));
   478             // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
   479             visitMaxs(-1, -1);
   480             visitEnd();
   481         }
   482 
   483         private void convertArgumentTypes(MethodType samType) {
   484             int lvIndex = 0;
   485             boolean samIncludesReceiver = implIsInstanceMethod &&
   486                                                    invokedType.parameterCount() == 0;
   487             int samReceiverLength = samIncludesReceiver ? 1 : 0;
   488             if (samIncludesReceiver) {
   489                 // push receiver
   490                 Class<?> rcvrType = samType.parameterType(0);
   491                 visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
   492                 lvIndex += getParameterSize(rcvrType);
   493                 convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
   494             }
   495             int samParametersLength = samType.parameterCount();
   496             int argOffset = implMethodType.parameterCount() - samParametersLength;
   497             for (int i = samReceiverLength; i < samParametersLength; i++) {
   498                 Class<?> argType = samType.parameterType(i);
   499                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
   500                 lvIndex += getParameterSize(argType);
   501                 convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
   502             }
   503         }
   504 
   505         private int invocationOpcode() throws InternalError {
   506             switch (implKind) {
   507                 case MethodHandleInfo.REF_invokeStatic:
   508                     return INVOKESTATIC;
   509                 case MethodHandleInfo.REF_newInvokeSpecial:
   510                     return INVOKESPECIAL;
   511                  case MethodHandleInfo.REF_invokeVirtual:
   512                     return INVOKEVIRTUAL;
   513                 case MethodHandleInfo.REF_invokeInterface:
   514                     return INVOKEINTERFACE;
   515                 case MethodHandleInfo.REF_invokeSpecial:
   516                     return INVOKESPECIAL;
   517                 default:
   518                     throw new InternalError("Unexpected invocation kind: " + implKind);
   519             }
   520         }
   521     }
   522 
   523     static int getParameterSize(Class<?> c) {
   524         if (c == Void.TYPE) {
   525             return 0;
   526         } else if (c == Long.TYPE || c == Double.TYPE) {
   527             return 2;
   528         }
   529         return 1;
   530     }
   531 
   532     static int getLoadOpcode(Class<?> c) {
   533         if(c == Void.TYPE) {
   534             throw new InternalError("Unexpected void type of load opcode");
   535         }
   536         return ILOAD + getOpcodeOffset(c);
   537     }
   538 
   539     static int getReturnOpcode(Class<?> c) {
   540         if(c == Void.TYPE) {
   541             return RETURN;
   542         }
   543         return IRETURN + getOpcodeOffset(c);
   544     }
   545 
   546     private static int getOpcodeOffset(Class<?> c) {
   547         if (c.isPrimitive()) {
   548             if (c == Long.TYPE) {
   549                 return 1;
   550             } else if (c == Float.TYPE) {
   551                 return 2;
   552             } else if (c == Double.TYPE) {
   553                 return 3;
   554             }
   555             return 0;
   556         } else {
   557             return 4;
   558         }
   559     }
   560 
   561 }