# HG changeset patch # User jiefu # Date 1572369207 25200 # Node ID 63994dedec49c0604622679c5b56820d66f2840b # Parent 6c255334120dc8058996750304150bc9f63a3205 8232864: Classes generated at link time by GenerateJLIClassesPlugin are not reproducible Reviewed-by: redestad, mchung diff -r 6c255334120d -r 63994dedec49 src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Tue Oct 29 08:26:55 2019 -0700 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Tue Oct 29 10:13:27 2019 -0700 @@ -36,7 +36,6 @@ 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 @@ private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); - Set speciesTypes = Set.of(); + private final TreeSet speciesTypes = new TreeSet<>(); - Set invokerTypes = Set.of(); + private final TreeSet invokerTypes = new TreeSet<>(); - Set callSiteTypes = Set.of(); + private final TreeSet callSiteTypes = new TreeSet<>(); - Map> dmhMethods = Map.of(); + private final Map> dmhMethods = new TreeMap<>(); String mainArgument; @@ -187,21 +186,31 @@ 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 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 @@ } private void readTraceConfig(Stream 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> newDMHMethods = new TreeMap<>(); - for (Map.Entry> 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 @@ 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 @@ } } - private void validateMethodTypes(Set 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 @@ generateHolderClasses(out); // Let it go - speciesTypes = null; - invokerTypes = null; - dmhMethods = null; + speciesTypes.clear(); + invokerTypes.clear(); + callSiteTypes.clear(); + dmhMethods.clear(); return out.build(); } diff -r 6c255334120d -r 63994dedec49 test/jdk/tools/jlink/JLinkReproducibleTest.java --- a/test/jdk/tools/jlink/JLinkReproducibleTest.java Tue Oct 29 08:26:55 2019 -0700 +++ b/test/jdk/tools/jlink/JLinkReproducibleTest.java Tue Oct 29 10:13:27 2019 -0700 @@ -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 @@ 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(); cmd.add(JDKToolFinder.getJDKTool("jlink")); cmd.addAll(List.of( @@ -52,6 +52,9 @@ "--compress=2", "--output", image.toString() )); + if (!with_default_trace_file) { + cmd.add("--generate-jli-classes=@file-not-exists"); + } run(cmd); } @@ -98,17 +101,31 @@ // 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)); } }