Skip to content

Commit b32d27c

Browse files
Roll up of makefile and test fix (temporary)
* likely test fix * Copy value classes into preview directories for inclusion in jimage
1 parent c1f4189 commit b32d27c

File tree

11 files changed

+516
-362
lines changed

11 files changed

+516
-362
lines changed

make/CompileJavaModules.gmk

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,16 @@ endif
9999

100100
################################################################################
101101
# Setup the main compilation
102+
103+
COMPILATION_OUTPUTDIR := $(if $($(MODULE)_BIN), $($(MODULE)_BIN), $(JDK_OUTPUTDIR)/modules)
104+
102105
$(eval $(call SetupJavaCompilation, $(MODULE), \
103106
SMALL_JAVA := false, \
104107
MODULE := $(MODULE), \
105108
SRC := $(wildcard $(MODULE_SRC_DIRS)), \
106109
INCLUDES := $(JDK_USER_DEFINED_FILTER), \
107110
FAIL_NO_SRC := $(FAIL_NO_SRC), \
108-
BIN := $(if $($(MODULE)_BIN), $($(MODULE)_BIN), $(JDK_OUTPUTDIR)/modules), \
111+
BIN := $(COMPILATION_OUTPUTDIR), \
109112
HEADERS := $(SUPPORT_OUTPUTDIR)/headers, \
110113
CREATE_API_DIGEST := true, \
111114
CLEAN := $(CLEAN), \
@@ -138,14 +141,23 @@ ifneq ($(COMPILER), bootjdk)
138141
MODULE_VALUECLASS_SRC_DIRS := $(call FindModuleValueClassSrcDirs, $(MODULE))
139142
MODULE_VALUECLASS_SOURCEPATH := $(call GetModuleValueClassSrcPath)
140143

144+
# Temporarily compile valueclasses into a separate directory with the form:
145+
# <tempdir>/<module>/<classpath>
146+
# and then copy the class files into:
147+
# <outdir>/<module>/META-INF/preview/<classpath>
148+
# We cannot compile directly into the desired directory because it's the
149+
# compiler which creates the original '<module>/<classpath>/...' hierarchy.
150+
VALUECLASS_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/$(VALUECLASSES_STR)
151+
PREVIEW_OUTPUTDIR := $(COMPILATION_OUTPUTDIR)/$(MODULE)/META-INF/preview
152+
141153
ifneq ($(MODULE_VALUECLASS_SRC_DIRS),)
142154
$(eval $(call SetupJavaCompilation, $(MODULE)-$(VALUECLASSES_STR), \
143155
SMALL_JAVA := false, \
144156
MODULE := $(MODULE), \
145157
SRC := $(wildcard $(MODULE_VALUECLASS_SRC_DIRS)), \
146158
INCLUDES := $(JDK_USER_DEFINED_FILTER), \
147159
FAIL_NO_SRC := $(FAIL_NO_SRC), \
148-
BIN := $(SUPPORT_OUTPUTDIR)/$(VALUECLASSES_STR)/, \
160+
BIN := $(VALUECLASS_OUTPUTDIR)/, \
149161
JAR := $(JDK_OUTPUTDIR)/lib/$(VALUECLASSES_STR)/$(MODULE)-$(VALUECLASSES_STR).jar, \
150162
HEADERS := $(SUPPORT_OUTPUTDIR)/headers, \
151163
DISABLED_WARNINGS := $(DISABLED_WARNINGS_java) preview, \
@@ -163,6 +175,14 @@ ifneq ($(COMPILER), bootjdk)
163175

164176
TARGETS += $($(MODULE)-$(VALUECLASSES_STR))
165177

178+
# Restructure the class file hierarchy from <module>/<classpath>/... to <module>/META-INF/preview/<classpath>/...
179+
$(PREVIEW_OUTPUTDIR)/_copy_valueclasses.marker: $($(MODULE)-$(VALUECLASSES_STR))
180+
$(call MakeTargetDir)
181+
$(CP) -R $(VALUECLASS_OUTPUTDIR)/$(MODULE)/. $(@D)/
182+
$(TOUCH) $@
183+
184+
TARGETS += $(PREVIEW_OUTPUTDIR)/_copy_valueclasses.marker
185+
166186
$(eval $(call SetupCopyFiles, $(MODULE)-copy-valueclass-jar, \
167187
FILES := $(JDK_OUTPUTDIR)/lib/$(VALUECLASSES_STR)/$(MODULE)-$(VALUECLASSES_STR).jar, \
168188
DEST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/$(VALUECLASSES_STR), \

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@
3737
import java.nio.file.StandardOpenOption;
3838
import java.security.AccessController;
3939
import java.security.PrivilegedAction;
40+
import java.util.NoSuchElementException;
4041
import java.util.Objects;
42+
import java.util.function.Predicate;
4143
import java.util.stream.IntStream;
44+
import java.util.stream.Stream;
45+
4246
import jdk.internal.jimage.decompressor.Decompressor;
4347

4448
/**
@@ -326,6 +330,87 @@ public String[] getEntryNames() {
326330
.toArray(String[]::new);
327331
}
328332

333+
/**
334+
* Returns the "raw" API for accessing underlying jimage resource entries.
335+
*
336+
* <p>This is only meaningful for use by code dealing directly with jimage
337+
* files, and cannot be used to reliably lookup resources used at runtime.
338+
*
339+
* <p>This API remains valid until the image reader from which it was
340+
* obtained is closed.
341+
*/
342+
// Package visible for use by ImageReader.
343+
ResourceEntries getResourceEntries() {
344+
return new ResourceEntries() {
345+
@Override
346+
public Stream<String> entryNamesIn(String module) {
347+
if (module.isEmpty() || module.equals("modules") || module.equals("packages")) {
348+
throw new IllegalArgumentException("Invalid module name: " + module);
349+
}
350+
return IntStream.range(0, offsets.capacity())
351+
.map(offsets::get)
352+
.filter(offset -> offset != 0)
353+
// Reusing a location instance or getting the module
354+
// offset directly would save a lot of allocations here.
355+
.mapToObj(offset -> ImageLocation.readFrom(BasicImageReader.this, offset))
356+
// Reverse lookup of module offset would be faster here.
357+
.filter(loc -> module.equals(loc.getModule()))
358+
.map(ImageLocation::getFullName);
359+
}
360+
361+
private ImageLocation getResourceLocation(String name) {
362+
// Other types of invalid name just result in no entry being found.
363+
if (name.startsWith("/modules/") || name.startsWith("/packages/")) {
364+
throw new IllegalArgumentException("Invalid entry name: " + name);
365+
}
366+
ImageLocation location = BasicImageReader.this.findLocation(name);
367+
if (location == null) {
368+
throw new NoSuchElementException("No such resource entry: " + name);
369+
}
370+
return location;
371+
}
372+
373+
@Override
374+
public long sizeOf(String name) {
375+
return getResourceLocation(name).getUncompressedSize();
376+
}
377+
378+
@Override
379+
public InputStream open(String name) {
380+
return BasicImageReader.this.getResourceStream(getResourceLocation(name));
381+
}
382+
};
383+
}
384+
385+
/**
386+
* Returns a sorted array of all matching entry names in the jimage file.
387+
*
388+
* <p>Entry names are of one of the following forms:
389+
* <ul>
390+
* <li>{@code "/modules/<mod-name>/path/to/class-or-resource"}
391+
* <li>{@code "/<mod-name>/path/to/directory"}
392+
* <li>{@code "/packages/<package-name>"}
393+
* </ul>
394+
*
395+
* <p>Note that the module names {@code "modules"} or {@code "packages"} are
396+
* not representable in a jimage file, so can never exist.
397+
*
398+
* <p>The resulting array is sorted lexicographically, and the resulting
399+
* order need not match that of a breadth or depth first search.
400+
*
401+
* @param matcher a predicate for entry names to be returned.
402+
*/
403+
public String[] getEntryNames(Predicate<String> matcher) {
404+
int[] attributeOffsets = new int[offsets.capacity()];
405+
offsets.get(attributeOffsets);
406+
return IntStream.of(attributeOffsets)
407+
.filter(o -> o != 0)
408+
.mapToObj(o -> ImageLocation.readFrom(this, o).getFullName())
409+
.filter(matcher)
410+
.sorted()
411+
.toArray(String[]::new);
412+
}
413+
329414
ImageLocation getLocation(int offset) {
330415
return ImageLocation.readFrom(this, offset);
331416
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ public ByteBuffer getResourceBuffer(Node node) {
230230
return reader.getResourceBuffer(node.getLocation());
231231
}
232232

233+
/**
234+
* Returns the "raw" API for accessing underlying jimage resource entries.
235+
*
236+
* <p>This is only meaningful for use by code dealing directly with jimage
237+
* files, and cannot be used to reliably lookup resources used at runtime.
238+
*
239+
* <p>This API remains valid until the image reader from which it was
240+
* obtained is closed.
241+
*/
242+
public ResourceEntries getResourceEntries() {
243+
return reader.getResourceEntries();
244+
}
245+
233246
private static final class SharedImageReader extends BasicImageReader {
234247
// There are >30,000 nodes in a complete jimage tree, and even relatively
235248
// common tasks (e.g. starting up javac) load somewhere in the region of
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package jdk.internal.jimage;
2+
3+
import java.io.InputStream;
4+
import java.util.stream.Stream;
5+
6+
/**
7+
* Accesses the underlying resource entries in a jimage file.
8+
*
9+
* <p>This API is designed only for use by the jlink classes, which manipulate
10+
* jimage files directly. For inspection of runtime resources, it is vital that
11+
* {@code previewMode} is correctly observed, making this API unsuitable.
12+
*
13+
* <p>This API ignores the {@code previewMode} of the {@link ImageReader} from
14+
* which it is obtained, and returns an unmapped view of entries (e.g. allowing
15+
* for direct access of resources in the {@code META-INF/preview/...} namespace).
16+
*
17+
* <p>It disallows access to resource directories (i.e. {@code "/modules/..."}
18+
* or packages (i.e. {@code "/packages/..."}.
19+
*/
20+
public interface ResourceEntries {
21+
/**
22+
* Returns the full entry names for all resources in the given module, in
23+
* random order. Entry names will always be prefixed by the given module
24+
* name (e.g. "/<module-name/...").
25+
*/
26+
Stream<String> entryNamesIn(String module);
27+
28+
/**
29+
* Returns the (uncompressed) size of a resource given its full entry name.
30+
*
31+
* @throws java.util.NoSuchElementException if the resource does not exist.
32+
*/
33+
long sizeOf(String name);
34+
35+
/**
36+
* Returns an {@link InputStream} for a resource given its full entry name.
37+
*
38+
* @throws java.util.NoSuchElementException if the resource does not exist.
39+
*/
40+
InputStream open(String name);
41+
}

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package jdk.tools.jlink.internal;
2626

27+
import java.io.Closeable;
2728
import java.io.IOException;
2829
import java.io.InputStream;
2930
import java.nio.file.Path;
@@ -34,7 +35,7 @@
3435
* An Archive of all content, classes, resources, configuration files, and
3536
* other, for a module.
3637
*/
37-
public interface Archive {
38+
public interface Archive extends Closeable {
3839

3940
/**
4041
* Entry is contained in an Archive
@@ -59,11 +60,12 @@ public static enum EntryType {
5960
private final String path;
6061

6162
/**
62-
* Constructs an entry of the given archive
63-
* @param archive archive
64-
* @param path
65-
* @param name an entry name that does not contain the module name
66-
* @param type
63+
* Constructs an entry of the given archive.
64+
*
65+
* @param archive the archive in which this entry exists.
66+
* @param path the complete path of the entry, including the module.
67+
* @param name an entry name relative to its containing module.
68+
* @param type the entry type.
6769
*/
6870
public Entry(Archive archive, String path, String name, EntryType type) {
6971
this.archive = Objects.requireNonNull(archive);
@@ -72,10 +74,6 @@ public Entry(Archive archive, String path, String name, EntryType type) {
7274
this.type = Objects.requireNonNull(type);
7375
}
7476

75-
public final Archive archive() {
76-
return archive;
77-
}
78-
7977
public final EntryType type() {
8078
return type;
8179
}
@@ -87,6 +85,11 @@ public final String name() {
8785
return name;
8886
}
8987

88+
/**
89+
* Returns the path of this entry.
90+
*/
91+
public final String path() {return path;}
92+
9093
/**
9194
* Returns the name representing a ResourcePoolEntry in the form of:
9295
* /$MODULE/$ENTRY_NAME
@@ -134,5 +137,6 @@ public String toString() {
134137
/*
135138
* Close the archive
136139
*/
140+
@Override
137141
void close() throws IOException;
138142
}

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -571,62 +571,4 @@ private static ResourcePoolManager createPoolManager(ResourcePool resultResource
571571
resultResources.entries().forEach(resources::add);
572572
return resources;
573573
}
574-
575-
/**
576-
* Helper method that splits a Resource path onto 3 items: module, parent
577-
* and resource name.
578-
*
579-
* @param path
580-
* @return An array containing module, parent and name.
581-
*/
582-
public static String[] splitPath(String path) {
583-
Objects.requireNonNull(path);
584-
String noRoot = path.substring(1);
585-
int pkgStart = noRoot.indexOf("/");
586-
String module = noRoot.substring(0, pkgStart);
587-
List<String> result = new ArrayList<>();
588-
result.add(module);
589-
String pkg = noRoot.substring(pkgStart + 1);
590-
String resName;
591-
int pkgEnd = pkg.lastIndexOf("/");
592-
if (pkgEnd == -1) { // No package.
593-
resName = pkg;
594-
} else {
595-
resName = pkg.substring(pkgEnd + 1);
596-
}
597-
598-
pkg = toPackage(pkg, false);
599-
result.add(pkg);
600-
result.add(resName);
601-
602-
String[] array = new String[result.size()];
603-
return result.toArray(array);
604-
}
605-
606-
/**
607-
* Returns the path of the resource.
608-
*/
609-
public static String resourceName(String path) {
610-
Objects.requireNonNull(path);
611-
String s = path.substring(1);
612-
int index = s.indexOf("/");
613-
return s.substring(index + 1);
614-
}
615-
616-
public static String toPackage(String name) {
617-
return toPackage(name, false);
618-
}
619-
620-
private static String toPackage(String name, boolean log) {
621-
int index = name.lastIndexOf('/');
622-
if (index > 0) {
623-
return name.substring(0, index).replace('/', '.');
624-
} else {
625-
// ## unnamed package
626-
if (log) {
627-
System.err.format("Warning: %s in unnamed package%n", name);
628-
}
629-
return "";
630-
}
631-
}
632574
}

0 commit comments

Comments
 (0)