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