34 import java.util.EnumSet; |
34 import java.util.EnumSet; |
35 import java.util.Map; |
35 import java.util.Map; |
36 import java.util.Set; |
36 import java.util.Set; |
37 import java.util.TreeMap; |
37 import java.util.TreeMap; |
38 import java.util.TreeSet; |
38 import java.util.TreeSet; |
39 import java.util.stream.Collectors; |
|
40 import java.util.stream.Stream; |
39 import java.util.stream.Stream; |
41 import jdk.internal.access.SharedSecrets; |
40 import jdk.internal.access.SharedSecrets; |
42 import jdk.internal.access.JavaLangInvokeAccess; |
41 import jdk.internal.access.JavaLangInvokeAccess; |
43 import jdk.tools.jlink.plugin.ResourcePoolEntry; |
42 import jdk.tools.jlink.plugin.ResourcePoolEntry; |
44 import jdk.tools.jlink.plugin.PluginException; |
43 import jdk.tools.jlink.plugin.PluginException; |
73 private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/'); |
72 private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/'); |
74 |
73 |
75 private static final JavaLangInvokeAccess JLIA |
74 private static final JavaLangInvokeAccess JLIA |
76 = SharedSecrets.getJavaLangInvokeAccess(); |
75 = SharedSecrets.getJavaLangInvokeAccess(); |
77 |
76 |
78 Set<String> speciesTypes = Set.of(); |
77 private final TreeSet<String> speciesTypes = new TreeSet<>(); |
79 |
78 |
80 Set<String> invokerTypes = Set.of(); |
79 private final TreeSet<String> invokerTypes = new TreeSet<>(); |
81 |
80 |
82 Set<String> callSiteTypes = Set.of(); |
81 private final TreeSet<String> callSiteTypes = new TreeSet<>(); |
83 |
82 |
84 Map<String, Set<String>> dmhMethods = Map.of(); |
83 private final Map<String, Set<String>> dmhMethods = new TreeMap<>(); |
85 |
84 |
86 String mainArgument; |
85 String mainArgument; |
87 |
86 |
88 public GenerateJLIClassesPlugin() { |
87 public GenerateJLIClassesPlugin() { |
89 } |
88 } |
185 @Override |
184 @Override |
186 public void configure(Map<String, String> config) { |
185 public void configure(Map<String, String> config) { |
187 mainArgument = config.get(NAME); |
186 mainArgument = config.get(NAME); |
188 } |
187 } |
189 |
188 |
|
189 private void addSpeciesType(String type) { |
|
190 speciesTypes.add(expandSignature(type)); |
|
191 } |
|
192 |
|
193 private void addInvokerType(String methodType) { |
|
194 validateMethodType(methodType); |
|
195 invokerTypes.add(methodType); |
|
196 } |
|
197 |
|
198 private void addCallSiteType(String csType) { |
|
199 validateMethodType(csType); |
|
200 callSiteTypes.add(csType); |
|
201 } |
|
202 |
190 public void initialize(ResourcePool in) { |
203 public void initialize(ResourcePool in) { |
191 // Start with the default configuration |
204 // Start with the default configuration |
192 speciesTypes = defaultSpecies().stream() |
205 defaultSpecies().stream().forEach(this::addSpeciesType); |
193 .map(type -> expandSignature(type)) |
206 |
194 .collect(Collectors.toSet()); |
207 defaultInvokers().stream().forEach(this::validateMethodType); |
195 |
208 |
196 invokerTypes = defaultInvokers(); |
209 defaultCallSiteTypes().stream().forEach(this::addCallSiteType); |
197 validateMethodTypes(invokerTypes); |
210 |
198 |
211 defaultDMHMethods().entrySet().stream().forEach(e -> { |
199 callSiteTypes = defaultCallSiteTypes(); |
212 e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type)); |
200 |
213 }); |
201 dmhMethods = defaultDMHMethods(); |
|
202 for (Set<String> dmhMethodTypes : dmhMethods.values()) { |
|
203 validateMethodTypes(dmhMethodTypes); |
|
204 } |
|
205 |
214 |
206 // Extend the default configuration with the contents in the supplied |
215 // Extend the default configuration with the contents in the supplied |
207 // input file - if none was supplied we look for the default file |
216 // input file - if none was supplied we look for the default file |
208 if (mainArgument == null || !mainArgument.startsWith("@")) { |
217 if (mainArgument == null || !mainArgument.startsWith("@")) { |
209 try (InputStream traceFile = |
218 try (InputStream traceFile = |
223 } |
232 } |
224 } |
233 } |
225 } |
234 } |
226 |
235 |
227 private void readTraceConfig(Stream<String> lines) { |
236 private void readTraceConfig(Stream<String> lines) { |
228 // Use TreeSet/TreeMap to keep things sorted in a deterministic |
|
229 // order to avoid scrambling the layout on small changes and to |
|
230 // ease finding methods in the generated code |
|
231 speciesTypes = new TreeSet<>(speciesTypes); |
|
232 invokerTypes = new TreeSet<>(invokerTypes); |
|
233 callSiteTypes = new TreeSet<>(callSiteTypes); |
|
234 |
|
235 TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>(); |
|
236 for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) { |
|
237 newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue())); |
|
238 } |
|
239 dmhMethods = newDMHMethods; |
|
240 lines.map(line -> line.split(" ")) |
237 lines.map(line -> line.split(" ")) |
241 .forEach(parts -> { |
238 .forEach(parts -> { |
242 switch (parts[0]) { |
239 switch (parts[0]) { |
243 case "[SPECIES_RESOLVE]": |
240 case "[SPECIES_RESOLVE]": |
244 // Allow for new types of species data classes being resolved here |
241 // Allow for new types of species data classes being resolved here |
245 if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) { |
242 if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) { |
246 String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length()); |
243 String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length()); |
247 if (!"L".equals(species)) { |
244 if (!"L".equals(species)) { |
248 speciesTypes.add(expandSignature(species)); |
245 addSpeciesType(species); |
249 } |
246 } |
250 } |
247 } |
251 break; |
248 break; |
252 case "[LF_RESOLVE]": |
249 case "[LF_RESOLVE]": |
253 String methodType = parts[3]; |
250 String methodType = parts[3]; |
254 validateMethodType(methodType); |
|
255 if (parts[1].equals(INVOKERS_HOLDER_NAME)) { |
251 if (parts[1].equals(INVOKERS_HOLDER_NAME)) { |
256 if ("linkToTargetMethod".equals(parts[2]) || |
252 if ("linkToTargetMethod".equals(parts[2]) || |
257 "linkToCallSite".equals(parts[2])) { |
253 "linkToCallSite".equals(parts[2])) { |
258 callSiteTypes.add(methodType); |
254 addCallSiteType(methodType); |
259 } else { |
255 } else { |
260 invokerTypes.add(methodType); |
256 addInvokerType(methodType); |
261 } |
257 } |
262 } else if (parts[1].contains("DirectMethodHandle")) { |
258 } else if (parts[1].contains("DirectMethodHandle")) { |
263 String dmh = parts[2]; |
259 String dmh = parts[2]; |
264 // ignore getObject etc for now (generated |
260 // ignore getObject etc for now (generated |
265 // by default) |
261 // by default) |
286 private Stream<String> fileLines(File file) { |
282 private Stream<String> fileLines(File file) { |
287 try { |
283 try { |
288 return Files.lines(file.toPath()); |
284 return Files.lines(file.toPath()); |
289 } catch (IOException io) { |
285 } catch (IOException io) { |
290 throw new PluginException("Couldn't read file"); |
286 throw new PluginException("Couldn't read file"); |
291 } |
|
292 } |
|
293 |
|
294 private void validateMethodTypes(Set<String> dmhMethodTypes) { |
|
295 for (String type : dmhMethodTypes) { |
|
296 validateMethodType(type); |
|
297 } |
287 } |
298 } |
288 } |
299 |
289 |
300 private void validateMethodType(String type) { |
290 private void validateMethodType(String type) { |
301 String[] typeParts = type.split("_"); |
291 String[] typeParts = type.split("_"); |