Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
41159 views
1
/*
2
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package jdk.internal.module;
27
28
import java.io.PrintStream;
29
import java.lang.module.Configuration;
30
import java.lang.module.ModuleReference;
31
import java.lang.module.ResolvedModule;
32
import java.util.ArrayDeque;
33
import java.util.Collections;
34
import java.util.Deque;
35
import java.util.HashMap;
36
import java.util.TreeMap;
37
import java.util.HashSet;
38
import java.util.Map;
39
import java.util.Set;
40
import java.util.function.Consumer;
41
import java.util.stream.Stream;
42
import static java.util.stream.Collectors.*;
43
44
/**
45
* A Builder to compute ModuleHashes from a given configuration
46
*/
47
public class ModuleHashesBuilder {
48
private final Configuration configuration;
49
private final Set<String> hashModuleCandidates;
50
51
/**
52
* Constructs a ModuleHashesBuilder that finds the packaged modules
53
* from the location of ModuleReference found from the given Configuration.
54
*
55
* @param config Configuration for building module hashes
56
* @param modules the candidate modules to be hashed
57
*/
58
public ModuleHashesBuilder(Configuration config, Set<String> modules) {
59
this.configuration = config;
60
this.hashModuleCandidates = modules;
61
}
62
63
/**
64
* Returns a map of a module M to ModuleHashes for the modules
65
* that depend upon M directly or indirectly.
66
*
67
* The key for each entry in the returned map is a module M that has
68
* no outgoing edges to any of the candidate modules to be hashed
69
* i.e. M is a leaf node in a connected subgraph containing M and
70
* other candidate modules from the module graph filtering
71
* the outgoing edges from M to non-candidate modules.
72
*/
73
public Map<String, ModuleHashes> computeHashes(Set<String> roots) {
74
// build a graph containing the packaged modules and
75
// its transitive dependences matching --hash-modules
76
Graph.Builder<String> builder = new Graph.Builder<>();
77
Deque<ResolvedModule> todo = new ArrayDeque<>(configuration.modules());
78
Set<ResolvedModule> visited = new HashSet<>();
79
ResolvedModule rm;
80
while ((rm = todo.poll()) != null) {
81
if (visited.add(rm)) {
82
builder.addNode(rm.name());
83
for (ResolvedModule dm : rm.reads()) {
84
if (!visited.contains(dm)) {
85
todo.push(dm);
86
}
87
builder.addEdge(rm.name(), dm.name());
88
}
89
}
90
}
91
92
// each node in a transposed graph is a matching packaged module
93
// in which the hash of the modules that depend upon it is recorded
94
Graph<String> transposedGraph = builder.build().transpose();
95
96
// traverse the modules in topological order that will identify
97
// the modules to record the hashes - it is the first matching
98
// module and has not been hashed during the traversal.
99
Set<String> mods = new HashSet<>();
100
Map<String, ModuleHashes> hashes = new TreeMap<>();
101
builder.build()
102
.orderedNodes()
103
.filter(mn -> roots.contains(mn) && !mods.contains(mn))
104
.forEach(mn -> {
105
// Compute hashes of the modules that depend on mn directly and
106
// indirectly excluding itself.
107
Set<String> ns = transposedGraph.dfs(mn)
108
.stream()
109
.filter(n -> !n.equals(mn) && hashModuleCandidates.contains(n))
110
.collect(toSet());
111
mods.add(mn);
112
mods.addAll(ns);
113
114
if (!ns.isEmpty()) {
115
Set<ModuleReference> mrefs = ns.stream()
116
.map(name -> configuration.findModule(name)
117
.orElseThrow(InternalError::new))
118
.map(ResolvedModule::reference)
119
.collect(toSet());
120
hashes.put(mn, ModuleHashes.generate(mrefs, "SHA-256"));
121
}
122
});
123
return hashes;
124
}
125
126
/*
127
* Utility class
128
*/
129
static class Graph<T> {
130
private final Set<T> nodes;
131
private final Map<T, Set<T>> edges;
132
133
public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
134
this.nodes = Collections.unmodifiableSet(nodes);
135
this.edges = Collections.unmodifiableMap(edges);
136
}
137
138
public Set<T> nodes() {
139
return nodes;
140
}
141
142
public Map<T, Set<T>> edges() {
143
return edges;
144
}
145
146
public Set<T> adjacentNodes(T u) {
147
return edges.get(u);
148
}
149
150
public boolean contains(T u) {
151
return nodes.contains(u);
152
}
153
154
/**
155
* Returns nodes sorted in topological order.
156
*/
157
public Stream<T> orderedNodes() {
158
TopoSorter<T> sorter = new TopoSorter<>(this);
159
return sorter.result.stream();
160
}
161
162
/**
163
* Traverses this graph and performs the given action in topological order.
164
*/
165
public void ordered(Consumer<T> action) {
166
TopoSorter<T> sorter = new TopoSorter<>(this);
167
sorter.ordered(action);
168
}
169
170
/**
171
* Traverses this graph and performs the given action in reverse topological order.
172
*/
173
public void reverse(Consumer<T> action) {
174
TopoSorter<T> sorter = new TopoSorter<>(this);
175
sorter.reverse(action);
176
}
177
178
/**
179
* Returns a transposed graph from this graph.
180
*/
181
public Graph<T> transpose() {
182
Builder<T> builder = new Builder<>();
183
nodes.forEach(builder::addNode);
184
// reverse edges
185
edges.keySet().forEach(u -> {
186
edges.get(u).forEach(v -> builder.addEdge(v, u));
187
});
188
return builder.build();
189
}
190
191
/**
192
* Returns all nodes reachable from the given root.
193
*/
194
public Set<T> dfs(T root) {
195
return dfs(Set.of(root));
196
}
197
198
/**
199
* Returns all nodes reachable from the given set of roots.
200
*/
201
public Set<T> dfs(Set<T> roots) {
202
ArrayDeque<T> todo = new ArrayDeque<>(roots);
203
Set<T> visited = new HashSet<>();
204
T u;
205
while ((u = todo.poll()) != null) {
206
if (visited.add(u) && contains(u)) {
207
adjacentNodes(u).stream()
208
.filter(v -> !visited.contains(v))
209
.forEach(todo::push);
210
}
211
}
212
return visited;
213
}
214
215
public void printGraph(PrintStream out) {
216
out.println("graph for " + nodes);
217
nodes
218
.forEach(u -> adjacentNodes(u)
219
.forEach(v -> out.format(" %s -> %s%n", u, v)));
220
}
221
222
static class Builder<T> {
223
final Set<T> nodes = new HashSet<>();
224
final Map<T, Set<T>> edges = new HashMap<>();
225
226
public void addNode(T node) {
227
if (nodes.add(node)) {
228
edges.computeIfAbsent(node, _e -> new HashSet<>());
229
}
230
}
231
232
public void addEdge(T u, T v) {
233
addNode(u);
234
addNode(v);
235
edges.get(u).add(v);
236
}
237
238
public Graph<T> build() {
239
return new Graph<T>(nodes, edges);
240
}
241
}
242
}
243
244
/**
245
* Topological sort
246
*/
247
private static class TopoSorter<T> {
248
final Deque<T> result = new ArrayDeque<>();
249
final Graph<T> graph;
250
251
TopoSorter(Graph<T> graph) {
252
this.graph = graph;
253
sort();
254
}
255
256
public void ordered(Consumer<T> action) {
257
result.forEach(action);
258
}
259
260
public void reverse(Consumer<T> action) {
261
result.descendingIterator().forEachRemaining(action);
262
}
263
264
private void sort() {
265
Set<T> visited = new HashSet<>();
266
Deque<T> stack = new ArrayDeque<>();
267
graph.nodes.forEach(node -> visit(node, visited, stack));
268
}
269
270
private Set<T> children(T node) {
271
return graph.edges().get(node);
272
}
273
274
private void visit(T node, Set<T> visited, Deque<T> stack) {
275
if (visited.add(node)) {
276
stack.push(node);
277
children(node).forEach(child -> visit(child, visited, stack));
278
stack.pop();
279
result.addLast(node);
280
}
281
else if (stack.contains(node)) {
282
throw new IllegalArgumentException(
283
"Cycle detected: " + node + " -> " + children(node));
284
}
285
}
286
}
287
}
288
289