< prev index next >
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java
Print this page
@@ -27,18 +27,15 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.lang.invoke.MethodType;
import java.nio.file.Files;
import java.util.EnumSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.stream.Stream;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.PluginException;
@@ -70,37 +67,14 @@
private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
private static final String DEFAULT_TRACE_FILE = "default_jli_trace.txt";
- private static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
- private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
- private static final String DMH_INVOKE_STATIC = "invokeStatic";
- private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
- private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
- private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
- private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
- private static final String DMH_INVOKE_SPECIAL_IFC = "invokeSpecialIFC";
-
- private static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder";
- private static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder";
-
- private static final String INVOKERS_HOLDER_NAME = "java.lang.invoke.Invokers$Holder";
- private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/');
-
- private static final JavaLangInvokeAccess JLIA
- = SharedSecrets.getJavaLangInvokeAccess();
-
- private final TreeSet<String> speciesTypes = new TreeSet<>();
-
- private final TreeSet<String> invokerTypes = new TreeSet<>();
-
- private final TreeSet<String> callSiteTypes = new TreeSet<>();
-
- private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
+ private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess();
String mainArgument;
+ String[] lines = null;
public GenerateJLIClassesPlugin() {
}
@Override
@@ -126,139 +100,25 @@
@Override
public String getArgumentsDescription() {
return PluginsResourceBundle.getArgument(NAME);
}
- private static int DMH_INVOKE_VIRTUAL_TYPE = 0;
- private static int DMH_INVOKE_INTERFACE_TYPE = 4;
-
- // Map from DirectMethodHandle method type to internal ID, matching values
- // of the corresponding constants in java.lang.invoke.MethodTypeForm
- private static final Map<String, Integer> DMH_METHOD_TYPE_MAP =
- Map.of(
- DMH_INVOKE_VIRTUAL, DMH_INVOKE_VIRTUAL_TYPE,
- DMH_INVOKE_STATIC, 1,
- DMH_INVOKE_SPECIAL, 2,
- DMH_NEW_INVOKE_SPECIAL, 3,
- DMH_INVOKE_INTERFACE, DMH_INVOKE_INTERFACE_TYPE,
- DMH_INVOKE_STATIC_INIT, 5,
- DMH_INVOKE_SPECIAL_IFC, 20
- );
-
@Override
public void configure(Map<String, String> config) {
mainArgument = config.get(NAME);
}
- private void addSpeciesType(String type) {
- speciesTypes.add(expandSignature(type));
- }
-
- private void addInvokerType(String methodType) {
- validateMethodType(methodType);
- invokerTypes.add(methodType);
- }
-
- private void addCallSiteType(String csType) {
- validateMethodType(csType);
- callSiteTypes.add(csType);
- }
-
- public void initialize(ResourcePool in) {
- // Load configuration from the contents in the supplied input file
- // - if none was supplied we look for the default file
- if (mainArgument == null || !mainArgument.startsWith("@")) {
- try (InputStream traceFile =
- this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {
- if (traceFile != null) {
- readTraceConfig(
- new BufferedReader(
- new InputStreamReader(traceFile)).lines());
- }
- } catch (Exception e) {
- throw new PluginException("Couldn't read " + DEFAULT_TRACE_FILE, e);
- }
- } else {
- File file = new File(mainArgument.substring(1));
- if (file.exists()) {
- readTraceConfig(fileLines(file));
- }
- }
- }
-
- private void readTraceConfig(Stream<String> lines) {
- lines.map(line -> line.split(" "))
- .forEach(parts -> {
- switch (parts[0]) {
- case "[SPECIES_RESOLVE]":
- // Allow for new types of species data classes being resolved here
- if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
- String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
- if (!"L".equals(species)) {
- addSpeciesType(species);
- }
- }
- break;
- case "[LF_RESOLVE]":
- String methodType = parts[3];
- if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
- if ("linkToTargetMethod".equals(parts[2]) ||
- "linkToCallSite".equals(parts[2])) {
- addCallSiteType(methodType);
- } else {
- addInvokerType(methodType);
- }
- } else if (parts[1].contains("DirectMethodHandle")) {
- String dmh = parts[2];
- // ignore getObject etc for now (generated
- // by default)
- if (DMH_METHOD_TYPE_MAP.containsKey(dmh)) {
- addDMHMethodType(dmh, methodType);
- }
- }
- break;
- default: break; // ignore
- }
- });
- }
-
- private void addDMHMethodType(String dmh, String methodType) {
- validateMethodType(methodType);
- Set<String> methodTypes = dmhMethods.get(dmh);
- if (methodTypes == null) {
- methodTypes = new TreeSet<>();
- dmhMethods.put(dmh, methodTypes);
- }
- methodTypes.add(methodType);
- }
-
- private Stream<String> fileLines(File file) {
- try {
- return Files.lines(file.toPath());
- } catch (IOException io) {
- throw new PluginException("Couldn't read file");
- }
- }
-
- private void validateMethodType(String type) {
- String[] typeParts = type.split("_");
- // check return type (second part)
- if (typeParts.length != 2 || typeParts[1].length() != 1
- || "LJIFDV".indexOf(typeParts[1].charAt(0)) == -1) {
- throw new PluginException(
- "Method type signature must be of form [LJIFD]*_[LJIFDV]");
- }
- // expand and check arguments (first part)
- expandSignature(typeParts[0]);
- }
-
- private static void requireBasicType(char c) {
- if ("LIJFD".indexOf(c) < 0) {
- throw new PluginException(
- "Character " + c + " must correspond to a basic field type: LIJFD");
- }
- }
+ // Repeat def, we do not have access right to InvokerBytecodeGeneratorHelper
+ // Must be exact same!
+ private static final String DIRECT_METHOD_HOLDER_ENTRY =
+ "/java.base/java/lang/invoke/DirectMethodHandle$Holder.class";
+ private static final String DELEGATING_METHOD_HOLDER_ENTRY =
+ "/java.base/java/lang/invoke/DelegatingMethodHandle$Holder.class";
+ private static final String INVOKERS_HOLDER_ENTRY =
+ "/java.base/java/lang/invoke/Invokers$Holder.class";
+ private static final String BASIC_FORMS_HOLDER_ENTRY =
+ "/java.base/java/lang/invoke/LambdaForm$Holder.class";
@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
initialize(in);
// Copy all but DMH_ENTRY to out
@@ -273,215 +133,51 @@
} else {
return entry;
}
}, out);
- // Generate BMH Species classes
- speciesTypes.forEach(types -> generateBMHClass(types, out));
-
// Generate LambdaForm Holder classes
generateHolderClasses(out);
-
- // Let it go
- speciesTypes.clear();
- invokerTypes.clear();
- callSiteTypes.clear();
- dmhMethods.clear();
-
+ // clear input.
+ lines = null;
return out.build();
}
- private void generateBMHClass(String types, ResourcePoolBuilder out) {
- try {
- // Generate class
- Map.Entry<String, byte[]> result =
- JLIA.generateConcreteBMHClassBytes(types);
- String className = result.getKey();
- byte[] bytes = result.getValue();
-
- // Add class to pool
- ResourcePoolEntry ndata = ResourcePoolEntry.create(
- "/java.base/" + className + ".class",
- bytes);
- out.add(ndata);
- } catch (Exception ex) {
- throw new PluginException(ex);
- }
- }
-
private void generateHolderClasses(ResourcePoolBuilder out) {
- int count = 0;
- for (Set<String> entry : dmhMethods.values()) {
- count += entry.size();
- }
- MethodType[] directMethodTypes = new MethodType[count];
- int[] dmhTypes = new int[count];
- int index = 0;
- for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
- String dmhType = entry.getKey();
- for (String type : entry.getValue()) {
- // The DMH type to actually ask for is retrieved by removing
- // the first argument, which needs to be of Object.class
- MethodType mt = asMethodType(type);
- if (mt.parameterCount() < 1 ||
- mt.parameterType(0) != Object.class) {
- throw new PluginException(
- "DMH type parameter must start with L: " + dmhType + " " + type);
- }
-
- // Adapt the method type of the LF to retrieve
- directMethodTypes[index] = mt.dropParameterTypes(0, 1);
-
- // invokeVirtual and invokeInterface must have a leading Object
- // parameter, i.e., the receiver
- dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
- if (dmhTypes[index] == DMH_INVOKE_INTERFACE_TYPE ||
- dmhTypes[index] == DMH_INVOKE_VIRTUAL_TYPE) {
- if (mt.parameterCount() < 2 ||
- mt.parameterType(1) != Object.class) {
- throw new PluginException(
- "DMH type parameter must start with LL: " + dmhType + " " + type);
- }
- }
- index++;
- }
- }
-
- // The invoker type to ask for is retrieved by removing the first
- // and the last argument, which needs to be of Object.class
- MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
- int i = 0;
- for (String invokerType : invokerTypes) {
- MethodType mt = asMethodType(invokerType);
- final int lastParam = mt.parameterCount() - 1;
- if (mt.parameterCount() < 2 ||
- mt.parameterType(0) != Object.class ||
- mt.parameterType(lastParam) != Object.class) {
- throw new PluginException(
- "Invoker type parameter must start and end with Object: " + invokerType);
- }
- mt = mt.dropParameterTypes(lastParam, lastParam + 1);
- invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
- i++;
- }
-
- // The callSite type to ask for is retrieved by removing the last
- // argument, which needs to be of Object.class
- MethodType[] callSiteMethodTypes = new MethodType[this.callSiteTypes.size()];
- i = 0;
- for (String callSiteType : callSiteTypes) {
- MethodType mt = asMethodType(callSiteType);
- final int lastParam = mt.parameterCount() - 1;
- if (mt.parameterCount() < 1 ||
- mt.parameterType(lastParam) != Object.class) {
- throw new PluginException(
- "CallSite type parameter must end with Object: " + callSiteType);
- }
- callSiteMethodTypes[i] = mt.dropParameterTypes(lastParam, lastParam + 1);
- i++;
- }
try {
- byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
- DIRECT_HOLDER, directMethodTypes, dmhTypes);
- ResourcePoolEntry ndata = ResourcePoolEntry
- .create(DIRECT_METHOD_HOLDER_ENTRY, bytes);
- out.add(ndata);
-
- bytes = JLIA.generateDelegatingMethodHandleHolderClassBytes(
- DELEGATING_HOLDER, directMethodTypes);
- ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HOLDER_ENTRY, bytes);
- out.add(ndata);
-
- bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER_INTERNAL_NAME,
- invokerMethodTypes, callSiteMethodTypes);
- ndata = ResourcePoolEntry.create(INVOKERS_HOLDER_ENTRY, bytes);
- out.add(ndata);
-
- bytes = JLIA.generateBasicFormsClassBytes(BASIC_FORMS_HOLDER);
- ndata = ResourcePoolEntry.create(BASIC_FORMS_HOLDER_ENTRY, bytes);
+ Map<String, byte[]> result = JLIA.generateMethodHandleHolderClasses(lines);
+ if (result != null) {
+ result.forEach ((k,v) -> {
+ ResourcePoolEntry ndata = ResourcePoolEntry.create(k, v);
out.add(ndata);
+ });
+ }
} catch (Exception ex) {
throw new PluginException(ex);
}
}
- private static final String DIRECT_METHOD_HOLDER_ENTRY =
- "/java.base/" + DIRECT_HOLDER + ".class";
- private static final String DELEGATING_METHOD_HOLDER_ENTRY =
- "/java.base/" + DELEGATING_HOLDER + ".class";
- private static final String BASIC_FORMS_HOLDER_ENTRY =
- "/java.base/" + BASIC_FORMS_HOLDER + ".class";
- private static final String INVOKERS_HOLDER_ENTRY =
- "/java.base/" + INVOKERS_HOLDER_INTERNAL_NAME + ".class";
- // Convert LL -> LL, L3 -> LLL
- public static String expandSignature(String signature) {
- StringBuilder sb = new StringBuilder();
- char last = 'X';
- int count = 0;
- for (int i = 0; i < signature.length(); i++) {
- char c = signature.charAt(i);
- if (c >= '0' && c <= '9') {
- count *= 10;
- count += (c - '0');
- } else {
- requireBasicType(c);
- for (int j = 1; j < count; j++) {
- sb.append(last);
- }
- sb.append(c);
- last = c;
- count = 0;
- }
- }
-
- // ended with a number, e.g., "L2": append last char count - 1 times
- if (count > 1) {
- requireBasicType(last);
- for (int j = 1; j < count; j++) {
- sb.append(last);
- }
+ public void initialize(ResourcePool in) {
+ // Load configuration from the contents in the supplied input file
+ // - if none was supplied we look for the default file
+ if (mainArgument == null || !mainArgument.startsWith("@")) {
+ try (InputStream traceFile =
+ this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {
+ if (traceFile != null) {
+ lines = new BufferedReader(
+ new InputStreamReader(traceFile)).lines().toArray(String[]::new);
}
- return sb.toString();
+ } catch (Exception e) {
+ throw new PluginException("Couldn't read " + DEFAULT_TRACE_FILE, e);
}
-
- private static MethodType asMethodType(String basicSignatureString) {
- String[] parts = basicSignatureString.split("_");
- assert(parts.length == 2);
- assert(parts[1].length() == 1);
- String parameters = expandSignature(parts[0]);
- Class<?> rtype = simpleType(parts[1].charAt(0));
- if (parameters.isEmpty()) {
- return MethodType.methodType(rtype);
} else {
- Class<?>[] ptypes = new Class<?>[parameters.length()];
- for (int i = 0; i < ptypes.length; i++) {
- ptypes[i] = simpleType(parameters.charAt(i));
- }
- return MethodType.methodType(rtype, ptypes);
+ File file = new File(mainArgument.substring(1));
+ try {
+ if (file.exists()) {
+ lines = Files.readAllLines(file.toPath()).toArray(new String[0]);
}
+ } catch (Exception e) {
+ throw new PluginException("Couldn't read " + file.getName(), e);
}
-
- private static Class<?> simpleType(char c) {
- switch (c) {
- case 'F':
- return float.class;
- case 'D':
- return double.class;
- case 'I':
- return int.class;
- case 'L':
- return Object.class;
- case 'J':
- return long.class;
- case 'V':
- return void.class;
- case 'Z':
- case 'B':
- case 'S':
- case 'C':
- throw new IllegalArgumentException("Not a valid primitive: " + c +
- " (use I instead)");
- default:
- throw new IllegalArgumentException("Not a primitive: " + c);
}
}
}
< prev index next >