Skip to content
Snippets Groups Projects
Commit 66a4fd2b authored by Jie Fu's avatar Jie Fu
Browse files

8232864: Classes generated at link time by GenerateJLIClassesPlugin are not reproducible

Reviewed-by: redestad, mchung
parent d83df453
No related branches found
No related tags found
No related merge requests found
...@@ -36,7 +36,6 @@ import java.util.Map; ...@@ -36,7 +36,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.JavaLangInvokeAccess;
...@@ -75,13 +74,13 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -75,13 +74,13 @@ public final class GenerateJLIClassesPlugin implements Plugin {
private static final JavaLangInvokeAccess JLIA private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess(); = 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; String mainArgument;
...@@ -187,21 +186,31 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -187,21 +186,31 @@ public final class GenerateJLIClassesPlugin implements Plugin {
mainArgument = config.get(NAME); 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) { public void initialize(ResourcePool in) {
// Start with the default configuration // Start with the default configuration
speciesTypes = defaultSpecies().stream() defaultSpecies().stream().forEach(this::addSpeciesType);
.map(type -> expandSignature(type))
.collect(Collectors.toSet());
invokerTypes = defaultInvokers(); defaultInvokers().stream().forEach(this::validateMethodType);
validateMethodTypes(invokerTypes);
callSiteTypes = defaultCallSiteTypes(); defaultCallSiteTypes().stream().forEach(this::addCallSiteType);
dmhMethods = defaultDMHMethods(); defaultDMHMethods().entrySet().stream().forEach(e -> {
for (Set<String> dmhMethodTypes : dmhMethods.values()) { e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type));
validateMethodTypes(dmhMethodTypes); });
}
// Extend the default configuration with the contents in the supplied // Extend the default configuration with the contents in the supplied
// input file - if none was supplied we look for the default file // input file - if none was supplied we look for the default file
...@@ -225,18 +234,6 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -225,18 +234,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
} }
private void readTraceConfig(Stream<String> lines) { 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(" ")) lines.map(line -> line.split(" "))
.forEach(parts -> { .forEach(parts -> {
switch (parts[0]) { switch (parts[0]) {
...@@ -245,19 +242,18 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -245,19 +242,18 @@ public final class GenerateJLIClassesPlugin implements Plugin {
if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) { if (parts.length == 3 && parts[1].startsWith("java.lang.invoke.BoundMethodHandle$Species_")) {
String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length()); String species = parts[1].substring("java.lang.invoke.BoundMethodHandle$Species_".length());
if (!"L".equals(species)) { if (!"L".equals(species)) {
speciesTypes.add(expandSignature(species)); addSpeciesType(species);
} }
} }
break; break;
case "[LF_RESOLVE]": case "[LF_RESOLVE]":
String methodType = parts[3]; String methodType = parts[3];
validateMethodType(methodType);
if (parts[1].equals(INVOKERS_HOLDER_NAME)) { if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
if ("linkToTargetMethod".equals(parts[2]) || if ("linkToTargetMethod".equals(parts[2]) ||
"linkToCallSite".equals(parts[2])) { "linkToCallSite".equals(parts[2])) {
callSiteTypes.add(methodType); addCallSiteType(methodType);
} else { } else {
invokerTypes.add(methodType); addInvokerType(methodType);
} }
} else if (parts[1].contains("DirectMethodHandle")) { } else if (parts[1].contains("DirectMethodHandle")) {
String dmh = parts[2]; String dmh = parts[2];
...@@ -291,12 +287,6 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -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) { private void validateMethodType(String type) {
String[] typeParts = type.split("_"); String[] typeParts = type.split("_");
// check return type (second part) // check return type (second part)
...@@ -340,9 +330,10 @@ public final class GenerateJLIClassesPlugin implements Plugin { ...@@ -340,9 +330,10 @@ public final class GenerateJLIClassesPlugin implements Plugin {
generateHolderClasses(out); generateHolderClasses(out);
// Let it go // Let it go
speciesTypes = null; speciesTypes.clear();
invokerTypes = null; invokerTypes.clear();
dmhMethods = null; callSiteTypes.clear();
dmhMethods.clear();
return out.build(); return out.build();
} }
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -43,7 +43,7 @@ public class JLinkReproducibleTest { ...@@ -43,7 +43,7 @@ public class JLinkReproducibleTest {
res.shouldHaveExitValue(0); 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>(); var cmd = new ArrayList<String>();
cmd.add(JDKToolFinder.getJDKTool("jlink")); cmd.add(JDKToolFinder.getJDKTool("jlink"));
cmd.addAll(List.of( cmd.addAll(List.of(
...@@ -52,6 +52,9 @@ public class JLinkReproducibleTest { ...@@ -52,6 +52,9 @@ public class JLinkReproducibleTest {
"--compress=2", "--compress=2",
"--output", image.toString() "--output", image.toString()
)); ));
if (!with_default_trace_file) {
cmd.add("--generate-jli-classes=@file-not-exists");
}
run(cmd); run(cmd);
} }
...@@ -98,17 +101,31 @@ public class JLinkReproducibleTest { ...@@ -98,17 +101,31 @@ public class JLinkReproducibleTest {
// Link the first image // Link the first image
var firstImage = Path.of("image-first"); var firstImage = Path.of("image-first");
jlink(firstImage); jlink(firstImage, true);
var firstModulesFile = firstImage.resolve("lib") var firstModulesFile = firstImage.resolve("lib")
.resolve("modules"); .resolve("modules");
// Link the second image // Link the second image
var secondImage = Path.of("image-second"); var secondImage = Path.of("image-second");
jlink(secondImage); jlink(secondImage, true);
var secondModulesFile = secondImage.resolve("lib") var secondModulesFile = secondImage.resolve("lib")
.resolve("modules"); .resolve("modules");
// Ensure module files are identical // Ensure module files are identical
assertEquals(-1L, Files.mismatch(firstModulesFile, secondModulesFile)); 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));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment