52 * Plugin to generate java.lang.invoke classes.
53 */
54 public final class GenerateJLIClassesPlugin implements Plugin {
55
56 private static final String NAME = "generate-jli-classes";
57
58 private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
59
60 private static final String DEFAULT_TRACE_FILE = "default_jli_trace.txt";
61
62 private static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
63 private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
64 private static final String DMH_INVOKE_STATIC = "invokeStatic";
65 private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
66 private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
67 private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
68 private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
69
70 private static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder";
71 private static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder";
72 private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
73
74 private static final JavaLangInvokeAccess JLIA
75 = SharedSecrets.getJavaLangInvokeAccess();
76
77 Set<String> speciesTypes = Set.of();
78
79 Set<String> invokerTypes = Set.of();
80
81 Map<String, Set<String>> dmhMethods = Map.of();
82
83 String mainArgument;
84
85 public GenerateJLIClassesPlugin() {
86 }
87
88 @Override
89 public String getName() {
90 return NAME;
91 }
92
93 @Override
94 public String getDescription() {
95 return DESCRIPTION;
96 }
97
98 @Override
99 public Set<State> getState() {
100 return EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL);
111 }
112
113 /**
114 * @return the default Species forms to generate.
115 *
116 * This list was derived from running a small startup benchmark.
117 * A better long-term solution is to define and run a set of quick
118 * generators and extracting this list as a step in the build process.
119 */
120 public static Set<String> defaultSpecies() {
121 return Set.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I",
122 "L7II", "L7IIL", "L8", "L9", "L10", "L10I", "L10II", "L10IIL",
123 "L11", "L12", "L13", "LI", "D", "L3I", "LIL", "LLI", "LLIL",
124 "LILL", "I", "LLILL");
125 }
126
127 /**
128 * @return the default invoker forms to generate.
129 */
130 private static Set<String> defaultInvokers() {
131 return Set.of("LL_L", "LL_I", "LILL_I", "L6_L");
132 }
133
134 /**
135 * @return the list of default DirectMethodHandle methods to generate.
136 */
137 private static Map<String, Set<String>> defaultDMHMethods() {
138 return Map.of(
139 DMH_INVOKE_VIRTUAL, Set.of("L_L", "LL_L", "LLI_I", "L3_V"),
140 DMH_INVOKE_SPECIAL, Set.of("LL_I", "LL_L", "LLF_L", "LLD_L", "L3_L",
141 "L4_L", "L5_L", "L6_L", "L7_L", "L8_L", "LLI_I", "LLI_L",
142 "LLIL_I", "LLII_I", "LLII_L", "L3I_L", "L3I_I", "LLILI_I",
143 "LLIIL_L", "LLIILL_L", "LLIILL_I", "LLIIL_I", "LLILIL_I",
144 "LLILILL_I", "LLILII_I", "LLI3_I", "LLI3L_I", "LLI3LL_I",
145 "LLI3_L", "LLI4_I"),
146 DMH_INVOKE_STATIC, Set.of("LII_I", "LIL_I", "LILIL_I", "LILII_I",
147 "L_I", "L_L", "L_V", "LD_L", "LF_L", "LI_I", "LII_L", "LLI_L",
148 "LL_V", "LL_L", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L",
149 "L8_L", "L9_L", "L10_L", "L10I_L", "L10II_L", "L10IIL_L",
150 "L11_L", "L12_L", "L13_L", "L14_L", "L14I_L", "L14II_L"),
151 DMH_NEW_INVOKE_SPECIAL, Set.of("L_L", "LL_L")
192 new BufferedReader(
193 new InputStreamReader(traceFile)).lines());
194 }
195 } catch (Exception e) {
196 throw new PluginException("Couldn't read " + DEFAULT_TRACE_FILE, e);
197 }
198 } else {
199 File file = new File(mainArgument.substring(1));
200 if (file.exists()) {
201 readTraceConfig(fileLines(file));
202 }
203 }
204 }
205
206 private void readTraceConfig(Stream<String> lines) {
207 // Use TreeSet/TreeMap to keep things sorted in a deterministic
208 // order to avoid scrambling the layout on small changes and to
209 // ease finding methods in the generated code
210 speciesTypes = new TreeSet<>(speciesTypes);
211 invokerTypes = new TreeSet<>(invokerTypes);
212 TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
213 for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
214 newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
215 }
216 dmhMethods = newDMHMethods;
217 lines.map(line -> line.split(" "))
218 .forEach(parts -> {
219 switch (parts[0]) {
220 case "[SPECIES_RESOLVE]":
221 // Allow for new types of species data classes being resolved here
222 if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
223 String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
224 if (!"L".equals(species)) {
225 speciesTypes.add(expandSignature(species));
226 }
227 }
228 break;
229 case "[LF_RESOLVE]":
230 String methodType = parts[3];
231 validateMethodType(methodType);
232 if (parts[1].contains("Invokers")) {
233 invokerTypes.add(methodType);
234 } else if (parts[1].contains("DirectMethodHandle")) {
235 String dmh = parts[2];
236 // ignore getObject etc for now (generated
237 // by default)
238 if (DMH_METHOD_TYPE_MAP.containsKey(dmh)) {
239 addDMHMethodType(dmh, methodType);
240 }
241 }
242 break;
243 default: break; // ignore
244 }
245 });
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);
277 throw new PluginException(
278 "Method type signature must be of form [LJIFD]*_[LJIFDV]");
279 }
280 // expand and check arguments (first part)
281 expandSignature(typeParts[0]);
282 }
283
284 private static void requireBasicType(char c) {
285 if ("LIJFD".indexOf(c) < 0) {
286 throw new PluginException(
287 "Character " + c + " must correspond to a basic field type: LIJFD");
288 }
289 }
290
291 @Override
292 public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
293 initialize(in);
294 // Copy all but DMH_ENTRY to out
295 in.transformAndCopy(entry -> {
296 // filter out placeholder entries
297 if (entry.path().equals(DIRECT_METHOD_HOLDER_ENTRY) ||
298 entry.path().equals(DELEGATING_METHOD_HOLDER_ENTRY) ||
299 entry.path().equals(INVOKERS_HOLDER_ENTRY) ||
300 entry.path().equals(BASIC_FORMS_HOLDER_ENTRY)) {
301 return null;
302 } else {
303 return entry;
304 }
305 }, out);
306
307 // Generate BMH Species classes
308 speciesTypes.forEach(types -> generateBMHClass(types, out));
309
310 // Generate LambdaForm Holder classes
311 generateHolderClasses(out);
312
313 // Let it go
314 speciesTypes = null;
315 invokerTypes = null;
316 dmhMethods = null;
317
318 return out.build();
319 }
320
344 }
345 MethodType[] directMethodTypes = new MethodType[count];
346 int[] dmhTypes = new int[count];
347 int index = 0;
348 for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
349 String dmhType = entry.getKey();
350 for (String type : entry.getValue()) {
351 // The DMH type to actually ask for is retrieved by removing
352 // the first argument, which needs to be of Object.class
353 MethodType mt = asMethodType(type);
354 if (mt.parameterCount() < 1 ||
355 mt.parameterType(0) != Object.class) {
356 throw new PluginException(
357 "DMH type parameter must start with L");
358 }
359 directMethodTypes[index] = mt.dropParameterTypes(0, 1);
360 dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
361 index++;
362 }
363 }
364 MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
365 int i = 0;
366 for (String invokerType : invokerTypes) {
367 // The invoker type to ask for is retrieved by removing the first
368 // and the last argument, which needs to be of Object.class
369 MethodType mt = asMethodType(invokerType);
370 final int lastParam = mt.parameterCount() - 1;
371 if (mt.parameterCount() < 2 ||
372 mt.parameterType(0) != Object.class ||
373 mt.parameterType(lastParam) != Object.class) {
374 throw new PluginException(
375 "Invoker type parameter must start and end with L");
376 }
377 mt = mt.dropParameterTypes(lastParam, lastParam + 1);
378 invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
379 i++;
380 }
381 try {
382 byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
383 DIRECT_HOLDER, directMethodTypes, dmhTypes);
384 ResourcePoolEntry ndata = ResourcePoolEntry
385 .create(DIRECT_METHOD_HOLDER_ENTRY, bytes);
386 out.add(ndata);
387
388 bytes = JLIA.generateDelegatingMethodHandleHolderClassBytes(
389 DELEGATING_HOLDER, directMethodTypes);
390 ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HOLDER_ENTRY, bytes);
391 out.add(ndata);
392
393 bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER,
394 invokerMethodTypes);
395 ndata = ResourcePoolEntry.create(INVOKERS_HOLDER_ENTRY, bytes);
396 out.add(ndata);
397
398 bytes = JLIA.generateBasicFormsClassBytes(BASIC_FORMS_HOLDER);
399 ndata = ResourcePoolEntry.create(BASIC_FORMS_HOLDER_ENTRY, bytes);
400 out.add(ndata);
401 } catch (Exception ex) {
402 throw new PluginException(ex);
403 }
404 }
405 private static final String DIRECT_METHOD_HOLDER_ENTRY =
406 "/java.base/" + DIRECT_HOLDER + ".class";
407 private static final String DELEGATING_METHOD_HOLDER_ENTRY =
408 "/java.base/" + DELEGATING_HOLDER + ".class";
409 private static final String BASIC_FORMS_HOLDER_ENTRY =
410 "/java.base/" + BASIC_FORMS_HOLDER + ".class";
411 private static final String INVOKERS_HOLDER_ENTRY =
412 "/java.base/" + INVOKERS_HOLDER + ".class";
413
414 // Convert LL -> LL, L3 -> LLL
415 public static String expandSignature(String signature) {
416 StringBuilder sb = new StringBuilder();
417 char last = 'X';
418 int count = 0;
419 for (int i = 0; i < signature.length(); i++) {
420 char c = signature.charAt(i);
421 if (c >= '0' && c <= '9') {
422 count *= 10;
423 count += (c - '0');
424 } else {
425 requireBasicType(c);
426 for (int j = 1; j < count; j++) {
427 sb.append(last);
428 }
429 sb.append(c);
430 last = c;
431 count = 0;
432 }
|
52 * Plugin to generate java.lang.invoke classes.
53 */
54 public final class GenerateJLIClassesPlugin implements Plugin {
55
56 private static final String NAME = "generate-jli-classes";
57
58 private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
59
60 private static final String DEFAULT_TRACE_FILE = "default_jli_trace.txt";
61
62 private static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
63 private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
64 private static final String DMH_INVOKE_STATIC = "invokeStatic";
65 private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
66 private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
67 private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
68 private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
69
70 private static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder";
71 private static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder";
72
73 private static final String INVOKERS_HOLDER_NAME = "java.lang.invoke.Invokers$Holder";
74 private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/');
75
76 private static final JavaLangInvokeAccess JLIA
77 = SharedSecrets.getJavaLangInvokeAccess();
78
79 Set<String> speciesTypes = Set.of();
80
81 Set<String> invokerTypes = Set.of();
82
83 Set<String> callSiteTypes = Set.of();
84
85 Map<String, Set<String>> dmhMethods = Map.of();
86
87 String mainArgument;
88
89 public GenerateJLIClassesPlugin() {
90 }
91
92 @Override
93 public String getName() {
94 return NAME;
95 }
96
97 @Override
98 public String getDescription() {
99 return DESCRIPTION;
100 }
101
102 @Override
103 public Set<State> getState() {
104 return EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL);
115 }
116
117 /**
118 * @return the default Species forms to generate.
119 *
120 * This list was derived from running a small startup benchmark.
121 * A better long-term solution is to define and run a set of quick
122 * generators and extracting this list as a step in the build process.
123 */
124 public static Set<String> defaultSpecies() {
125 return Set.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I",
126 "L7II", "L7IIL", "L8", "L9", "L10", "L10I", "L10II", "L10IIL",
127 "L11", "L12", "L13", "LI", "D", "L3I", "LIL", "LLI", "LLIL",
128 "LILL", "I", "LLILL");
129 }
130
131 /**
132 * @return the default invoker forms to generate.
133 */
134 private static Set<String> defaultInvokers() {
135 return Set.of("LL_L", "LL_I", "LLLL_L", "LLLL_I", "LLIL_L", "LLIL_I", "L6_L");
136 }
137
138 /**
139 * @return the list of default DirectMethodHandle methods to generate.
140 */
141 private static Map<String, Set<String>> defaultDMHMethods() {
142 return Map.of(
143 DMH_INVOKE_VIRTUAL, Set.of("L_L", "LL_L", "LLI_I", "L3_V"),
144 DMH_INVOKE_SPECIAL, Set.of("LL_I", "LL_L", "LLF_L", "LLD_L", "L3_L",
145 "L4_L", "L5_L", "L6_L", "L7_L", "L8_L", "LLI_I", "LLI_L",
146 "LLIL_I", "LLII_I", "LLII_L", "L3I_L", "L3I_I", "LLILI_I",
147 "LLIIL_L", "LLIILL_L", "LLIILL_I", "LLIIL_I", "LLILIL_I",
148 "LLILILL_I", "LLILII_I", "LLI3_I", "LLI3L_I", "LLI3LL_I",
149 "LLI3_L", "LLI4_I"),
150 DMH_INVOKE_STATIC, Set.of("LII_I", "LIL_I", "LILIL_I", "LILII_I",
151 "L_I", "L_L", "L_V", "LD_L", "LF_L", "LI_I", "LII_L", "LLI_L",
152 "LL_V", "LL_L", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L",
153 "L8_L", "L9_L", "L10_L", "L10I_L", "L10II_L", "L10IIL_L",
154 "L11_L", "L12_L", "L13_L", "L14_L", "L14I_L", "L14II_L"),
155 DMH_NEW_INVOKE_SPECIAL, Set.of("L_L", "LL_L")
196 new BufferedReader(
197 new InputStreamReader(traceFile)).lines());
198 }
199 } catch (Exception e) {
200 throw new PluginException("Couldn't read " + DEFAULT_TRACE_FILE, e);
201 }
202 } else {
203 File file = new File(mainArgument.substring(1));
204 if (file.exists()) {
205 readTraceConfig(fileLines(file));
206 }
207 }
208 }
209
210 private void readTraceConfig(Stream<String> lines) {
211 // Use TreeSet/TreeMap to keep things sorted in a deterministic
212 // order to avoid scrambling the layout on small changes and to
213 // ease finding methods in the generated code
214 speciesTypes = new TreeSet<>(speciesTypes);
215 invokerTypes = new TreeSet<>(invokerTypes);
216 callSiteTypes = new TreeSet<>(callSiteTypes);
217
218 TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
219 for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
220 newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
221 }
222 dmhMethods = newDMHMethods;
223 lines.map(line -> line.split(" "))
224 .forEach(parts -> {
225 switch (parts[0]) {
226 case "[SPECIES_RESOLVE]":
227 // Allow for new types of species data classes being resolved here
228 if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
229 String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
230 if (!"L".equals(species)) {
231 speciesTypes.add(expandSignature(species));
232 }
233 }
234 break;
235 case "[LF_RESOLVE]":
236 String methodType = parts[3];
237 validateMethodType(methodType);
238 if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
239 if ("linkToTargetMethod".equals(parts[2]) ||
240 "linkToCallSite".equals(parts[2])) {
241 callSiteTypes.add(methodType);
242 } else {
243 invokerTypes.add(methodType);
244 }
245 } else if (parts[1].contains("DirectMethodHandle")) {
246 String dmh = parts[2];
247 // ignore getObject etc for now (generated
248 // by default)
249 if (DMH_METHOD_TYPE_MAP.containsKey(dmh)) {
250 addDMHMethodType(dmh, methodType);
251 }
252 }
253 break;
254 default: break; // ignore
255 }
256 });
257 }
258
259 private void addDMHMethodType(String dmh, String methodType) {
260 validateMethodType(methodType);
261 Set<String> methodTypes = dmhMethods.get(dmh);
262 if (methodTypes == null) {
263 methodTypes = new TreeSet<>();
264 dmhMethods.put(dmh, methodTypes);
288 throw new PluginException(
289 "Method type signature must be of form [LJIFD]*_[LJIFDV]");
290 }
291 // expand and check arguments (first part)
292 expandSignature(typeParts[0]);
293 }
294
295 private static void requireBasicType(char c) {
296 if ("LIJFD".indexOf(c) < 0) {
297 throw new PluginException(
298 "Character " + c + " must correspond to a basic field type: LIJFD");
299 }
300 }
301
302 @Override
303 public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
304 initialize(in);
305 // Copy all but DMH_ENTRY to out
306 in.transformAndCopy(entry -> {
307 // filter out placeholder entries
308 String path = entry.path();
309 if (path.equals(DIRECT_METHOD_HOLDER_ENTRY) ||
310 path.equals(DELEGATING_METHOD_HOLDER_ENTRY) ||
311 path.equals(INVOKERS_HOLDER_ENTRY) ||
312 path.equals(BASIC_FORMS_HOLDER_ENTRY)) {
313 return null;
314 } else {
315 return entry;
316 }
317 }, out);
318
319 // Generate BMH Species classes
320 speciesTypes.forEach(types -> generateBMHClass(types, out));
321
322 // Generate LambdaForm Holder classes
323 generateHolderClasses(out);
324
325 // Let it go
326 speciesTypes = null;
327 invokerTypes = null;
328 dmhMethods = null;
329
330 return out.build();
331 }
332
356 }
357 MethodType[] directMethodTypes = new MethodType[count];
358 int[] dmhTypes = new int[count];
359 int index = 0;
360 for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
361 String dmhType = entry.getKey();
362 for (String type : entry.getValue()) {
363 // The DMH type to actually ask for is retrieved by removing
364 // the first argument, which needs to be of Object.class
365 MethodType mt = asMethodType(type);
366 if (mt.parameterCount() < 1 ||
367 mt.parameterType(0) != Object.class) {
368 throw new PluginException(
369 "DMH type parameter must start with L");
370 }
371 directMethodTypes[index] = mt.dropParameterTypes(0, 1);
372 dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
373 index++;
374 }
375 }
376
377 // The invoker type to ask for is retrieved by removing the first
378 // and the last argument, which needs to be of Object.class
379 MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
380 int i = 0;
381 for (String invokerType : invokerTypes) {
382 MethodType mt = asMethodType(invokerType);
383 final int lastParam = mt.parameterCount() - 1;
384 if (mt.parameterCount() < 2 ||
385 mt.parameterType(0) != Object.class ||
386 mt.parameterType(lastParam) != Object.class) {
387 throw new PluginException(
388 "Invoker type parameter must start and end with Object: " + invokerType);
389 }
390 mt = mt.dropParameterTypes(lastParam, lastParam + 1);
391 invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
392 i++;
393 }
394
395 // The callSite type to ask for is retrieved by removing the last
396 // argument, which needs to be of Object.class
397 MethodType[] callSiteMethodTypes = new MethodType[this.callSiteTypes.size()];
398 i = 0;
399 for (String callSiteType : callSiteTypes) {
400 MethodType mt = asMethodType(callSiteType);
401 final int lastParam = mt.parameterCount() - 1;
402 if (mt.parameterCount() < 1 ||
403 mt.parameterType(lastParam) != Object.class) {
404 throw new PluginException(
405 "CallSite type parameter must end with Object: " + callSiteType);
406 }
407 callSiteMethodTypes[i] = mt.dropParameterTypes(lastParam, lastParam + 1);
408 i++;
409 }
410 try {
411 byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
412 DIRECT_HOLDER, directMethodTypes, dmhTypes);
413 ResourcePoolEntry ndata = ResourcePoolEntry
414 .create(DIRECT_METHOD_HOLDER_ENTRY, bytes);
415 out.add(ndata);
416
417 bytes = JLIA.generateDelegatingMethodHandleHolderClassBytes(
418 DELEGATING_HOLDER, directMethodTypes);
419 ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HOLDER_ENTRY, bytes);
420 out.add(ndata);
421
422 bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER_INTERNAL_NAME,
423 invokerMethodTypes, callSiteMethodTypes);
424 ndata = ResourcePoolEntry.create(INVOKERS_HOLDER_ENTRY, bytes);
425 out.add(ndata);
426
427 bytes = JLIA.generateBasicFormsClassBytes(BASIC_FORMS_HOLDER);
428 ndata = ResourcePoolEntry.create(BASIC_FORMS_HOLDER_ENTRY, bytes);
429 out.add(ndata);
430 } catch (Exception ex) {
431 throw new PluginException(ex);
432 }
433 }
434 private static final String DIRECT_METHOD_HOLDER_ENTRY =
435 "/java.base/" + DIRECT_HOLDER + ".class";
436 private static final String DELEGATING_METHOD_HOLDER_ENTRY =
437 "/java.base/" + DELEGATING_HOLDER + ".class";
438 private static final String BASIC_FORMS_HOLDER_ENTRY =
439 "/java.base/" + BASIC_FORMS_HOLDER + ".class";
440 private static final String INVOKERS_HOLDER_ENTRY =
441 "/java.base/" + INVOKERS_HOLDER_INTERNAL_NAME + ".class";
442
443 // Convert LL -> LL, L3 -> LLL
444 public static String expandSignature(String signature) {
445 StringBuilder sb = new StringBuilder();
446 char last = 'X';
447 int count = 0;
448 for (int i = 0; i < signature.length(); i++) {
449 char c = signature.charAt(i);
450 if (c >= '0' && c <= '9') {
451 count *= 10;
452 count += (c - '0');
453 } else {
454 requireBasicType(c);
455 for (int j = 1; j < count; j++) {
456 sb.append(last);
457 }
458 sb.append(c);
459 last = c;
460 count = 0;
461 }
|