1 /*
  2  * Copyright (c) 2016, 2025, 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.vm.annotation.AOTSafeClassInitializer;
 29 import sun.invoke.util.Wrapper;
 30 
 31 import java.lang.classfile.Annotation;
 32 import java.lang.classfile.ClassFile;
 33 import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
 34 import java.lang.classfile.attribute.SourceFileAttribute;
 35 import java.lang.constant.ClassDesc;
 36 import java.util.ArrayList;
 37 import java.util.HashSet;
 38 import java.util.Map;
 39 import java.util.Objects;
 40 import java.util.Set;
 41 import java.util.TreeMap;
 42 import java.util.TreeSet;
 43 import java.util.stream.Stream;
 44 
 45 import static java.lang.classfile.ClassFile.*;
 46 import static java.lang.invoke.LambdaForm.BasicType.*;
 47 import static java.lang.invoke.LambdaForm.Kind.*;
 48 import static java.lang.invoke.MethodTypeForm.*;
 49 
 50 /**
 51  * Helper class to assist the GenerateJLIClassesPlugin to get access to
 52  * generate classes ahead of time.
 53  */
 54 class GenerateJLIClassesHelper {
 55     // Map from DirectMethodHandle method type name to index to LambdaForms
 56     static final Map<String, Integer> DMH_METHOD_TYPE_MAP =
 57             Map.of(
 58                     DIRECT_INVOKE_VIRTUAL.methodName,     LF_INVVIRTUAL,
 59                     DIRECT_INVOKE_STATIC.methodName,      LF_INVSTATIC,
 60                     DIRECT_INVOKE_SPECIAL.methodName,     LF_INVSPECIAL,
 61                     DIRECT_NEW_INVOKE_SPECIAL.methodName, LF_NEWINVSPECIAL,
 62                     DIRECT_INVOKE_INTERFACE.methodName,   LF_INVINTERFACE,
 63                     DIRECT_INVOKE_STATIC_INIT.methodName, LF_INVSTATIC_INIT,
 64                     DIRECT_INVOKE_SPECIAL_IFC.methodName, LF_INVSPECIAL_IFC
 65             );
 66 
 67     static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
 68     static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder";
 69     static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder";
 70     static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
 71     static final String INVOKERS_HOLDER_CLASS_NAME = INVOKERS_HOLDER.replace('/', '.');
 72     static final String BMH_SPECIES_PREFIX = "java.lang.invoke.BoundMethodHandle$Species_";
 73     static final Annotation AOT_SAFE_ANNOTATION = Annotation.of(AOTSafeClassInitializer.class.describeConstable().orElseThrow());
 74 
 75     static class HolderClassBuilder {
 76 
 77 
 78         private final TreeSet<String> speciesTypes = new TreeSet<>();
 79         private final TreeSet<String> invokerTypes = new TreeSet<>();
 80         private final TreeSet<String> linkerTypes = new TreeSet<>();
 81         private final TreeSet<String> callSiteTypes = new TreeSet<>();
 82         private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
 83 
 84         HolderClassBuilder addSpeciesType(String type) {
 85             speciesTypes.add(expandSignature(type));
 86             return this;
 87         }
 88 
 89         HolderClassBuilder addInvokerType(String methodType) {
 90             validateMethodType(methodType);
 91             invokerTypes.add(methodType);
 92             return this;
 93         }
 94 
 95         HolderClassBuilder addLinkerType(String methodType) {
 96             validateMethodType(methodType);
 97             linkerTypes.add(methodType);
 98             return this;
 99         }
100 
101         HolderClassBuilder addCallSiteType(String csType) {
102             validateMethodType(csType);
103             callSiteTypes.add(csType);
104             return this;
105         }
106 
107         Map<String, byte[]> build() {
108             int count = 0;
109             for (Set<String> entry : dmhMethods.values()) {
110                 count += entry.size();
111             }
112             MethodType[] directMethodTypes = new MethodType[count];
113             int[] dmhTypes = new int[count];
114             int index = 0;
115             for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
116                 String dmhType = entry.getKey();
117                 for (String type : entry.getValue()) {
118                     // The DMH type to actually ask for is retrieved by removing
119                     // the first argument, which needs to be of Object.class
120                     MethodType mt = asMethodType(type);
121                     if (mt.parameterCount() < 1 ||
122                             mt.parameterType(0) != Object.class) {
123                         throw new RuntimeException(
124                                 "DMH type parameter must start with L: " + dmhType + " " + type);
125                     }
126 
127                     // Adapt the method type of the LF to retrieve
128                     directMethodTypes[index] = mt.dropParameterTypes(0, 1);
129 
130                     // invokeVirtual and invokeInterface must have a leading Object
131                     // parameter, i.e., the receiver
132                     dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
133                     if (dmhTypes[index] == LF_INVINTERFACE || dmhTypes[index] == LF_INVVIRTUAL) {
134                         if (mt.parameterCount() < 2 ||
135                                 mt.parameterType(1) != Object.class) {
136                             throw new RuntimeException(
137                                     "DMH type parameter must start with LL: " + dmhType + " " + type);
138                         }
139                     }
140                     index++;
141                 }
142             }
143 
144             // The linker type to ask for is retrieved by removing the first
145             // and the last argument, which needs to be of Object.class
146             MethodType[] linkerMethodTypes = new MethodType[linkerTypes.size()];
147             index = 0;
148             for (String linkerType : linkerTypes) {
149                 MethodType mt = asMethodType(linkerType);
150                 final int lastParam = mt.parameterCount() - 1;
151                 if (!checkLinkerTypeParams(mt)) {
152                     throw new RuntimeException(
153                             "Linker type parameter must start and end with Object: " + linkerType);
154                 }
155                 mt = mt.dropParameterTypes(lastParam, lastParam + 1);
156                 linkerMethodTypes[index] = mt.dropParameterTypes(0, 1);
157                 index++;
158             }
159 
160             // The invoker type to ask for is retrieved by removing the first
161             // argument, which needs to be of Object.class
162             MethodType[] invokerMethodTypes = new MethodType[invokerTypes.size()];
163             index = 0;
164             for (String invokerType : invokerTypes) {
165                 MethodType mt = asMethodType(invokerType);
166                 if (!checkInvokerTypeParams(mt)) {
167                     throw new RuntimeException(
168                             "Invoker type parameter must start with 2 Objects: " + invokerType);
169                 }
170                 invokerMethodTypes[index] = mt.dropParameterTypes(0, 2);
171                 index++;
172             }
173 
174             // The callSite type to ask for is retrieved by removing the last
175             // argument, which needs to be of Object.class
176             MethodType[] callSiteMethodTypes = new MethodType[callSiteTypes.size()];
177             index = 0;
178             for (String callSiteType : callSiteTypes) {
179                 MethodType mt = asMethodType(callSiteType);
180                 final int lastParam = mt.parameterCount() - 1;
181                 if (mt.parameterCount() < 1 ||
182                         mt.parameterType(lastParam) != Object.class) {
183                     throw new RuntimeException(
184                             "CallSite type parameter must end with Object: " + callSiteType);
185                 }
186                 callSiteMethodTypes[index] = mt.dropParameterTypes(lastParam, lastParam + 1);
187                 index++;
188             }
189 
190             Map<String, byte[]> result = new TreeMap<>();
191             result.put(DIRECT_HOLDER,
192                        generateDirectMethodHandleHolderClassBytes(
193                             DIRECT_HOLDER, directMethodTypes, dmhTypes));
194             result.put(DELEGATING_HOLDER,
195                        generateDelegatingMethodHandleHolderClassBytes(
196                             DELEGATING_HOLDER, directMethodTypes));
197             result.put(INVOKERS_HOLDER,
198                        generateInvokersHolderClassBytes(INVOKERS_HOLDER,
199                             linkerMethodTypes, invokerMethodTypes, callSiteMethodTypes));
200             result.put(BASIC_FORMS_HOLDER,
201                        generateBasicFormsClassBytes(BASIC_FORMS_HOLDER));
202 
203             speciesTypes.forEach(types -> {
204                 Map.Entry<String, byte[]> entry = generateConcreteBMHClassBytes(types);
205                 result.put(entry.getKey(), entry.getValue());
206             });
207 
208             // clear builder
209             speciesTypes.clear();
210             invokerTypes.clear();
211             callSiteTypes.clear();
212             dmhMethods.clear();
213 
214             return result;
215         }
216 
217         public static MethodType asMethodType(String basicSignatureString) {
218             String[] parts = basicSignatureString.split("_");
219             assert (parts.length == 2);
220             assert (parts[1].length() == 1);
221             String parameters = expandSignature(parts[0]);
222             Class<?> rtype = simpleType(parts[1].charAt(0));
223             if (parameters.isEmpty()) {
224                 return MethodType.methodType(rtype);
225             } else {
226                 Class<?>[] ptypes = new Class<?>[parameters.length()];
227                 for (int i = 0; i < ptypes.length; i++) {
228                     ptypes[i] = simpleType(parameters.charAt(i));
229                 }
230                 return MethodType.methodType(rtype, ptypes);
231             }
232         }
233 
234         public static boolean checkInvokerTypeParams(MethodType mt) {
235             return (mt.parameterCount() >= 2 &&
236                     mt.parameterType(0) == Object.class &&
237                     mt.parameterType(1) == Object.class);
238         }
239 
240         public static boolean checkLinkerTypeParams(MethodType mt) {
241             final int lastParam = mt.parameterCount() - 1;
242             return (mt.parameterCount() >= 2 &&
243                     mt.parameterType(0) == Object.class &&
244                     mt.parameterType(lastParam) == Object.class);
245         }
246 
247         private void addDMHMethodType(String dmh, String methodType) {
248             validateMethodType(methodType);
249             Set<String> methodTypes = dmhMethods.get(dmh);
250             if (methodTypes == null) {
251                 methodTypes = new TreeSet<>();
252                 dmhMethods.put(dmh, methodTypes);
253             }
254             methodTypes.add(methodType);
255         }
256 
257         private static void validateMethodType(String type) {
258             String[] typeParts = type.split("_");
259             // check return type (second part)
260             if (typeParts.length != 2 || typeParts[1].length() != 1
261                     || !isBasicTypeChar(typeParts[1].charAt(0))) {
262                 throw new RuntimeException(
263                         "Method type signature must be of form [LJIFD]*_[LJIFDV]");
264             }
265             // expand and check arguments (first part)
266             expandSignature(typeParts[0]);
267         }
268 
269         // Convert LL -> LL, L3 -> LLL
270         private static String expandSignature(String signature) {
271             StringBuilder sb = new StringBuilder();
272             char last = 'X';
273             int count = 0;
274             for (int i = 0; i < signature.length(); i++) {
275                 char c = signature.charAt(i);
276                 if (c >= '0' && c <= '9') {
277                     count *= 10;
278                     count += (c - '0');
279                 } else {
280                     requireBasicType(c);
281                     for (int j = 1; j < count; j++) {
282                         sb.append(last);
283                     }
284                     sb.append(c);
285                     last = c;
286                     count = 0;
287                 }
288             }
289 
290             // ended with a number, e.g., "L2": append last char count - 1 times
291             if (count > 1) {
292                 requireBasicType(last);
293                 for (int j = 1; j < count; j++) {
294                     sb.append(last);
295                 }
296             }
297             return sb.toString();
298         }
299 
300         private static void requireBasicType(char c) {
301             if (!isArgBasicTypeChar(c)) {
302                 throw new RuntimeException(
303                         "Character " + c + " must correspond to a basic field type: LIJFD");
304             }
305         }
306 
307         private static Class<?> simpleType(char c) {
308             if (isBasicTypeChar(c)) {
309                 return LambdaForm.BasicType.basicType(c).basicTypeClass();
310             }
311             switch (c) {
312                 case 'Z':
313                 case 'B':
314                 case 'S':
315                 case 'C':
316                     throw new IllegalArgumentException("Not a valid primitive: " + c +
317                             " (use I instead)");
318                 default:
319                     throw new IllegalArgumentException("Not a primitive: " + c);
320             }
321         }
322     }
323 
324     /*
325      * Returns a map of class name in internal form to the corresponding class bytes
326      * per the given stream of SPECIES_RESOLVE and LF_RESOLVE trace logs.
327      *
328      * Used by GenerateJLIClassesPlugin to pre-generate holder classes during
329      * jlink phase.
330      */
331     static Map<String, byte[]> generateHolderClasses(Stream<String> traces)  {
332         Objects.requireNonNull(traces);
333         HolderClassBuilder builder = new HolderClassBuilder();
334         traces.map(line -> line.split(" "))
335                 .forEach(parts -> {
336                     switch (parts[0]) {
337                         case "[SPECIES_RESOLVE]":
338                             // Allow for new types of species data classes being resolved here
339                             assert parts.length >= 2;
340                             if (parts[1].startsWith(BMH_SPECIES_PREFIX)) {
341                                 String species = parts[1].substring(BMH_SPECIES_PREFIX.length());
342                                 if (!"L".equals(species)) {
343                                     builder.addSpeciesType(species);
344                                 }
345                             }
346                             break;
347                         case "[LF_RESOLVE]":
348                             assert parts.length > 3;
349                             String methodType = parts[3];
350                             if (parts[1].equals(INVOKERS_HOLDER_CLASS_NAME)) {
351                                 if ("linkToTargetMethod".equals(parts[2]) ||
352                                         "linkToCallSite".equals(parts[2])) {
353                                     builder.addCallSiteType(methodType);
354                                 } else if (parts[2].endsWith("nvoker")) {
355                                     // MH.exactInvoker exactInvoker MH.invoker invoker
356                                     builder.addInvokerType(methodType);
357                                 } else {
358                                     builder.addLinkerType(methodType);
359                                 }
360                             } else if (parts[1].contains("DirectMethodHandle")) {
361                                 String dmh = parts[2];
362                                 // ignore getObject etc for now (generated by default)
363                                 if (DMH_METHOD_TYPE_MAP.containsKey(dmh)) {
364                                     builder.addDMHMethodType(dmh, methodType);
365                                 }
366                             }
367                             break;
368                         default:
369                             break; // ignore
370                     }
371                 });
372 
373         return builder.build();
374     }
375 
376     /**
377      * Returns a {@code byte[]} representation of a class implementing
378      * the zero and identity forms of all {@code LambdaForm.BasicType}s.
379      */
380     static byte[] generateBasicFormsClassBytes(String className) {
381         ArrayList<LambdaForm> forms = new ArrayList<>();
382         ArrayList<String> names = new ArrayList<>();
383         HashSet<String> dedupSet = new HashSet<>();
384         for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) {
385             String name;
386 
387             LambdaForm identity = LambdaForm.identityForm(type);
388             name = identity.kind.defaultLambdaName
389                    + "_" + identity.returnType().basicTypeChar();
390             if (dedupSet.add(name)) {
391                 names.add(name);
392                 forms.add(identity);
393             }
394 
395             if (type != V_TYPE) {
396                 LambdaForm constant = LambdaForm.constantForm(type);
397                 name = constant.kind.defaultLambdaName
398                         + "_" + constant.returnType().basicTypeChar();
399                 if (dedupSet.add(name)) {
400                     names.add(name);
401                     forms.add(constant);
402                 }
403             }
404         }
405         return generateCodeBytesForLFs(className,
406                 names.toArray(new String[0]),
407                 forms.toArray(new LambdaForm[0]));
408     }
409 
410     /**
411      * Returns a {@code byte[]} representation of a class implementing
412      * DirectMethodHandle of each pairwise combination of {@code MethodType} and
413      * an {@code int} representing method type.
414      */
415     static byte[] generateDirectMethodHandleHolderClassBytes(String className,
416             MethodType[] methodTypes, int[] types) {
417         ArrayList<LambdaForm> forms = new ArrayList<>();
418         ArrayList<String> names = new ArrayList<>();
419         for (int i = 0; i < methodTypes.length; i++) {
420             // invokeVirtual and invokeInterface must have a leading Object
421             // parameter, i.e., the receiver
422             if (types[i] == LF_INVVIRTUAL || types[i] == LF_INVINTERFACE) {
423                 if (methodTypes[i].parameterCount() < 1 ||
424                         methodTypes[i].parameterType(0) != Object.class) {
425                     throw new InternalError("Invalid method type for " +
426                             (types[i] == LF_INVVIRTUAL ? "invokeVirtual" : "invokeInterface") +
427                             " DMH, needs at least two leading reference arguments: " +
428                             methodTypes[i]);
429                 }
430             }
431 
432             LambdaForm form = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i], types[i]);
433             forms.add(form);
434             names.add(form.kind.defaultLambdaName);
435         }
436         for (Wrapper wrapper : Wrapper.values()) {
437             int ftype = wrapper == Wrapper.VOID ? DirectMethodHandle.FT_CHECKED_REF : DirectMethodHandle.ftypeKind(wrapper.primitiveType());
438             for (byte b = DirectMethodHandle.AF_GETFIELD; b < DirectMethodHandle.AF_LIMIT; b++) {
439                 LambdaForm form = DirectMethodHandle
440                         .makePreparedFieldLambdaForm(b, /*isVolatile*/false, ftype);
441                 if (form.kind == GENERIC)
442                     throw new InternalError(b + " non-volatile " + ftype);
443                 forms.add(form);
444                 names.add(form.kind.defaultLambdaName);
445                 // volatile
446                 form = DirectMethodHandle
447                         .makePreparedFieldLambdaForm(b, /*isVolatile*/true, ftype);
448                 if (form.kind == GENERIC)
449                     throw new InternalError(b + " volatile " + ftype);
450                 forms.add(form);
451                 names.add(form.kind.defaultLambdaName);
452             }
453         }
454         return generateCodeBytesForLFs(className,
455                 names.toArray(new String[0]),
456                 forms.toArray(new LambdaForm[0]));
457     }
458 
459     /**
460      * Returns a {@code byte[]} representation of a class implementing
461      * DelegatingMethodHandles of each {@code MethodType} kind in the
462      * {@code methodTypes} argument.
463      */
464     static byte[] generateDelegatingMethodHandleHolderClassBytes(String className,
465             MethodType[] methodTypes) {
466 
467         HashSet<MethodType> dedupSet = new HashSet<>();
468         ArrayList<LambdaForm> forms = new ArrayList<>();
469         ArrayList<String> names = new ArrayList<>();
470         for (int i = 0; i < methodTypes.length; i++) {
471             // generate methods representing the DelegatingMethodHandle
472             if (dedupSet.add(methodTypes[i])) {
473                 // reinvokers are variant with the associated SpeciesData
474                 // and shape of the target LF, but we can easily pregenerate
475                 // the basic reinvokers associated with Species_L. Ultimately we
476                 // may want to consider pregenerating more of these, which will
477                 // require an even more complex naming scheme
478                 LambdaForm reinvoker = makeReinvokerFor(methodTypes[i]);
479                 forms.add(reinvoker);
480                 String speciesSig = BoundMethodHandle.speciesDataFor(reinvoker).key();
481                 assert(speciesSig.equals("L"));
482                 names.add(reinvoker.kind.defaultLambdaName + "_" + speciesSig);
483 
484                 LambdaForm delegate = makeDelegateFor(methodTypes[i]);
485                 forms.add(delegate);
486                 names.add(delegate.kind.defaultLambdaName);
487             }
488         }
489         return generateCodeBytesForLFs(className,
490                 names.toArray(new String[0]),
491                 forms.toArray(new LambdaForm[0]));
492     }
493 
494     /**
495      * Returns a {@code byte[]} representation of a class implementing
496      * the invoker forms for the set of supplied {@code linkerMethodTypes}
497      * {@code invokerMethodTypes}, and {@code callSiteMethodTypes}.
498      */
499     static byte[] generateInvokersHolderClassBytes(String className,
500             MethodType[] linkerMethodTypes, MethodType[] invokerMethodTypes,
501             MethodType[] callSiteMethodTypes) {
502 
503         HashSet<MethodType> dedupSet = new HashSet<>();
504         ArrayList<LambdaForm> forms = new ArrayList<>();
505         ArrayList<String> names = new ArrayList<>();
506 
507         int[] invokerTypes = {
508             MethodTypeForm.LF_EX_INVOKER,
509             MethodTypeForm.LF_GEN_INVOKER,
510         };
511 
512         for (MethodType methodType : invokerMethodTypes) {
513             // generate methods representing invokers of the specified type
514             if (dedupSet.add(methodType)) {
515                 for (int type : invokerTypes) {
516                     LambdaForm invokerForm = Invokers.invokeHandleForm(methodType,
517                             /*customized*/false, type);
518                     forms.add(invokerForm);
519                     names.add(invokerForm.kind.defaultLambdaName);
520                 }
521             }
522         }
523 
524         int[] linkerTypes = {
525                 MethodTypeForm.LF_EX_LINKER,
526                 MethodTypeForm.LF_GEN_LINKER,
527         };
528 
529         dedupSet = new HashSet<>();
530         for (MethodType methodType : linkerMethodTypes) {
531             // generate methods representing linkers of the specified type
532             if (dedupSet.add(methodType)) {
533                 for (int type : linkerTypes) {
534                     LambdaForm linkerForm = Invokers.invokeHandleForm(methodType,
535                             /*customized*/false, type);
536                     forms.add(linkerForm);
537                     names.add(linkerForm.kind.defaultLambdaName);
538                 }
539             }
540         }
541 
542         dedupSet = new HashSet<>();
543         for (int i = 0; i < callSiteMethodTypes.length; i++) {
544             // generate methods representing invokers of the specified type
545             if (dedupSet.add(callSiteMethodTypes[i])) {
546                 LambdaForm callSiteForm = Invokers.callSiteForm(callSiteMethodTypes[i], true);
547                 forms.add(callSiteForm);
548                 names.add(callSiteForm.kind.defaultLambdaName);
549 
550                 LambdaForm methodHandleForm = Invokers.callSiteForm(callSiteMethodTypes[i], false);
551                 forms.add(methodHandleForm);
552                 names.add(methodHandleForm.kind.defaultLambdaName);
553             }
554         }
555 
556         return generateCodeBytesForLFs(className,
557                 names.toArray(new String[0]),
558                 forms.toArray(new LambdaForm[0]));
559     }
560 
561     /*
562      * Generate customized code for a set of LambdaForms of specified types into
563      * a class with a specified name.
564      */
565     private static byte[] generateCodeBytesForLFs(String className, String[] names, LambdaForm[] forms) {
566         return ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> {
567             clb.withFlags(ACC_PRIVATE | ACC_FINAL | ACC_SUPER)
568                .withSuperclass(InvokerBytecodeGenerator.INVOKER_SUPER_DESC)
569                .with(RuntimeVisibleAnnotationsAttribute.of(AOT_SAFE_ANNOTATION))
570                .with(SourceFileAttribute.of(className.substring(className.lastIndexOf('/') + 1)));
571             for (int i = 0; i < forms.length; i++) {
572                 new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb, false);
573             }
574         });
575     }
576 
577     private static LambdaForm makeReinvokerFor(MethodType type) {
578         MethodHandle emptyHandle = MethodHandles.empty(type);
579         return DelegatingMethodHandle.makeReinvokerForm(emptyHandle,
580                 MethodTypeForm.LF_REBIND,
581                 BoundMethodHandle.speciesData_L(),
582                 BoundMethodHandle.speciesData_L().getterFunction(0));
583     }
584 
585     private static LambdaForm makeDelegateFor(MethodType type) {
586         MethodHandle handle = MethodHandles.empty(type);
587         return DelegatingMethodHandle.makeReinvokerForm(
588                 handle,
589                 MethodTypeForm.LF_DELEGATE,
590                 DelegatingMethodHandle.class,
591                 DelegatingMethodHandle.NF_getTarget);
592     }
593 
594     /**
595      * Returns a {@code byte[]} representation of {@code BoundMethodHandle}
596      * species class implementing the signature defined by {@code types}.
597      */
598     @SuppressWarnings({"rawtypes", "unchecked"})
599     static Map.Entry<String, byte[]> generateConcreteBMHClassBytes(final String types) {
600         for (char c : types.toCharArray()) {
601             if (!isArgBasicTypeChar(c)) {
602                 throw new IllegalArgumentException("All characters must "
603                         + "correspond to a basic field type: LIJFD");
604             }
605         }
606         final BoundMethodHandle.SpeciesData species = BoundMethodHandle.SPECIALIZER.findSpecies(types);
607         final String className = species.speciesCode().getName();
608         final ClassSpecializer.Factory factory = BoundMethodHandle.SPECIALIZER.factory();
609         final byte[] code = factory.generateConcreteSpeciesCodeFile(className, species);
610         return Map.entry(className.replace('.', '/'), code);
611     }
612 
613 }