Import: share a referenced project's CCU instead of pickling it - #20416
Open
auduchinok wants to merge 2 commits into
Open
Import: share a referenced project's CCU instead of pickling it#20416auduchinok wants to merge 2 commits into
auduchinok wants to merge 2 commits into
Conversation
Contributor
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
A project reference pickles its signature once and every consumer unpickles its own copy: five projects referencing one hub hold five copies of its signature TAST. The pickled tree is already in the shape consumers need, so offer it directly through IImportedProjectCcu, and pickle only when something asks. Four things make it usable: - Remapped against a ccu made for this view, not the project's live one, which a consumer would else hold whole. - PruneExportedSignatureInPlace brings it to the shape unpickling produces: no value definitions, no display-only data, no compiled-representation cache. - Every non-local reference is re-pointed at the reading project's ccu of the same name, as unpickling does; a name the reader lacks keeps ours. So a consumer on another framework takes it too. - What each name bound to is recorded, and a second consumer takes that copy only where it resolves all of them alike. Binding runs once the batch is registered and before anything relinks: an assembly unpickled beside it resolves the names it mentions against what is registered, and a delayed CCU is an error there. Depends on sharing imported assemblies (dotnet#20296). Also fixes a check-then-act race in BackgroundCompiler: builders were cached without a second look under the gate, so callers arriving together each built the project. Retained memory, under editor options. Diagnostics identical with the change off and on: Fantomas 8 proj 350.2 -> 275.7 MB -74.5 (-21.3%) ReSharper.FSharp 10 proj 384.9 -> 304.6 MB -80.3 (-20.9%) FsToolkit 8 proj 87.7 -> 70.1 MB -17.6 (-20.1%) Oxpecker 16 proj 131.7 -> 114.2 MB -17.5 (-13.3%) Prime 5 proj 112.2 -> 97.9 MB -14.3 (-12.7%) IcedTasks 7 proj 97.0 -> 92.4 MB -4.6 (-4.7%) FCS solution 14 proj 820.8 -> 818.7 MB -2.1 (-0.2%) consoleapp 1 proj 29.4 -> 29.4 MB 0.0 The FCS solution gains least: nearly every edge in it crosses framework import layers, so each consumer rebuilds a copy of its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
auduchinok
force-pushed
the
il-projectReferenceHandover
branch
from
September 2, 2026 14:31
befdc7b to
d62a9b1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A project reference pickles its signature once and every consumer unpickles its own copy: five projects
referencing one hub hold five copies of its signature TAST. The pickled tree is already in the shape
consumers need, so offer it directly through
IImportedProjectCcu, and pickle only when something asks.Depends on the shared imported assemblies change (#20296), whose keys let a consumer establish it will hold
the same ccus.
Four things make it usable:
whole.
PruneExportedSignatureInPlacebrings it to the shape unpickling produces: no value definitions, nodisplay-only data, no compiled-representation cache. Rescoping happens in the same traversal that builds
the tree -
ILScopeRef.Localis whatinternalis rooted at, so a consumer would otherwise read thereference's internals as its own.
u_ccurefdoesfor a consumer reading the bytes; a name the reader lacks keeps ours. This is what lets a consumer on
another framework take the contents.
them alike. Consumers that disagree get a copy each, capped at eight.
Binding runs once the batch is registered and before anything relinks: an assembly unpickled beside it
resolves the names it mentions against what is registered, and a delayed CCU is an error there rather than
a wait.
The numbers are smaller due to other FSharpChecker creation flags.
consoleapp has no project references. Not all of this is the handover: switching the handover alone off and
on inside one build moves the compiler's own solution by 2 MB rather than 61, the rest coming from dropping
the language version out of the import reuse key, which lets projects that differ only in it share one
imported graph.
Also fixes a check-then-act race in
BackgroundCompilerthat predates this: builders were cached without asecond look under the gate, so callers arriving together each built the project, and a project built twice
is two of everything it imports. Nothing here survives that.