Skip to content

Commit b81f4fa

Browse files
david-beaumontjaikiran
authored andcommitted
8360037: Refactor ImageReader in preparation for Valhalla support
Reviewed-by: alanb, rriggs, jpai
1 parent 5a44219 commit b81f4fa

File tree

10 files changed

+870
-616
lines changed

10 files changed

+870
-616
lines changed

src/java.base/share/classes/jdk/internal/jimage/ImageReader.java

Lines changed: 482 additions & 517 deletions
Large diffs are not rendered by default.

src/java.base/share/classes/jdk/internal/jrtfs/ExplodedImage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ byte[] getContent() throws IOException {
119119
}
120120

121121
@Override
122-
public List<Node> getChildren() {
122+
public Stream<String> getChildNames() {
123123
if (!isDirectory())
124-
throw new IllegalArgumentException("not a directory: " + getNameString());
124+
throw new IllegalArgumentException("not a directory: " + getName());
125125
if (children == null) {
126126
List<Node> list = new ArrayList<>();
127127
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
@@ -138,7 +138,7 @@ public List<Node> getChildren() {
138138
}
139139
children = list;
140140
}
141-
return children;
141+
return children.stream().map(Node::getName);
142142
}
143143

144144
@Override

src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,7 @@ final class JrtFileAttributes implements BasicFileAttributes {
4949
//-------- basic attributes --------
5050
@Override
5151
public FileTime creationTime() {
52-
return node.creationTime();
52+
return node.getFileAttributes().creationTime();
5353
}
5454

5555
@Override
@@ -69,12 +69,12 @@ public boolean isRegularFile() {
6969

7070
@Override
7171
public FileTime lastAccessTime() {
72-
return node.lastAccessTime();
72+
return node.getFileAttributes().lastAccessTime();
7373
}
7474

7575
@Override
7676
public FileTime lastModifiedTime() {
77-
return node.lastModifiedTime();
77+
return node.getFileAttributes().lastModifiedTime();
7878
}
7979

8080
@Override

src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
import java.nio.file.attribute.FileTime;
5555
import java.nio.file.attribute.UserPrincipalLookupService;
5656
import java.nio.file.spi.FileSystemProvider;
57-
import java.util.ArrayList;
5857
import java.util.Arrays;
5958
import java.util.Collections;
6059
import java.util.HashSet;
@@ -64,7 +63,6 @@
6463
import java.util.Set;
6564
import java.util.regex.Pattern;
6665
import jdk.internal.jimage.ImageReader.Node;
67-
import static java.util.stream.Collectors.toList;
6866

6967
/**
7068
* jrt file system implementation built on System jimage files.
@@ -225,19 +223,19 @@ Iterator<Path> iteratorOf(JrtPath path, DirectoryStream.Filter<? super Path> fil
225223
throw new NotDirectoryException(path.getName());
226224
}
227225
if (filter == null) {
228-
return node.getChildren()
229-
.stream()
230-
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
231-
.iterator();
226+
return node.getChildNames()
227+
.map(child -> (Path) (path.resolve(new JrtPath(this, child).getFileName())))
228+
.iterator();
232229
}
233-
return node.getChildren()
234-
.stream()
235-
.map(child -> (Path)(path.resolve(new JrtPath(this, child.getNameString()).getFileName())))
236-
.filter(p -> { try { return filter.accept(p);
237-
} catch (IOException x) {}
238-
return false;
239-
})
240-
.iterator();
230+
return node.getChildNames()
231+
.map(child -> (Path) (path.resolve(new JrtPath(this, child).getFileName())))
232+
.filter(p -> {
233+
try {
234+
return filter.accept(p);
235+
} catch (IOException x) {}
236+
return false;
237+
})
238+
.iterator();
241239
}
242240

243241
// returns the content of the file resource specified by the path

src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ static SystemImage open() throws IOException {
5858
if (modulesImageExists) {
5959
// open a .jimage and build directory structure
6060
final ImageReader image = ImageReader.open(moduleImageFile);
61-
image.getRootDirectory();
6261
return new SystemImage() {
6362
@Override
6463
Node findNode(String path) throws IOException {

src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@
3434
import java.lang.module.ModuleReference;
3535
import java.lang.reflect.Constructor;
3636
import java.net.URI;
37-
import java.net.URLConnection;
3837
import java.nio.ByteBuffer;
3938
import java.nio.file.Files;
4039
import java.nio.file.Path;
@@ -54,7 +53,6 @@
5453
import java.util.stream.Stream;
5554
import java.util.stream.StreamSupport;
5655

57-
import jdk.internal.jimage.ImageLocation;
5856
import jdk.internal.jimage.ImageReader;
5957
import jdk.internal.jimage.ImageReaderFactory;
6058
import jdk.internal.access.JavaNetUriAccess;
@@ -210,7 +208,7 @@ public static ModuleFinder ofSystem() {
210208
}
211209

212210
/**
213-
* Parses the module-info.class of all module in the runtime image and
211+
* Parses the {@code module-info.class} of all modules in the runtime image and
214212
* returns a ModuleFinder to find the modules.
215213
*
216214
* @apiNote The returned ModuleFinder is thread safe.
@@ -219,20 +217,16 @@ private static ModuleFinder ofModuleInfos() {
219217
// parse the module-info.class in every module
220218
Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
221219
Map<String, byte[]> nameToHash = new HashMap<>();
222-
ImageReader reader = SystemImage.reader();
223-
for (String mn : reader.getModuleNames()) {
224-
ImageLocation loc = reader.findLocation(mn, "module-info.class");
225-
ModuleInfo.Attributes attrs
226-
= ModuleInfo.read(reader.getResourceBuffer(loc), null);
227220

228-
nameToAttributes.put(mn, attrs);
221+
allModuleAttributes().forEach(attrs -> {
222+
nameToAttributes.put(attrs.descriptor().name(), attrs);
229223
ModuleHashes hashes = attrs.recordedHashes();
230224
if (hashes != null) {
231225
for (String name : hashes.names()) {
232226
nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
233227
}
234228
}
235-
}
229+
});
236230

237231
// create a ModuleReference for each module
238232
Set<ModuleReference> mrefs = new HashSet<>();
@@ -253,6 +247,40 @@ private static ModuleFinder ofModuleInfos() {
253247
return new SystemModuleFinder(mrefs, nameToModule);
254248
}
255249

250+
/**
251+
* Parses the {@code module-info.class} of all modules in the runtime image and
252+
* returns a stream of {@link ModuleInfo.Attributes Attributes} for them. The
253+
* returned attributes are in no specific order.
254+
*/
255+
private static Stream<ModuleInfo.Attributes> allModuleAttributes() {
256+
// System-wide image reader.
257+
ImageReader reader = SystemImage.reader();
258+
try {
259+
return reader.findNode("/modules")
260+
.getChildNames()
261+
.map(mn -> readModuleAttributes(reader, mn));
262+
} catch (IOException e) {
263+
throw new Error("Error reading root /modules entry", e);
264+
}
265+
}
266+
267+
/**
268+
* Returns the module's "module-info", returning a holder for its class file
269+
* attributes. Every module is required to have a valid {@code module-info.class}.
270+
*/
271+
private static ModuleInfo.Attributes readModuleAttributes(ImageReader reader, String moduleName) {
272+
Exception err = null;
273+
try {
274+
ImageReader.Node node = reader.findNode(moduleName + "/module-info.class");
275+
if (node != null && node.isResource()) {
276+
return ModuleInfo.read(reader.getResourceBuffer(node), null);
277+
}
278+
} catch (IOException | UncheckedIOException e) {
279+
err = e;
280+
}
281+
throw new Error("Missing or invalid module-info.class for module: " + moduleName, err);
282+
}
283+
256284
/**
257285
* A ModuleFinder that finds module in an array or set of modules.
258286
*/
@@ -382,34 +410,18 @@ private static class SystemModuleReader implements ModuleReader {
382410
this.module = module;
383411
}
384412

385-
/**
386-
* Returns the ImageLocation for the given resource, {@code null}
387-
* if not found.
388-
*/
389-
private ImageLocation findImageLocation(String name) throws IOException {
390-
Objects.requireNonNull(name);
391-
if (closed)
392-
throw new IOException("ModuleReader is closed");
393-
ImageReader imageReader = SystemImage.reader();
394-
if (imageReader != null) {
395-
return imageReader.findLocation(module, name);
396-
} else {
397-
// not an images build
398-
return null;
399-
}
400-
}
401-
402413
/**
403414
* Returns {@code true} if the given resource exists, {@code false}
404415
* if not found.
405416
*/
406-
private boolean containsImageLocation(String name) throws IOException {
407-
Objects.requireNonNull(name);
417+
private boolean containsResource(String resourcePath) throws IOException {
418+
Objects.requireNonNull(resourcePath);
408419
if (closed)
409420
throw new IOException("ModuleReader is closed");
410421
ImageReader imageReader = SystemImage.reader();
411422
if (imageReader != null) {
412-
return imageReader.verifyLocation(module, name);
423+
ImageReader.Node node = imageReader.findNode("/modules" + resourcePath);
424+
return node != null && node.isResource();
413425
} else {
414426
// not an images build
415427
return false;
@@ -418,8 +430,9 @@ private boolean containsImageLocation(String name) throws IOException {
418430

419431
@Override
420432
public Optional<URI> find(String name) throws IOException {
421-
if (containsImageLocation(name)) {
422-
URI u = JNUA.create("jrt", "/" + module + "/" + name);
433+
String resourcePath = "/" + module + "/" + name;
434+
if (containsResource(resourcePath)) {
435+
URI u = JNUA.create("jrt", resourcePath);
423436
return Optional.of(u);
424437
} else {
425438
return Optional.empty();
@@ -442,14 +455,25 @@ private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
442455
}
443456
}
444457

458+
/**
459+
* Returns the node for the given resource if found. If the name references
460+
* a non-resource node, then {@code null} is returned.
461+
*/
462+
private ImageReader.Node findResource(ImageReader reader, String name) throws IOException {
463+
Objects.requireNonNull(name);
464+
if (closed) {
465+
throw new IOException("ModuleReader is closed");
466+
}
467+
String nodeName = "/modules/" + module + "/" + name;
468+
ImageReader.Node node = reader.findNode(nodeName);
469+
return (node != null && node.isResource()) ? node : null;
470+
}
471+
445472
@Override
446473
public Optional<ByteBuffer> read(String name) throws IOException {
447-
ImageLocation location = findImageLocation(name);
448-
if (location != null) {
449-
return Optional.of(SystemImage.reader().getResourceBuffer(location));
450-
} else {
451-
return Optional.empty();
452-
}
474+
ImageReader reader = SystemImage.reader();
475+
return Optional.ofNullable(findResource(reader, name))
476+
.map(reader::getResourceBuffer);
453477
}
454478

455479
@Override
@@ -481,7 +505,7 @@ public void close() {
481505
private static class ModuleContentSpliterator implements Spliterator<String> {
482506
final String moduleRoot;
483507
final Deque<ImageReader.Node> stack;
484-
Iterator<ImageReader.Node> iterator;
508+
Iterator<String> iterator;
485509

486510
ModuleContentSpliterator(String module) throws IOException {
487511
moduleRoot = "/modules/" + module;
@@ -502,13 +526,10 @@ private static class ModuleContentSpliterator implements Spliterator<String> {
502526
private String next() throws IOException {
503527
for (;;) {
504528
while (iterator.hasNext()) {
505-
ImageReader.Node node = iterator.next();
506-
String name = node.getName();
529+
String name = iterator.next();
530+
ImageReader.Node node = SystemImage.reader().findNode(name);
507531
if (node.isDirectory()) {
508-
// build node
509-
ImageReader.Node dir = SystemImage.reader().findNode(name);
510-
assert dir.isDirectory();
511-
stack.push(dir);
532+
stack.push(node);
512533
} else {
513534
// strip /modules/$MODULE/ prefix
514535
return name.substring(moduleRoot.length() + 1);
@@ -520,7 +541,7 @@ private String next() throws IOException {
520541
} else {
521542
ImageReader.Node dir = stack.poll();
522543
assert dir.isDirectory();
523-
iterator = dir.getChildren().iterator();
544+
iterator = dir.getChildNames().iterator();
524545
}
525546
}
526547
}

0 commit comments

Comments
 (0)