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