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      */
InnerClassLambdaMetafactory(MethodHandles.Lookup caller, MethodType invokedType, String samMethodName, MethodType samMethodType, MethodHandle implMethod, MethodType instantiatedMethodType, boolean isSerializable, Class<?>[] markerInterfaces, MethodType[] additionalBridges)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
buildCallSite()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      */
spinInnerClass()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         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
289         new ForwardingMethodGenerator(mv).generate(samMethodType);
290 
291         // Forward the bridges
292         if (additionalBridges != null) {
293             for (MethodType mt : additionalBridges) {
294                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
295                                     mt.toMethodDescriptorString(), null, null);
296                 mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
297                 new ForwardingMethodGenerator(mv).generate(mt);
298             }
299         }
300 
301         if (isSerializable)
302             generateSerializationFriendlyMethods();
303         else if (accidentallySerializable)
304             generateSerializationHostileMethods();
305 
306         cw.visitEnd();
307 
308         // Define the generated class in this VM.
309 
310         final byte[] classBytes = cw.toByteArray();
311 
312         // If requested, dump out to a file for debugging purposes
313         if (dumper != null) {
314             AccessController.doPrivileged(new PrivilegedAction<Void>() {
315                 @Override
316                 public Void run() {
317                     dumper.dumpClass(lambdaClassName, classBytes);
318                     return null;
319                 }
320             }, null,
321             new FilePermission("<<ALL FILES>>", "read, write"),
322             // createDirectories may need it
323             new PropertyPermission("user.dir", "read"));
324         }
325 
326         return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
327     }
328 
329     /**
330      * Generate the factory method for the class
331      */
generateFactory()332     private void generateFactory() {
333         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
334         m.visitCode();
335         m.visitTypeInsn(NEW, lambdaClassName);
336         m.visitInsn(Opcodes.DUP);
337         int parameterCount = invokedType.parameterCount();
338         for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
339             Class<?> argType = invokedType.parameterType(typeIndex);
340             m.visitVarInsn(getLoadOpcode(argType), varIndex);
341             varIndex += getParameterSize(argType);
342         }
343         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
344         m.visitInsn(ARETURN);
345         m.visitMaxs(-1, -1);
346         m.visitEnd();
347     }
348 
349     /**
350      * Generate the constructor for the class
351      */
generateConstructor()352     private void generateConstructor() {
353         // Generate constructor
354         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
355                                             constructorType.toMethodDescriptorString(), null, null);
356         ctor.visitCode();
357         ctor.visitVarInsn(ALOAD, 0);
358         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
359                              METHOD_DESCRIPTOR_VOID, false);
360         int parameterCount = invokedType.parameterCount();
361         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
362             ctor.visitVarInsn(ALOAD, 0);
363             Class<?> argType = invokedType.parameterType(i);
364             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
365             lvIndex += getParameterSize(argType);
366             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
367         }
368         ctor.visitInsn(RETURN);
369         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
370         ctor.visitMaxs(-1, -1);
371         ctor.visitEnd();
372     }
373 
374     /**
375      * Generate a writeReplace method that supports serialization
376      */
generateSerializationFriendlyMethods()377     private void generateSerializationFriendlyMethods() {
378         TypeConvertingMethodAdapter mv
379                 = new TypeConvertingMethodAdapter(
380                     cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
381                     NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
382                     null, null));
383 
384         mv.visitCode();
385         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
386         mv.visitInsn(DUP);
387         mv.visitLdcInsn(Type.getType(targetClass));
388         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
389         mv.visitLdcInsn(samMethodName);
390         mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
391         mv.visitLdcInsn(implInfo.getReferenceKind());
392         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
393         mv.visitLdcInsn(implInfo.getName());
394         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
395         mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
396         mv.iconst(argDescs.length);
397         mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
398         for (int i = 0; i < argDescs.length; i++) {
399             mv.visitInsn(DUP);
400             mv.iconst(i);
401             mv.visitVarInsn(ALOAD, 0);
402             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
403             mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
404             mv.visitInsn(AASTORE);
405         }
406         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
407                 DESCR_CTOR_SERIALIZED_LAMBDA, false);
408         mv.visitInsn(ARETURN);
409         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
410         mv.visitMaxs(-1, -1);
411         mv.visitEnd();
412     }
413 
414     /**
415      * Generate a readObject/writeObject method that is hostile to serialization
416      */
generateSerializationHostileMethods()417     private void generateSerializationHostileMethods() {
418         MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
419                                           NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
420                                           null, SER_HOSTILE_EXCEPTIONS);
421         mv.visitCode();
422         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
423         mv.visitInsn(DUP);
424         mv.visitLdcInsn("Non-serializable lambda");
425         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
426                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
427         mv.visitInsn(ATHROW);
428         mv.visitMaxs(-1, -1);
429         mv.visitEnd();
430 
431         mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
432                             NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
433                             null, SER_HOSTILE_EXCEPTIONS);
434         mv.visitCode();
435         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
436         mv.visitInsn(DUP);
437         mv.visitLdcInsn("Non-serializable lambda");
438         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
439                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
440         mv.visitInsn(ATHROW);
441         mv.visitMaxs(-1, -1);
442         mv.visitEnd();
443     }
444 
445     /**
446      * This class generates a method body which calls the lambda implementation
447      * method, converting arguments, as needed.
448      */
449     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
450 
ForwardingMethodGenerator(MethodVisitor mv)451         ForwardingMethodGenerator(MethodVisitor mv) {
452             super(mv);
453         }
454 
generate(MethodType methodType)455         void generate(MethodType methodType) {
456             visitCode();
457 
458             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
459                 visitTypeInsn(NEW, implMethodClassName);
460                 visitInsn(DUP);
461             }
462             for (int i = 0; i < argNames.length; i++) {
463                 visitVarInsn(ALOAD, 0);
464                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
465             }
466 
467             convertArgumentTypes(methodType);
468 
469             // Invoke the method we want to forward to
470             visitMethodInsn(invocationOpcode(), implMethodClassName,
471                             implMethodName, implMethodDesc,
472                             implDefiningClass.isInterface());
473 
474             // Convert the return value (if any) and return it
475             // Note: if adapting from non-void to void, the 'return'
476             // instruction will pop the unneeded result
477             Class<?> samReturnClass = methodType.returnType();
478             convertType(implMethodReturnClass, samReturnClass, samReturnClass);
479             visitInsn(getReturnOpcode(samReturnClass));
480             // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
481             visitMaxs(-1, -1);
482             visitEnd();
483         }
484 
convertArgumentTypes(MethodType samType)485         private void convertArgumentTypes(MethodType samType) {
486             int lvIndex = 0;
487             boolean samIncludesReceiver = implIsInstanceMethod &&
488                                                    invokedType.parameterCount() == 0;
489             int samReceiverLength = samIncludesReceiver ? 1 : 0;
490             if (samIncludesReceiver) {
491                 // push receiver
492                 Class<?> rcvrType = samType.parameterType(0);
493                 visitVarInsn(getLoadOpcode(rcvrType), lvIndex + 1);
494                 lvIndex += getParameterSize(rcvrType);
495                 convertType(rcvrType, implDefiningClass, instantiatedMethodType.parameterType(0));
496             }
497             int samParametersLength = samType.parameterCount();
498             int argOffset = implMethodType.parameterCount() - samParametersLength;
499             for (int i = samReceiverLength; i < samParametersLength; i++) {
500                 Class<?> argType = samType.parameterType(i);
501                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
502                 lvIndex += getParameterSize(argType);
503                 convertType(argType, implMethodType.parameterType(argOffset + i), instantiatedMethodType.parameterType(i));
504             }
505         }
506 
invocationOpcode()507         private int invocationOpcode() throws InternalError {
508             switch (implKind) {
509                 case MethodHandleInfo.REF_invokeStatic:
510                     return INVOKESTATIC;
511                 case MethodHandleInfo.REF_newInvokeSpecial:
512                     return INVOKESPECIAL;
513                  case MethodHandleInfo.REF_invokeVirtual:
514                     return INVOKEVIRTUAL;
515                 case MethodHandleInfo.REF_invokeInterface:
516                     return INVOKEINTERFACE;
517                 case MethodHandleInfo.REF_invokeSpecial:
518                     return INVOKESPECIAL;
519                 default:
520                     throw new InternalError("Unexpected invocation kind: " + implKind);
521             }
522         }
523     }
524 
getParameterSize(Class<?> c)525     static int getParameterSize(Class<?> c) {
526         if (c == Void.TYPE) {
527             return 0;
528         } else if (c == Long.TYPE || c == Double.TYPE) {
529             return 2;
530         }
531         return 1;
532     }
533 
getLoadOpcode(Class<?> c)534     static int getLoadOpcode(Class<?> c) {
535         if(c == Void.TYPE) {
536             throw new InternalError("Unexpected void type of load opcode");
537         }
538         return ILOAD + getOpcodeOffset(c);
539     }
540 
getReturnOpcode(Class<?> c)541     static int getReturnOpcode(Class<?> c) {
542         if(c == Void.TYPE) {
543             return RETURN;
544         }
545         return IRETURN + getOpcodeOffset(c);
546     }
547 
getOpcodeOffset(Class<?> c)548     private static int getOpcodeOffset(Class<?> c) {
549         if (c.isPrimitive()) {
550             if (c == Long.TYPE) {
551                 return 1;
552             } else if (c == Float.TYPE) {
553                 return 2;
554             } else if (c == Double.TYPE) {
555                 return 3;
556             }
557             return 0;
558         } else {
559             return 4;
560         }
561     }
562 
563 }
564