1 /*
  2  * Copyright (c) 2012, 2023, 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.misc.PreviewFeatures;
 29 import jdk.internal.misc.CDS;
 30 import jdk.internal.org.objectweb.asm.*;
 31 import jdk.internal.util.ClassFileDumper;
 32 import sun.invoke.util.BytecodeDescriptor;
 33 import sun.invoke.util.VerifyAccess;
 34 import sun.security.action.GetBooleanAction;
 35 
 36 import java.io.Serializable;
 37 import java.lang.constant.ConstantDescs;
 38 import java.lang.reflect.Modifier;
 39 import java.util.HashSet;
 40 import java.util.LinkedHashSet;
 41 import java.util.Set;
 42 
 43 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
 44 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
 45 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
 46 import static java.lang.invoke.MethodType.methodType;
 47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 48 
 49 /**
 50  * Lambda metafactory implementation which dynamically creates an
 51  * inner-class-like class per lambda callsite.
 52  *
 53  * @see LambdaMetafactory
 54  */
 55 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
 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 LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
 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 
 68     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
 69     private static final String NAME_METHOD_READ_OBJECT = "readObject";
 70     private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
 71 
 72     private static final String DESCR_CLASS = "Ljava/lang/Class;";
 73     private static final String DESCR_STRING = "Ljava/lang/String;";
 74     private static final String DESCR_OBJECT = "Ljava/lang/Object;";
 75     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
 76             = "(" + DESCR_CLASS + DESCR_STRING + DESCR_STRING + DESCR_STRING + "I"
 77             + DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
 78 
 79     private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
 80     private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
 81 
 82     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 83 
 84     // For dumping generated classes to disk, for debugging purposes
 85     private static final ClassFileDumper lambdaProxyClassFileDumper;
 86 
 87     private static final boolean disableEagerInitialization;
 88 
 89     // condy to load implMethod from class data
 90     private static final ConstantDynamic implMethodCondy;
 91 
 92     static {
 93         // To dump the lambda proxy classes, set this system property:
 94         //    -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles
 95         // or -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles=true
 96         final String dumpProxyClassesKey = "jdk.invoke.LambdaMetafactory.dumpProxyClassFiles";
 97         lambdaProxyClassFileDumper = ClassFileDumper.getInstance(dumpProxyClassesKey, "DUMP_LAMBDA_PROXY_CLASS_FILES");
 98 
 99         final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
100         disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
101 
102         // condy to load implMethod from class data
103         MethodType classDataMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
104         Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classData",
105                                          classDataMType.descriptorString(), false);
106         implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm);
107     }
108 
109     // See context values in AbstractValidatingLambdaMetafactory
110     private final String implMethodClassName;        // Name of type containing implementation "CC"
111     private final String implMethodName;             // Name of implementation method "impl"
112     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
113     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
114     private final ClassWriter cw;                    // ASM class writer
115     private final String[] argNames;                 // Generated names for the constructor arguments
116     private final String[] argDescs;                 // Type descriptors for the constructor arguments
117     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda"
118     private final boolean useImplMethodHandle;       // use MethodHandle invocation instead of symbolic bytecode invocation
119 
120     /**
121      * General meta-factory constructor, supporting both standard cases and
122      * allowing for uncommon options such as serialization or bridging.
123      *
124      * @param caller Stacked automatically by VM; represents a lookup context
125      *               with the accessibility privileges of the caller.
126      * @param factoryType Stacked automatically by VM; the signature of the
127      *                    invoked method, which includes the expected static
128      *                    type of the returned lambda object, and the static
129      *                    types of the captured arguments for the lambda.  In
130      *                    the event that the implementation method is an
131      *                    instance method, the first argument in the invocation
132      *                    signature will correspond to the receiver.
133      * @param interfaceMethodName Name of the method in the functional interface to
134      *                   which the lambda or method reference is being
135      *                   converted, represented as a String.
136      * @param interfaceMethodType Type of the method in the functional interface to
137      *                            which the lambda or method reference is being
138      *                            converted, represented as a MethodType.
139      * @param implementation The implementation method which should be called (with
140      *                       suitable adaptation of argument types, return types,
141      *                       and adjustment for captured arguments) when methods of
142      *                       the resulting functional interface instance are invoked.
143      * @param dynamicMethodType The signature of the primary functional
144      *                          interface method after type variables are
145      *                          substituted with their instantiation from
146      *                          the capture site
147      * @param isSerializable Should the lambda be made serializable?  If set,
148      *                       either the target type or one of the additional SAM
149      *                       types must extend {@code Serializable}.
150      * @param altInterfaces Additional interfaces which the lambda object
151      *                      should implement.
152      * @param altMethods Method types for additional signatures to be
153      *                   implemented by invoking the implementation method
154      * @throws LambdaConversionException If any of the meta-factory protocol
155      *         invariants are violated
156      * @throws SecurityException If a security manager is present, and it
157      *         <a href="MethodHandles.Lookup.html#secmgr">denies access</a>
158      *         from {@code caller} to the package of {@code implementation}.
159      */
160     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
161                                        MethodType factoryType,
162                                        String interfaceMethodName,
163                                        MethodType interfaceMethodType,
164                                        MethodHandle implementation,
165                                        MethodType dynamicMethodType,
166                                        boolean isSerializable,
167                                        Class<?>[] altInterfaces,
168                                        MethodType[] altMethods)
169             throws LambdaConversionException {
170         super(caller, factoryType, interfaceMethodName, interfaceMethodType,
171               implementation, dynamicMethodType,
172               isSerializable, altInterfaces, altMethods);
173         implMethodClassName = implClass.getName().replace('.', '/');
174         implMethodName = implInfo.getName();
175         implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
176         constructorType = factoryType.changeReturnType(Void.TYPE);
177         lambdaClassName = lambdaClassName(targetClass);
178         // If the target class invokes a protected method inherited from a
179         // superclass in a different package, or does 'invokespecial', the
180         // lambda class has no access to the resolved method. Instead, we need
181         // to pass the live implementation method handle to the proxy class
182         // to invoke directly. (javac prefers to avoid this situation by
183         // generating bridges in the target class)
184         useImplMethodHandle = (Modifier.isProtected(implInfo.getModifiers()) &&
185                                !VerifyAccess.isSamePackage(targetClass, implInfo.getDeclaringClass())) ||
186                                implKind == H_INVOKESPECIAL;
187         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
188         int parameterCount = factoryType.parameterCount();
189         if (parameterCount > 0) {
190             argNames = new String[parameterCount];
191             argDescs = new String[parameterCount];
192             for (int i = 0; i < parameterCount; i++) {
193                 argNames[i] = "arg$" + (i + 1);
194                 argDescs[i] = BytecodeDescriptor.unparse(factoryType.parameterType(i));
195             }
196         } else {
197             argNames = argDescs = EMPTY_STRING_ARRAY;
198         }
199     }
200 
201     private static String lambdaClassName(Class<?> targetClass) {
202         String name = targetClass.getName();
203         if (targetClass.isHidden()) {
204             // use the original class name
205             name = name.replace('/', '_');
206         }
207         return name.replace('.', '/') + "$$Lambda";
208     }
209 
210     /**
211      * Build the CallSite. Generate a class file which implements the functional
212      * interface, define the class, if there are no parameters create an instance
213      * of the class which the CallSite will return, otherwise, generate handles
214      * which will call the class' constructor.
215      *
216      * @return a CallSite, which, when invoked, will return an instance of the
217      * functional interface
218      * @throws LambdaConversionException If properly formed functional interface
219      * is not found
220      */
221     @Override
222     CallSite buildCallSite() throws LambdaConversionException {
223         final Class<?> innerClass = spinInnerClass();
224         if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
225             try {
226                 return new ConstantCallSite(caller.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD,
227                                                                     factoryType.returnType()));
228             } catch (ReflectiveOperationException e) {
229                 throw new LambdaConversionException(
230                         "Exception finding " + LAMBDA_INSTANCE_FIELD + " static field", e);
231             }
232         } else {
233             try {
234                 MethodHandle mh = caller.findConstructor(innerClass, constructorType);
235                 if (factoryType.parameterCount() == 0) {
236                     // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance
237                     Object inst = mh.asType(methodType(Object.class)).invokeExact();
238                     return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
239                 } else {
240                     return new ConstantCallSite(mh.asType(factoryType));
241                 }
242             } catch (ReflectiveOperationException e) {
243                 throw new LambdaConversionException("Exception finding constructor", e);
244             } catch (Throwable e) {
245                 throw new LambdaConversionException("Exception instantiating lambda object", e);
246             }
247         }
248     }
249 
250     /**
251      * Spins the lambda proxy class.
252      *
253      * This first checks if a lambda proxy class can be loaded from CDS archive.
254      * Otherwise, generate the lambda proxy class. If CDS dumping is enabled, it
255      * registers the lambda proxy class for including into the CDS archive.
256      */
257     private Class<?> spinInnerClass() throws LambdaConversionException {
258         // CDS does not handle disableEagerInitialization or useImplMethodHandle
259         if (!disableEagerInitialization && !useImplMethodHandle) {
260             if (CDS.isSharingEnabled()) {
261                 // load from CDS archive if present
262                 Class<?> innerClass = LambdaProxyClassArchive.find(targetClass,
263                                                                    interfaceMethodName,
264                                                                    factoryType,
265                                                                    interfaceMethodType,
266                                                                    implementation,
267                                                                    dynamicMethodType,
268                                                                    isSerializable,
269                                                                    altInterfaces,
270                                                                    altMethods);
271                 if (innerClass != null) return innerClass;
272             }
273 
274             // include lambda proxy class in CDS archive at dump time
275             if (CDS.isDumpingArchive()) {
276                 Class<?> innerClass = generateInnerClass();
277                 LambdaProxyClassArchive.register(targetClass,
278                                                  interfaceMethodName,
279                                                  factoryType,
280                                                  interfaceMethodType,
281                                                  implementation,
282                                                  dynamicMethodType,
283                                                  isSerializable,
284                                                  altInterfaces,
285                                                  altMethods,
286                                                  innerClass);
287                 return innerClass;
288             }
289 
290         }
291         return generateInnerClass();
292     }
293 
294     /**
295      * Generate a class file which implements the functional
296      * interface, define and return the class.
297      *
298      * @return a Class which implements the functional interface
299      * @throws LambdaConversionException If properly formed functional interface
300      * is not found
301      */
302     private Class<?> generateInnerClass() throws LambdaConversionException {
303         String[] interfaceNames;
304         String interfaceName = interfaceClass.getName().replace('.', '/');
305         boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
306         if (altInterfaces.length == 0) {
307             interfaceNames = new String[]{interfaceName};
308         } else {
309             // Assure no duplicate interfaces (ClassFormatError)
310             Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
311             itfs.add(interfaceName);
312             for (Class<?> i : altInterfaces) {
313                 itfs.add(i.getName().replace('.', '/'));
314                 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
315             }
316             interfaceNames = itfs.toArray(new String[itfs.size()]);
317         }
318 
319         int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
320         cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
321                  lambdaClassName, null,
322                  JAVA_LANG_OBJECT, interfaceNames);
323 
324         // Generate final fields to be filled in by constructor
325         for (int i = 0; i < argDescs.length; i++) {
326             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
327                                             argNames[i],
328                                             argDescs[i],
329                                             null, null);
330             fv.visitEnd();
331         }
332 
333         generateConstructor();
334 
335         if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
336             generateClassInitializer();
337         }
338 
339         // Forward the SAM method
340         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
341                                           interfaceMethodType.toMethodDescriptorString(), null, null);
342         new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
343 
344         // Forward the altMethods
345         if (altMethods != null) {
346             for (MethodType mt : altMethods) {
347                 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
348                                     mt.toMethodDescriptorString(), null, null);
349                 new ForwardingMethodGenerator(mv).generate(mt);
350             }
351         }
352 
353         if (isSerializable)
354             generateSerializationFriendlyMethods();
355         else if (accidentallySerializable)
356             generateSerializationHostileMethods();
357 
358         // generate Preload attribute if it references any value class
359         PreloadAttributeBuilder builder = new PreloadAttributeBuilder(targetClass);
360         builder.add(factoryType)
361                .add(interfaceMethodType)
362                .add(implMethodType)
363                .add(dynamicMethodType)
364                .add(altMethods);
365         if (!builder.isEmpty())
366             cw.visitAttribute(builder.build());
367 
368         cw.visitEnd();
369 
370         // Define the generated class in this VM.
371 
372         final byte[] classBytes = cw.toByteArray();
373         try {
374             // this class is linked at the indy callsite; so define a hidden nestmate
375             var classdata = useImplMethodHandle? implementation : null;
376             return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
377                          .defineClass(!disableEagerInitialization, classdata);
378 
379         } catch (Throwable t) {
380             throw new InternalError(t);
381         }
382     }
383 
384     /**
385      * Generate a static field and a static initializer that sets this field to an instance of the lambda
386      */
387     private void generateClassInitializer() {
388         String lambdaTypeDescriptor = factoryType.returnType().descriptorString();
389 
390         // Generate the static final field that holds the lambda singleton
391         FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL,
392                 LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, null, null);
393         fv.visitEnd();
394 
395         // Instantiate the lambda and store it to the static final field
396         MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
397         clinit.visitCode();
398 
399         clinit.visitTypeInsn(NEW, lambdaClassName);
400         clinit.visitInsn(Opcodes.DUP);
401         assert factoryType.parameterCount() == 0;
402         clinit.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
403         clinit.visitFieldInsn(PUTSTATIC, lambdaClassName, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor);
404 
405         clinit.visitInsn(RETURN);
406         clinit.visitMaxs(-1, -1);
407         clinit.visitEnd();
408     }
409 
410     /**
411      * Generate the constructor for the class
412      */
413     private void generateConstructor() {
414         // Generate constructor
415         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
416                                             constructorType.toMethodDescriptorString(), null, null);
417         ctor.visitCode();
418         ctor.visitVarInsn(ALOAD, 0);
419         ctor.visitMethodInsn(INVOKESPECIAL, JAVA_LANG_OBJECT, NAME_CTOR,
420                              METHOD_DESCRIPTOR_VOID, false);
421         int parameterCount = factoryType.parameterCount();
422         for (int i = 0, lvIndex = 0; i < parameterCount; i++) {
423             ctor.visitVarInsn(ALOAD, 0);
424             Class<?> argType = factoryType.parameterType(i);
425             ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
426             lvIndex += getParameterSize(argType);
427             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
428         }
429         ctor.visitInsn(RETURN);
430         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
431         ctor.visitMaxs(-1, -1);
432         ctor.visitEnd();
433     }
434 
435     /**
436      * Generate a writeReplace method that supports serialization
437      */
438     private void generateSerializationFriendlyMethods() {
439         TypeConvertingMethodAdapter mv
440                 = new TypeConvertingMethodAdapter(
441                     cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
442                     NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
443                     null, null));
444 
445         mv.visitCode();
446         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
447         mv.visitInsn(DUP);
448         mv.visitLdcInsn(Type.getType(targetClass));
449         mv.visitLdcInsn(factoryType.returnType().getName().replace('.', '/'));
450         mv.visitLdcInsn(interfaceMethodName);
451         mv.visitLdcInsn(interfaceMethodType.toMethodDescriptorString());
452         mv.visitLdcInsn(implInfo.getReferenceKind());
453         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
454         mv.visitLdcInsn(implInfo.getName());
455         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
456         mv.visitLdcInsn(dynamicMethodType.toMethodDescriptorString());
457         mv.iconst(argDescs.length);
458         mv.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
459         for (int i = 0; i < argDescs.length; i++) {
460             mv.visitInsn(DUP);
461             mv.iconst(i);
462             mv.visitVarInsn(ALOAD, 0);
463             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
464             mv.boxIfTypePrimitive(Type.getType(argDescs[i]));
465             mv.visitInsn(AASTORE);
466         }
467         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
468                 DESCR_CTOR_SERIALIZED_LAMBDA, false);
469         mv.visitInsn(ARETURN);
470         // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
471         mv.visitMaxs(-1, -1);
472         mv.visitEnd();
473     }
474 
475     /**
476      * Generate a readObject/writeObject method that is hostile to serialization
477      */
478     private void generateSerializationHostileMethods() {
479         MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
480                                           NAME_METHOD_WRITE_OBJECT, DESCR_METHOD_WRITE_OBJECT,
481                                           null, SER_HOSTILE_EXCEPTIONS);
482         mv.visitCode();
483         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
484         mv.visitInsn(DUP);
485         mv.visitLdcInsn("Non-serializable lambda");
486         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
487                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
488         mv.visitInsn(ATHROW);
489         mv.visitMaxs(-1, -1);
490         mv.visitEnd();
491 
492         mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
493                             NAME_METHOD_READ_OBJECT, DESCR_METHOD_READ_OBJECT,
494                             null, SER_HOSTILE_EXCEPTIONS);
495         mv.visitCode();
496         mv.visitTypeInsn(NEW, NAME_NOT_SERIALIZABLE_EXCEPTION);
497         mv.visitInsn(DUP);
498         mv.visitLdcInsn("Non-serializable lambda");
499         mv.visitMethodInsn(INVOKESPECIAL, NAME_NOT_SERIALIZABLE_EXCEPTION, NAME_CTOR,
500                            DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION, false);
501         mv.visitInsn(ATHROW);
502         mv.visitMaxs(-1, -1);
503         mv.visitEnd();
504     }
505 
506     /**
507      * This class generates a method body which calls the lambda implementation
508      * method, converting arguments, as needed.
509      */
510     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
511 
512         ForwardingMethodGenerator(MethodVisitor mv) {
513             super(mv);
514         }
515 
516         void generate(MethodType methodType) {
517             visitCode();
518 
519             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
520                 visitTypeInsn(NEW, implMethodClassName);
521                 visitInsn(DUP);
522             }
523             if (useImplMethodHandle) {
524                 visitLdcInsn(implMethodCondy);
525             }
526             for (int i = 0; i < argNames.length; i++) {
527                 visitVarInsn(ALOAD, 0);
528                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
529             }
530 
531             convertArgumentTypes(methodType);
532 
533             if (useImplMethodHandle) {
534                 MethodType mtype = implInfo.getMethodType();
535                 if (implKind != MethodHandleInfo.REF_invokeStatic) {
536                     mtype = mtype.insertParameterTypes(0, implClass);
537                 }
538                 visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
539                                 "invokeExact", mtype.descriptorString(), false);
540             } else {
541                 // Invoke the method we want to forward to
542                 visitMethodInsn(invocationOpcode(), implMethodClassName,
543                                 implMethodName, implMethodDesc,
544                                 implClass.isInterface());
545             }
546             // Convert the return value (if any) and return it
547             // Note: if adapting from non-void to void, the 'return'
548             // instruction will pop the unneeded result
549             Class<?> implReturnClass = implMethodType.returnType();
550             Class<?> samReturnClass = methodType.returnType();
551             convertType(implReturnClass, samReturnClass, samReturnClass);
552             visitInsn(getReturnOpcode(samReturnClass));
553             // Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
554             visitMaxs(-1, -1);
555             visitEnd();
556         }
557 
558         private void convertArgumentTypes(MethodType samType) {
559             int lvIndex = 0;
560             int samParametersLength = samType.parameterCount();
561             int captureArity = factoryType.parameterCount();
562             for (int i = 0; i < samParametersLength; i++) {
563                 Class<?> argType = samType.parameterType(i);
564                 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
565                 lvIndex += getParameterSize(argType);
566                 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
567             }
568         }
569 
570         private int invocationOpcode() throws InternalError {
571             return switch (implKind) {
572                 case MethodHandleInfo.REF_invokeStatic     -> INVOKESTATIC;
573                 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
574                 case MethodHandleInfo.REF_invokeVirtual    -> INVOKEVIRTUAL;
575                 case MethodHandleInfo.REF_invokeInterface  -> INVOKEINTERFACE;
576                 case MethodHandleInfo.REF_invokeSpecial    -> INVOKESPECIAL;
577                 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
578             };
579         }
580     }
581 
582     /*
583      * Preload attribute builder
584      */
585     static class PreloadAttributeBuilder {
586         private final Set<Class<?>> preloadClasses = new HashSet<>();
587         PreloadAttributeBuilder(Class<?> targetClass) {
588             if (requiresPreload(targetClass)) {
589                 preloadClasses.add(targetClass);
590             }
591         }
592 
593         /*
594          * Add the value types referenced in the given MethodType.
595          */
596         PreloadAttributeBuilder add(MethodType mt) {
597             // parameter types
598             for (Class<?> paramType : mt.ptypes()) {
599                 if (requiresPreload(paramType)) {
600                     preloadClasses.add(paramType);
601                 }
602             }
603             // return type
604             if (requiresPreload(mt.returnType())) {
605                 preloadClasses.add(mt.returnType());
606             }
607             return this;
608         }
609 
610         PreloadAttributeBuilder add(MethodType... mtypes) {
611             for (MethodType mt : mtypes) {
612                 add(mt);
613             }
614             return this;
615         }
616 
617         boolean requiresPreload(Class<?> cls) {
618             Class<?> c = cls;
619             while (c.isArray()) {
620                 c = c.getComponentType();
621             }
622             return c.isValue();
623         }
624 
625         boolean isEmpty() {
626             return preloadClasses.isEmpty();
627         }
628 
629         Attribute build() {
630             return new Attribute("Preload") {
631                 @Override
632                 protected ByteVector write(ClassWriter cw,
633                                            byte[] code,
634                                            int len,
635                                            int maxStack,
636                                            int maxLocals) {
637                     ByteVector attr = new ByteVector();
638                     attr.putShort(preloadClasses.size());
639                     for (Class<?> c : preloadClasses) {
640                         attr.putShort(cw.newClass(Type.getInternalName(c)));
641                     }
642                     return attr;
643                 }
644             };
645         }
646     }
647 
648     static int getParameterSize(Class<?> c) {
649         if (c == Void.TYPE) {
650             return 0;
651         } else if (c == Long.TYPE || c == Double.TYPE) {
652             return 2;
653         }
654         return 1;
655     }
656 
657     static int getLoadOpcode(Class<?> c) {
658         if(c == Void.TYPE) {
659             throw new InternalError("Unexpected void type of load opcode");
660         }
661         return ILOAD + getOpcodeOffset(c);
662     }
663 
664     static int getReturnOpcode(Class<?> c) {
665         if(c == Void.TYPE) {
666             return RETURN;
667         }
668         return IRETURN + getOpcodeOffset(c);
669     }
670 
671     private static int getOpcodeOffset(Class<?> c) {
672         if (c.isPrimitive()) {
673             if (c == Long.TYPE) {
674                 return 1;
675             } else if (c == Float.TYPE) {
676                 return 2;
677             } else if (c == Double.TYPE) {
678                 return 3;
679             }
680             return 0;
681         } else {
682             return 4;
683         }
684     }
685 
686 }