Skip to content

ADFA-6854: Share one javac package map per JAR across file managers - #2229

Draft
itsaky-adfa wants to merge 4 commits into
perf/ADFA-6854-library-scopefrom
perf/ADFA-6854-javac-packages
Draft

itsaky-adfa wants to merge 4 commits into
perf/ADFA-6854-library-scopefrom
perf/ADFA-6854-javac-packages

Conversation

@itsaky-adfa

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

Copy link
Copy Markdown
Contributor

Draft, part 2 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. This PR: javac package map shared per JAR
  3. JarListing: one packed index per JAR for zipfs2 and javac
  4. Lazy Kotlin VFS over JarListing (needs a kt-android release)

What

  • CachedJarFileSystem.packageIndex() builds a JAR's RelativeDirectory -> Path package map once. The map is read-only and safe for concurrent first access.
  • JarPackageProviderImpl.getPackages returns that map, so every javac ArchiveContainer shares it instead of walking the archive itself (JavacFileManager.java:629-654).
  • SourceFileManager now registers JarPackageProvider in the context of its delegate file manager. Without it, javac falls back to an empty map and a full walk per container (JavacFileManager.java:183-186). This was why the Java LSP's file managers did not get the shared map in the first on-device run.
  • JarFsClasspathReader (boot classpath) no longer builds the map as a side effect of its walk. It reads the shared index and lists each package directory once.

Why

The ticket measured 37.1 MB of per-file-manager package maps, because CachedJarFileSystem.packages was filled only for boot JARs. Every file manager walked every JAR and kept its own map.

Measured

OnePlus Pad 2, cold open of CoGo at stage ffaa75be84, heap dump after open, javac structures reachable from JavacFileManager:

stage stack before the SourceFileManager fix (a71e6da99c) stack (3254dcc1db)
javac package structures 39.2 MB, 804,305 objects 39.2 MB, 804,305 objects 26.6 MB, 463,805 objects

With PR 3 the shared map is a lazy view over the JAR's listing, so the shared part adds no per-package objects.

The remaining 26.6 MB is not the package map. It is javac's own per-manager index, pathsAndContainersByLocationAndRelativeDirectory, which every one of the 98 SourceFileManagers in the dump builds for itself (the ticket counted 91 managers). Reducing it needs either a change to that index inside javac or fewer file managers. It is tracked as an open item in the top PR.

Tests

  • CachedJarFileSystemPackageIndexTest: equality with javac's own walk, one instance across callers, 16 concurrent first callers, non-identifier directories skipped.
  • SourceFileManagerSharedPackagesTest: the archive containers of two separate file managers share the JAR's package map, and classes are still listed through it.
  • JarFsClasspathReaderListClassesTest: same classes listed as before.
  • javac-services and projects suites pass.
  • :lsp:java:testV7DebugUnitTest: JavaCompilerProviderTest > test module specific compilers fails, and the task hits Gradle's 10-minute timeout. Both also happen on stage without this stack.

@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