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