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