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.GetPropertyAction;
32 import sun.security.action.GetBooleanAction;
33 
34 import java.io.FilePermission;
35 import java.io.Serializable;
36 import java.lang.reflect.Constructor;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39 import java.util.LinkedHashSet;
40 import java.util.concurrent.atomic.AtomicInteger;
41 import java.util.PropertyPermission;
42 import java.util.Set;
43 
44 import static jdk.internal.org.objectweb.asm.Opcodes.*;
45 
46 /**
47  * Lambda metafactory implementation which dynamically creates an
48  * inner-class-like class per lambda callsite.
49  *
50  * @see LambdaMetafactory
51  */
52 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
53     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
54 
55     private static final int CLASSFILE_VERSION = 52;
56     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
57     private static final String JAVA_LANG_OBJECT = "java/lang/Object";
58     private static final String NAME_CTOR = "<init>";
59     private static final String NAME_FACTORY = "get$Lambda";
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 
82     private static final String[] EMPTY_STRING_ARRAY = new String[0];
83 
84     // Used to ensure that each spun class name is unique
85     private static final AtomicInteger counter = new AtomicInteger(0);
86 
87     // For dumping generated classes to disk, for debugging purposes
88     private static final ProxyClassesDumper dumper;
89 
90     private static final boolean disableEagerInitialization;
91 
92     static {
93         final String dumpProxyClassesKey = "jdk.internal.lambda.dumpProxyClasses";
94         String dumpPath = GetPropertyAction.privilegedGetProperty(dumpProxyClassesKey);
95         dumper = (null == dumpPath) ? null : ProxyClassesDumper.getInstance(dumpPath);
96 
97         final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
98         disableEagerInitialization = AccessController.doPrivileged(
99             new GetBooleanAction(disableEagerInitializationKey)).booleanValue();
100     }
101 
102     // See context values in AbstractValidatingLambdaMetafactory
103     private final String implMethodClassName;        // Name of type containing implementation "CC"
104     private final String implMethodName;             // Name of implementation method "impl"
105     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
106     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
107     private final ClassWriter cw;                    // ASM class writer
108     private final String[] argNames;                 // Generated names for the constructor arguments
109     private final String[] argDescs;                 // Type descriptors for the constructor arguments
110     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
111 
112     /**
113      * General meta-factory constructor, supporting both standard cases and
114      * allowing for uncommon options such as serialization or bridging.
115      *
116      * @param caller Stacked automatically by VM; represents a lookup context
117      *               with the accessibility privileges of the caller.
118      * @param invokedType Stacked automatically by VM; the signature of the
119      *                    invoked method, which includes the expected static
120      *                    type of the returned lambda object, and the static
121      *                    types of the captured arguments for the lambda.  In
122      *                    the event that the implementation method is an
123      *                    instance method, the first argument in the invocation
124      *                    signature will correspond to the receiver.
125      * @param samMethodName Name of the method in the functional interface to
126      *                      which the lambda or method reference is being
127      *                      converted, represented as a String.
128      * @param samMethodType Type of the method in the functional interface to
129      *                      which the lambda or method reference is being
130      *                      converted, represented as a MethodType.
131      * @param implMethod The implementation method which should be called (with
132      *                   suitable adaptation of argument types, return types,
133      *                   and adjustment for captured arguments) when methods of
134      *                   the resulting functional interface instance are invoked.
135      * @param instantiatedMethodType The signature of the primary functional
136      *                               interface method after type variables are
137      *                               substituted with their instantiation from
138      *                               the capture site
139      * @param isSerializable Should the lambda be made serializable?  If set,
140      *                       either the target type or one of the additional SAM
141      *                       types must extend {@code Serializable}.
142      * @param markerInterfaces Additional interfaces which the lambda object
143      *                       should implement.
144      * @param additionalBridges Method types for additional signatures to be
145      *                          bridged to the implementation method
146      * @throws LambdaConversionException If any of the meta-factory protocol
147      * invariants are violated
148      */
InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, boolean isSerializable, Class<?>[] markerInterfaces, MethodType[] additionalBridges)149     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
150                                        MethodType invokedType,
151                                        String samMethodName,
152                                        MethodType samMethodType,
153                                        MethodHandle implMethod,
154                                        MethodType instantiatedMethodType,
155                                        boolean isSerializable,
156                                        Class<?>[] markerInterfaces,
157                                        MethodType[] additionalBridges)
158             throws LambdaConversionException {
159         super(caller, invokedType, samMethodName, samMethodType,
160               implMethod, instantiatedMethodType,
161               isSerializable, markerInterfaces, additionalBridges);
162         implMethodClassName = implClass.getName().replace('.', '/');
163         implMethodName = implInfo.getName();
164         implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
165         constructorType = invokedType.changeReturnType(Void.TYPE);
166         lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
167         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
168         int parameterCount = invokedType.parameterCount();
169         if (parameterCount > 0) {
170             argNames = new String[parameterCount];
171             argDescs = new String[parameterCount];
172             for (int i = 0; i < parameterCount; i++) {
173                 argNames[i] = "arg$" + (i + 1);
174                 argDescs[i] = BytecodeDescriptor.unparse(invokedType.parameterType(i));
175             }
176         } else {
177             argNames = argDescs = EMPTY_STRING_ARRAY;
178         }
179     }
180 
181     /**
182      * Build the CallSite. Generate a class file which implements the functional
183      * interface, define the class, if there are no parameters create an instance
184      * of the class which the CallSite will return, otherwise, generate handles
185      * which will call the class' constructor.
186      *
187      * @return a CallSite, which, when invoked, will return an instance of the
188      * functional interface
189      * @throws ReflectiveOperationException
190      * @throws LambdaConversionException If properly formed functional interface
191      * is not found
192      */
193     @Override
buildCallSite()194     CallSite buildCallSite() throws LambdaConversionException {
195         final Class<?> innerClass = spinInnerClass();
196         if (invokedType.parameterCount() == 0 && !disableEagerInitialization) {
197             // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance,
198             // unless we've suppressed eager initialization
199             final Constructor<?>[] ctrs = AccessController.doPrivileged(
200                     new PrivilegedAction<>() {
201                 @Override
202                 public Constructor<?>[] run() {
203                     Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
204                     if (ctrs.length == 1) {
205                         // The lambda implementing inner class constructor is private, set
206                         // it accessible (by us) before creating the constant sole instance
207                         ctrs[0].setAccessible(true);
208                     }
209                     return ctrs;
210                 }
211                     });
212             if (ctrs.length != 1) {
213                 throw new LambdaConversionException("Expected one lambda constructor for "
214                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
215             }
216 
217             try {
218                 Object inst = ctrs[0].newInstance();
219                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
220             }
221             catch (ReflectiveOperationException e) {
222                 throw new LambdaConversionException("Exception instantiating lambda object", e);
223             }
224         } else {
225             try {
226                 if (!disableEagerInitialization) {
227                     UNSAFE.ensureClassInitialized(innerClass);
228                 }
229                 return new ConstantCallSite(
230                         MethodHandles.Lookup.IMPL_LOOKUP
231                              .findStatic(innerClass, NAME_FACTORY, invokedType));
232             }
233             catch (ReflectiveOperationException e) {
234                 throw new LambdaConversionException("Exception finding constructor", e);
235             }
236         }
237     }
238 
239     /**
240      * Generate a class file which implements the functional
241      * interface, define and return the class.
242      *
243      * @implNote The class that is generated does not include signature
244      * information for exceptions that may be present on the SAM method.
245      * This is to reduce classfile size, and is harmless as checked exceptions
246      * are erased anyway, no one will ever compile against this classfile,
247      * and we make no guarantees about the reflective properties of lambda
248      * objects.
249      *
250      * @return a Class which implements the functional interface
251      * @throws LambdaConversionException If properly formed functional interface
252      * is not found
253      */
spinInnerClass()254     private Class<?> spinInnerClass() throws LambdaConversionException {
255         String[] interfaces;
256         String samIntf = samBase.getName().replace('.', '/');
257         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(samBase);
258         if (markerInterfaces.length == 0) {
259             interfaces = new String[]{samIntf};
260         } else {
261             // Assure no duplicate interfaces (ClassFormatError)
262             Set<String> itfs = new LinkedHashSet<>(markerInterfaces.length + 1);
263             itfs.add(samIntf);
264             for (Class<?> markerInterface : markerInterfaces) {
265                 itfs.add(markerInterface.getName().replace('.', '/'));
266                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(markerInterface);
267             }
268             interfaces = itfs.toArray(new String[itfs.size()]);
269         }
270 
271         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
272                  lambdaClassName, null,
273                  JAVA_LANG_OBJECT, interfaces);
274 
275         // Generate final fields to be filled in by constructor
276         for (int i = 0; i < argDescs.length; i++) {
277             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
278                                             argNames[i],
279                                             argDescs[i],
280                                             null, null);
281             fv.visitEnd();
282         }
283 
284         generateConstructor();
285 
286         if (invokedType.parameterCount() != 0 || disableEagerInitialization) {
287             generateFactory();
288         }
289 
290         // Forward the SAM method
291         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
292                                           samMethodType.toMethodDescriptorString(), null, null);
293         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
294         new ForwardingMethodGenerator(mv).generate(samMethodType);
295 
296         // Forward the bridges
297         if (additionalBridges != null) {
298             for (MethodType mt : additionalBridges) {
299                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
300                                     mt.toMethodDescriptorString(), null, null);
301                 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
302                 new ForwardingMethodGenerator(mv).generate(mt);
303             }
304         }
305 
306         if (isSerializable)
307             generateSerializationFriendlyMethods();
308         else if (accidentallySerializable)
309             generateSerializationHostileMethods();
310 
311         cw.visitEnd();
312 
313         // Define the generated class in this VM.
314 
315         final byte[] classBytes = cw.toByteArray();
316 
317         // If requested, dump out to a file for debugging purposes
318         if (dumper != null) {
319             AccessController.doPrivileged(new PrivilegedAction<>() {
320                 @Override
321                 public Void run() {
322                     dumper.dumpClass(lambdaClassName, classBytes);
323                     return null;
324                 }
325             }, null,
326             new FilePermission("<<ALL FILES>>", "read, write"),
327             // createDirectories may need it
328             new PropertyPermission("user.dir", "read"));
329         }
330 
331         return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
332     }
333 
334     /**
335      * Generate the factory method for the class
336      */
generateFactory()337     private void generateFactory() {
338         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
339         m.visitCode();
340         m.visitTypeInsn(NEW, lambdaClassName);
341         m.visitInsn(Opcodes.DUP);
342         int parameterCount = invokedType.parameterCount();
343         for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
344             Class<?> argType = invokedType.parameterType(typeIndex);
345             m.visitVarInsn(getLoadOpcode(argType), varIndex);
346             varIndex += getParameterSize(argType);
347         }
348         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
349         m.visitInsn(ARETURN);
350         m.visitMaxs(-1, -1);
351         m.visitEnd();
352     }
353 
354     /**
355      * Generate the constructor for the class
356      */
generateConstructor()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      */
generateSerializationFriendlyMethods()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      */
generateSerializationHostileMethods()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 
ForwardingMethodGenerator(MethodVisitor mv)456         ForwardingMethodGenerator(MethodVisitor mv) {
457             super(mv);
458         }
459 
generate(MethodType methodType)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 
convertArgumentTypes(MethodType samType)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 
invocationOpcode()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 
getParameterSize(Class<?> c)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 
getLoadOpcode(Class<?> c)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 
getReturnOpcode(Class<?> c)537     static int getReturnOpcode(Class<?> c) {
538         if(c == Void.TYPE) {
539             return RETURN;
540         }
541         return IRETURN + getOpcodeOffset(c);
542     }
543 
getOpcodeOffset(Class<?> c)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 }
560