Skip to content

Migrate away from ILLink custom steps #10842

Open

Description

@sbomer

Background

dotnet/runtime#107211 proposes moving ILLink custom steps out of the trimmer process to enable ILLink to be published trimmed and AOT compiled, transition from Mono.Cecil to System.Reflection.Metadata, and reduce the ILLink API surface.

This issue tracks the work in dotnet/android to migrate all custom steps registered via _TrimmerCustomSteps.

Before MarkStep

During MarkStep

Remaining legacy LLVM IR type map steps

These steps remain registered via _TrimmerCustomSteps, but do not need to be migrated. They can be removed when the legacy LLVM IR type map is retired:

  • PreserveSubStepDispatcher / PreserveExportedTypes
  • MarkJavaObjects
  • PreserveJavaExceptions
  • PreserveApplications
  • PreserveRegistrations
  • PreserveJavaInterfaces

This step still needs to be supported with the trimmable type map:

After CleanStep

References

Activity

  1. added this to the .NET 11 milestone on Feb 19, 2026
  2. self-assigned this
    on Feb 19, 2026
  3. added
    Area: TrimmingIssues with ILLink or NativeAOT related to trimming.
    and removed
    needs-triageIssues that need to be assigned.
    on Feb 23, 2026
  4. simonrozsival commented on Sep 2, 2026

    @simonrozsival
    Member

    Resource-designer follow-up:

    • The resource designer assembly is generated from the AAPT2 symbol pass before CoreCompile and trimming.
    • Application scalar IDs in ResourceConstant are literal const int fields. We verified that Roslyn inlines referenced-assembly constants into consumer IL (const int -> ldc.i4; const long -> ldc.i8).
    • Shared designer properties remain ordinary calls. NativeAOT may optimize those getters, while CoreCLR can retain/ship the designer assembly; no late constant-propagation rewrite is required for correctness.
    • Mutable legacy resource fields remain ldsfld, and int[] styleables cannot be constants. Those are compatibility cases for the existing pre-trim task until they can be replaced by runtime/JNI initialization; they are not a reason to build another late assembly-rewriting step.

    Therefore we should not pursue the approach from the already-closed #11996 or migrate that constant propagation into another external MSBuild assembly-rewriter. The custom-step migration tracked here is complete: #11059/#11084 moved the legacy designer handling out of ILLink, every checklist item is done, and the remaining LLVM-IR-only steps are documented as retirement-only.

  5. simonrozsival commented on Sep 3, 2026

    @simonrozsival
    Member

    Follow-up: “no custom ILLink steps” and “no managed-assembly rewriting” are separate milestones.

    The trimmed trimmable-typemap path is already free of our post-compile assembly rewriters: it skips _RunAfterILLinkAdditionalSteps, does not run PreTrimmingFixLegacyDesigner, uses generated typemap/proxy assemblies instead of RewriteMarshalMethods, and its _RemoveRegisterAttribute override only stages/copies assemblies. The remaining mark-time handlers are LLVM-IR-only and can disappear with that implementation.

    The remaining rewrite exposure is untrimmed builds, where _LinkAssembliesNoShrink still runs for every typemap and may apply three compatibility fixes:

    • FixLegacyResourceDesignerStep: supports pre-designer-assembly libraries with mutable resource fields. Modern scalar IDs are compile-time constants and need no rewrite; styleable arrays remain non-constant. Trimmed trimmable builds already omit this compatibility (see the NativeAOT skip in SkiaSharpCanvasBasedAppRuns). If compatibility is required without rewriting, the practical replacement is generated app source that assigns legacy fields from the shared designer properties/arrays, reusing the existing ResourceDesignerImportGenerator model. A JNI lookup by itself does not repair existing ldsfld consumers unless it also writes those legacy managed fields.
    • FixAbstractMethodsStep: binary compatibility for binding assemblies whose Java interfaces gained abstract methods. This is unrelated to typemap lookup and has no generated-proxy equivalent; see Consider binding historical new abstract methods as virtual #9557. Removing it means explicitly dropping that ecosystem compatibility (and also avoids failures such as Can't build for release due to modreq from in #12656).
    • AddKeepAlivesStep: compatibility only for old Xamarin.Android-produced binding assemblies; .NET for Android assemblies already contain the calls. Removing it means dropping that legacy guarantee or finding a runtime-level replacement.

    Other writers are legacy/optional optimizations: StripEmbeddedLibrariesStep (package size), RemoveResourceDesignerStep/AndroidLinkResources (experimental size/startup optimization), RemoveRegisterAttribute (metadata size), and RewriteMarshalMethods (replaced by generated trimmable proxy/UCO assemblies). None blocks making the trimmable typemap the default.

    So the default switch does not require migrating more steps. A stronger “never rewrite referenced assemblies” goal needs a separate LinkAssembliesNoShrink retirement decision: copy-only staging on the trimmable path plus an explicit support policy for the three old-binary compatibility cases above.

  6. sbomer commented on Sep 3, 2026

    @sbomer
    MemberAuthor

    Could we open a new issue to track the goal of not having any custom IL rewriting logic? The intention of this one was to track removal of custom steps specifically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Area: TrimmingIssues with ILLink or NativeAOT related to trimming.

Type

No type

Projects

  • Status
    No status

Relationships

None yet

Development

No branches or pull requests

Issue actions