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