8232864: Classes generated at link time by GenerateJLIClassesPlugin are not reproducible
Reviewed-by: redestad, mchung
This commit is contained in:
parent
d83df45396
commit
66a4fd2b79
@ -36,7 +36,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.access.JavaLangInvokeAccess;
|
||||
@ -75,13 +74,13 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
private static final JavaLangInvokeAccess JLIA
|
||||
= SharedSecrets.getJavaLangInvokeAccess();
|
||||
|
||||
Set<String> speciesTypes = Set.of();
|
||||
private final TreeSet<String> speciesTypes = new TreeSet<>();
|
||||
|
||||
Set<String> invokerTypes = Set.of();
|
||||
private final TreeSet<String> invokerTypes = new TreeSet<>();
|
||||
|
||||
Set<String> callSiteTypes = Set.of();
|
||||
private final TreeSet<String> callSiteTypes = new TreeSet<>();
|
||||
|
||||
Map<String, Set<String>> dmhMethods = Map.of();
|
||||
private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
|
||||
|
||||
String mainArgument;
|
||||
|
||||
@ -187,21 +186,31 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
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) {
|
||||
// Start with the default configuration
|
||||
speciesTypes = defaultSpecies().stream()
|
||||
.map(type -> expandSignature(type))
|
||||
.collect(Collectors.toSet());
|
||||
defaultSpecies().stream().forEach(this::addSpeciesType);
|
||||
|
||||
invokerTypes = defaultInvokers();
|
||||
validateMethodTypes(invokerTypes);
|
||||
defaultInvokers().stream().forEach(this::validateMethodType);
|
||||
|
||||
callSiteTypes = defaultCallSiteTypes();
|
||||
defaultCallSiteTypes().stream().forEach(this::addCallSiteType);
|
||||
|
||||
dmhMethods = defaultDMHMethods();
|
||||
for (Set<String> dmhMethodTypes : dmhMethods.values()) {
|
||||
validateMethodTypes(dmhMethodTypes);
|
||||
}
|
||||
defaultDMHMethods().entrySet().stream().forEach(e -> {
|
||||
e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type));
|
||||
});
|
||||
|
||||
// Extend the default configuration with the contents in the supplied
|
||||
// input file - if none was supplied we look for the default file
|
||||
@ -225,18 +234,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
}
|
||||
|
||||
private void readTraceConfig(Stream<String> lines) {
|
||||
// Use TreeSet/TreeMap to keep things sorted in a deterministic
|
||||
// order to avoid scrambling the layout on small changes and to
|
||||
// ease finding methods in the generated code
|
||||
speciesTypes = new TreeSet<>(speciesTypes);
|
||||
invokerTypes = new TreeSet<>(invokerTypes);
|
||||
callSiteTypes = new TreeSet<>(callSiteTypes);
|
||||
|
||||
TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
|
||||
for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
|
||||
newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
|
||||
}
|
||||
dmhMethods = newDMHMethods;
|
||||
lines.map(line -> line.split(" "))
|
||||
.forEach(parts -> {
|
||||
switch (parts[0]) {
|
||||
@ -245,19 +242,18 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
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)) {
|
||||
speciesTypes.add(expandSignature(species));
|
||||
addSpeciesType(species);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "[LF_RESOLVE]":
|
||||
String methodType = parts[3];
|
||||
validateMethodType(methodType);
|
||||
if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
|
||||
if ("linkToTargetMethod".equals(parts[2]) ||
|
||||
"linkToCallSite".equals(parts[2])) {
|
||||
callSiteTypes.add(methodType);
|
||||
addCallSiteType(methodType);
|
||||
} else {
|
||||
invokerTypes.add(methodType);
|
||||
addInvokerType(methodType);
|
||||
}
|
||||
} else if (parts[1].contains("DirectMethodHandle")) {
|
||||
String dmh = parts[2];
|
||||
@ -291,12 +287,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodTypes(Set<String> dmhMethodTypes) {
|
||||
for (String type : dmhMethodTypes) {
|
||||
validateMethodType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodType(String type) {
|
||||
String[] typeParts = type.split("_");
|
||||
// check return type (second part)
|
||||
@ -340,9 +330,10 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
generateHolderClasses(out);
|
||||
|
||||
// Let it go
|
||||
speciesTypes = null;
|
||||
invokerTypes = null;
|
||||
dmhMethods = null;
|
||||
speciesTypes.clear();
|
||||
invokerTypes.clear();
|
||||
callSiteTypes.clear();
|
||||
dmhMethods.clear();
|
||||
|
||||
return out.build();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,7 +43,7 @@ public class JLinkReproducibleTest {
|
||||
res.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static void jlink(Path image) throws Exception {
|
||||
private static void jlink(Path image, boolean with_default_trace_file) throws Exception {
|
||||
var cmd = new ArrayList<String>();
|
||||
cmd.add(JDKToolFinder.getJDKTool("jlink"));
|
||||
cmd.addAll(List.of(
|
||||
@ -52,6 +52,9 @@ public class JLinkReproducibleTest {
|
||||
"--compress=2",
|
||||
"--output", image.toString()
|
||||
));
|
||||
if (!with_default_trace_file) {
|
||||
cmd.add("--generate-jli-classes=@file-not-exists");
|
||||
}
|
||||
run(cmd);
|
||||
}
|
||||
|
||||
@ -98,17 +101,31 @@ public class JLinkReproducibleTest {
|
||||
|
||||
// Link the first image
|
||||
var firstImage = Path.of("image-first");
|
||||
jlink(firstImage);
|
||||
jlink(firstImage, true);
|
||||
var firstModulesFile = firstImage.resolve("lib")
|
||||
.resolve("modules");
|
||||
|
||||
// Link the second image
|
||||
var secondImage = Path.of("image-second");
|
||||
jlink(secondImage);
|
||||
jlink(secondImage, true);
|
||||
var secondModulesFile = secondImage.resolve("lib")
|
||||
.resolve("modules");
|
||||
|
||||
// Ensure module files are identical
|
||||
assertEquals(-1L, Files.mismatch(firstModulesFile, secondModulesFile));
|
||||
|
||||
// Link the third image
|
||||
var thirdImage = Path.of("image-third");
|
||||
jlink(thirdImage, false);
|
||||
var thirdModulesFile = thirdImage.resolve("lib")
|
||||
.resolve("modules");
|
||||
// Link the fourth image
|
||||
var fourthImage = Path.of("image-fourth");
|
||||
jlink(fourthImage, false);
|
||||
var fourthModulesFile = fourthImage.resolve("lib")
|
||||
.resolve("modules");
|
||||
|
||||
// Ensure module files are identical
|
||||
assertEquals(-1L, Files.mismatch(thirdModulesFile, fourthModulesFile));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user