RFR: 8368467: [lworld] Add new flag generation for jimage to support preview mode

David Beaumont duke at openjdk.org
Tue Sep 23 20:36:55 UTC 2025


On Tue, 23 Sep 2025 19:25:22 GMT, David Beaumont <duke at openjdk.org> wrote:

> Adds support for writing preview related flags into jimage files.
> 
> Preview mode is complex. It's not nearly as simple as "does something in /modules/xxx/... have an entry in /modules/xxx/META-INF/preview/...".
> 
> Specific issues include:
> 
> Supporting preview-only resources without forcing a double lookup on everything.
> Changing the set of entries in /packages/xxx directories to account for preview only packages in some modules.
> Minimising the work done during image reader initialization to only need to process the small number of preview resources (rather than scanning the whole file to look for them).
> The new flags added by this code address these issues, but calculating them correctly with only minor adjustments to the existing code was not feasible, it just became a lot larger and very complex.
> 
> To address this, a new type (ModuleReference) is introduced to track and then merge information about packages seen in each module. This allows a much simpler inner loop for processing resource paths when building the node tree, combined with a subsequent merging stage to produce the final package information for each module.
> 
> Not that since ModuleReference is needed during jimage reading, that class is already present in the previous PR on which this is based, but it starts to be used to calculate the module flags in this PR.
> 
> This PR can also adds the ImageReader unit tests for preview mode, which rely on being able to generate jimage files with preview mode flags in.
> 
> Compare and review this against https://github.com/openjdk/valhalla/pull/1619.

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java line 290:

> 288:     }
> 289: 
> 290:     private static ResourcePool getResourcePool(

Pulled out so the variable holding it is effectively final and can be used in a lambda expression.

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java line 93:

> 91: 
> 92:         return new ImageLocationWriter(strings)
> 93:                 .addAttribute(ATTRIBUTE_MODULE, moduleName)

This got reformatted correctly to 8 indent because of the new entry.

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 151:

> 149:      * occur (e.g. {@code HAS_NORMAL_CONTENT + IS_PREVIEW_ONLY}).
> 150:      *
> 151:      * <p>Package node entries are sorted by name, with the exception that (if

This is out of date (along with the test). It's now sorted "preview first" and then "by name". The reason for the change is that I had made an incorrect assumption that I didn't need to process empty packages from preview resources, but I do (they still appear in /packages/xxx directories).

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 252:

> 250:             packageToModules.forEach((pkgName, modRefs) -> {
> 251:                 // Merge multiple refs for the same module.
> 252:                 List<ModuleReference> pkgModules = modRefs.stream()

This is where module references are merged so each package has the right set of flags according to all the resources visited in the module (empty, non-empty, preview, preview-only...). This replaces the use of the two maps (moduleToPackage and packageToModule) and a bunch of other logic.

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 298:

> 296:             ModuleReference emptyRef = ModuleReference.forEmptyPackage(modName, isPreviewPath);
> 297: 
> 298:             // Work down through empty packages to final resource.

This loop and the section after replaces the logic between L191 and L238 in the original code.

Instead of two maps (which would be 4 if we tried to add preview support that way) with near-duplicated logic, there's now just "walk down the path creating empty package nodes until the last segment is reached, then exit and create the resource node in a non-empty package".

The empty/non-empty/preview nature of these packages is all handled when the module references are merged later, but for now they are independent.

src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 431:

> 429:                 ByteBuffer byteBuffer = ByteBuffer.allocate(8 * refs.size());
> 430:                 byteBuffer.order(writer.getByteOrder());
> 431:                 ModuleReference.write(refs, byteBuffer.asIntBuffer(), writer::addString);

Call into the ModuleReference code added in the previous PR to write the package flags and offsets.

test/jdk/tools/jlink/whitebox/jdk.jlink/jdk/tools/jlink/internal/ImageResourcesTreeTest.java line 197:

> 195:     }
> 196: 
> 197:     @Test

This test needs updating. The order of the entries has changed. Sorry for not spotting sooner.

-------------

PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373352347
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373354187
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373387987
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373377751
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373371691
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373380118
PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2373357299


More information about the valhalla-dev mailing list