On Mon, 27 Oct 2025 12:55:36 GMT, David Beaumont <[email protected]> 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. > > David Beaumont has updated the pull request with a new target base due to a > merge or a rebase. The pull request now contains one commit: > > Rollup after resync of dependent PR. > > * Fixing up after dependent PR changes > * feedback and remove unused code > * new tests for ImageLocation > * Restoring lost changes and updating some comments. > * add system property guard to preview mode > * Remove TODOs now jimage version is bumped > * jimage writer changes to support preview mode. src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 206: > 204: } catch (InvalidTreeException err) { > 205: // It has been observed some badly created jar file > to contain > 206: // invalid directory entry marked as not directory > (see 8131762). I'm not 100% sure of the value of retaining stderr logging like this, especially if the code continues after ignoring the input, but it's the same behaviour as before, so I'm leaving it as-is. src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 261: > 259: // Intermediate packages are marked "empty" (no resources). > This might > 260: // later be merged with a non-empty reference for the same > package. > 261: ModuleReference emptyRef = > ModuleReference.forEmptyPackageIn(modName, isPreviewPath); This convinces me that `forEmptyPackageIn` is a better name than `forEmptyPackage`, since the passing of the module name as the first parameter no longer raises eyebrows. src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 276: > 274: ModuleReference resourceRef = > ModuleReference.forPackageIn(modName, isPreviewPath); > 275: packageToModules.computeIfAbsent(fullPkgName, p -> new > HashSet<>()).add(resourceRef); > 276: // Init adds new node to parent (don't add resources to > directAccess). I'd be happy to rename the `directAccess` field. It's really a holder for directories. The fact it's "direct access" is rather a statement of its form (obvious since it's a map really) and not its function. Thoughts? src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 295: > 293: } > 294: > 295: // Helper to iterate package names up to, and including, the > complete name. If this comment isn't clear enough I can elaborate. Basically lets you iterate indices in "foo.bar.baz" as `3, 7, 11, -1` (including an index at the end of the string before it returns `-1`). This is just here to make the for-loop cleaner where the real business logic is. src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 311: > 309: } > 310: > 311: private String removeRadical(Node node) { I don't think this method obviously earns its keep, so would be happy to inline it, perhaps with a string constant. But also happy to leave it. src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java line 416: > 414: // A resource location, remove "/modules" > 415: String s = tree.toResourceName(current); > 416: current.setLocation(outLocations.get(s)); Calling this via the method adds a check that nothing is being overwritten. test/jdk/jdk/internal/jimage/ImageLocationTest.java line 89: > 87: } > 88: > 89: @Test The `getPackageFlags` tests check that module references get merged correctly to create the parent directory flags we expect. While adding individual resources you build up a *list* of references in each package, one for each resource (directly or indirectly) in that package. This is a key reason for how the new code can simplify things around the outer "add each resource in turn" loop, by just collecting the references and merging them later to get the right result. test/jdk/jdk/internal/jimage/ImageLocationTest.java line 119: > 117: ModuleReference.forEmptyPackage("modbaz", true)); > 118: int previewOnlyFlags = ImageLocation.getPackageFlags(refs); > 119: // Note the asymmetry between this and the getFlags() case. > Unlike This is a flag combination you can't see for locations in `/modules`, because "has-preview-version" there means "is-not-a-preview-resource" and thus cannot imply "preview only". But there is no concept of "is-a-preview-resource" for things in the `/packages` space. However, the code using the flags doesn't really care about what combinations exist since the flags are designed to be used independently of each other, each answering a specific question at a certain place in the processing code. * `hasPreviewVersion` means: * Put this entry first so we can skip 99% of packages with no preview content during pre-processing. * `isPreviewOnly` means: * Don't add this to the `/packages` directory when *not* in preview mode. * Put the node for this location in the preview-only map to be added separately during directory completion (in preview mode). test/jdk/jdk/internal/jimage/ImageReaderTest.java line 251: > 249: > 250: // Preview version of classes either overwrite existing > entries or are added to directories. > 251: assertEquals("Preview: com.foo.HasPreviewVersion", > loader.loadAndGetToString("modfoo", "com.foo.HasPreviewVersion")); This "load the class, run its `toString()` method and test the result" could be encapsulated a bit more if you think it would make the intent of the test clearer. E.g.: assertClassToString("modfoo", "com.foo.HasPreviewVersion", "Preview: com.foo.HasPreviewVersion", loader); Or even: loader.assertNormalVersion("modfoo", "com.foo.NormalFoo"); loader.assertPreviewVersion("modfoo", "com.foo.HasPreviewVersion"); Thoughts? test/micro/org/openjdk/bench/jdk/internal/jrtfs/ImageReaderBenchmark.java line 318: > 316: } > 317: > 318: /// Note: This list is inherently a little fragile and may end up > being more Sorry about this enormous non-diff. It's because of moving the static init into a holder class because we now want "module" + "path" as two separate things, pre-calculated, for benchmarking the new APIs. ------------- PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465642516 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465648972 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465656652 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465667236 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465672206 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465677574 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465700949 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465738045 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465769498 PR Review Comment: https://git.openjdk.org/valhalla/pull/1621#discussion_r2465776447
