Backport from openjdk 10 --- orig/jdk-3cc80be736f2/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleSorter.java 1970-01-01 01:00:01.000000000 +0100 +++ jdk-3cc80be736f2/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleSorter.java 2022-04-12 20:48:04.474353305 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, 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 @@ -30,13 +30,16 @@ import jdk.tools.jlink.plugin.ResourcePoolModuleView; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.nio.ByteBuffer; -import java.util.Deque; +import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Stream; @@ -45,9 +48,8 @@ * Helper class to sort modules in topological order */ public final class ModuleSorter { - private final Deque nodes = new LinkedList<>(); - private final Map> edges = new HashMap<>(); - private final Deque result = new LinkedList<>(); + private final Map> graph = new HashMap<>(); + private final List result = new ArrayList<>(); private final ResourcePoolModuleView moduleView; @@ -69,11 +71,17 @@ private ModuleSorter addModule(ResourcePoolModule module) { addNode(module); - readModuleDescriptor(module).requires().forEach(req -> { + // the module graph will be traversed in a stable order for + // the topological sort. So add the dependences in the module name order + readModuleDescriptor(module).requires() + .stream() + .sorted(Comparator.comparing(Requires::name)) + .forEach(req -> + { ResourcePoolModule dep = moduleView.findModule(req.name()).orElse(null); if (dep != null) { addNode(dep); - edges.get(module.name()).add(dep); + graph.get(module).add(dep); } else if (!req.modifiers().contains(Modifier.STATIC)) { throw new PluginException(req.name() + " not found"); } @@ -82,22 +90,23 @@ } private void addNode(ResourcePoolModule module) { - nodes.add(module); - edges.computeIfAbsent(module.name(), _n -> new HashSet<>()); + graph.computeIfAbsent(module, _n -> new LinkedHashSet<>()); } + /* + * The module graph will be traversed in a stable order + * (traversing the modules and their dependences in alphabetical order) + * so that it will produce the same result of a given module graph. + */ private synchronized void build() { - if (!result.isEmpty() || nodes.isEmpty()) + if (!result.isEmpty() || graph.isEmpty()) return; - Deque visited = new LinkedList<>(); - Deque done = new LinkedList<>(); - ResourcePoolModule node; - while ((node = nodes.poll()) != null) { - if (!visited.contains(node)) { - visit(node, visited, done); - } - } + Set visited = new HashSet<>(); + Set done = new HashSet<>(); + graph.keySet().stream() + .sorted(Comparator.comparing(ResourcePoolModule::name)) + .forEach(node -> visit(node, visited, done)); } public Stream sorted() { @@ -106,19 +115,21 @@ } private void visit(ResourcePoolModule node, - Deque visited, - Deque done) { + Set visited, + Set done) { if (visited.contains(node)) { if (!done.contains(node)) { throw new IllegalArgumentException("Cyclic detected: " + - node + " " + edges.get(node.name())); + node + " " + graph.get(node)); } return; } + + // traverse the dependences of the given module which are + // also sorted in alphabetical order visited.add(node); - edges.get(node.name()) - .forEach(x -> visit(x, visited, done)); + graph.get(node).forEach(x -> visit(x, visited, done)); done.add(node); - result.addLast(node); + result.add(node); } }