Skip to content

ADFA-6854: One packed JarListing per JAR for zipfs2 and javac - #2230

Draft
itsaky-adfa wants to merge 8 commits into
perf/ADFA-6854-javac-packagesfrom
perf/ADFA-6854-jar-listing
Draft

itsaky-adfa wants to merge 8 commits into
perf/ADFA-6854-javac-packagesfrom
perf/ADFA-6854-jar-listing

Conversation

@itsaky-adfa

@itsaky-adfa itsaky-adfa commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Draft, part 3 of 4 of the ADFA-6854 stack. Do not merge yet: see "Open items" in the top PR.

Stack (bottom to top):

  1. Kotlin library scopes check membership by root
  2. javac package map shared per JAR
  3. This PR: JarListing, one packed index per JAR for zipfs2 and javac
  4. Lazy Kotlin VFS over JarListing (needs a kt-android release)

What

  • JarListing (java-compiler, zipfs2.listing) is an immutable index of one JAR, built from one read of the central directory:

    • names packed into one byte array;
    • per-entry metadata in primitive arrays, with zip64 values in a small overflow table;
    • an open-addressing hash for lookups;
    • int[] parent, child and sibling links, with directories the JAR omits synthesized.

    It has no per-entry objects. Missing zip64 extras and any number of entry kinds behave as zipfs2 does today, so a JAR that opens today still opens.

  • JarListingCache.SHARED keys listings by path. Each get does one stat. When the size or mtime changes, it drops the listing and notifies listeners (zipfs2 here, the Kotlin VFS in PR 4) before building a new one. Listener failures are collected and rethrown after all listeners have run.

  • zipfs2 listing mode. CachedJarFileSystems opened through CachingJarFileSystemProvider keep no cen byte array and no IndexNode map. Lookups, directory iteration and entry reads go through the listing. Writable zip file systems are unchanged.

  • Replaced JARs. A JAR replaced in place is closed and reopened, and is never read with the old listing's offsets. R.jar was the only JAR invalidated before; now every JAR is.

  • javac package view. ListingPackageMap is a lazy view over the listing, so packageIndex() stores no per-package objects.

Measured

OnePlus Pad 2, cold open of CoGo at stage ffaa75be84, heap dump after open. The numbers cover the whole stack.

stage stack
zipfs2 index (IndexNode, names, cen) 36.7 MB 0.4 MB
JarListing, all 405 JARs - 13.3 MB

The budget was ~15 MB for all JARs. The javac structures (39.2 -> 26.6 MB) are covered in PR 2.

Tests

JarListingTest (21), JarListingCacheTest (11), CachedJarFileSystemListingTest and CachedJarFileSystemPackageIndexTest. They compare against ZipFile and JDK zipfs:

  • walks, bytes, attributes;
  • synthesized directories;
  • a stub prefix;
  • a JAR replaced in place;
  • concurrent first opens.

javac-services 42/42 and projects 52/52 pass.

Behaviour differences in listing mode, none used by any caller:

  • entry mtimes are DOS time only;
  • no zip extra/comment attributes;
  • directory order is unspecified;
  • the env map is ignored (javac's multi-release was never read by zipfs2).

@atlassian

atlassian Bot commented Nov 6, 2026

Copy link
Copy Markdown

To enable Code Reviewer, link your GitHub account to your Atlassian account.

This is a one-time task that takes less than a minute. Once your account is linked, resubmit the pull request to trigger a code review.

@itsaky-adfa
itsaky-adfa added this pull request to stack #2232 November 6, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant