Skip to content

[TrimmableTypeMap] Implement pre-trimming build task #10789

@simonrozsival

Description

@simonrozsival

Part of #10788
Details outlined in #10757

Implementation Plan

Implement a build-time code generation step that runs before the trimmer and produces:

  1. Per-assembly typemap assemblies — one per input assembly containing Java peer types, plus a root `_Microsoft.Android.TypeMaps.dll` that ties them together via `TypeMapAssemblyTargetAttribute`
  2. JCW Java source files (`.java`) with `registerNatives` in `static {}` blocks

Uses System.Reflection.Metadata (SRM) for both reading and emitting — no Mono.Cecil.

Key design decisions

Decision Choice
Assembly reading/writing SRM only, no Cecil
Marshal method registration `RegisterNatives` (no LLVM IR)
Access to protected members `IgnoresAccessChecksTo`
Incremental builds Per-assembly typemap assemblies via `TypeMapAssemblyTargetAttribute`
TypeMap entries `TypeMapAttribute` 2-arg (unconditional) and 3-arg (trimmable)
Proxy pattern Self-application: `[Proxy] class Proxy : JavaPeerProxyAttribute`
JCW Java stubs `registerNatives` in `static {}`, actual JNI package names (no CRC hash)
Task assembly Separate `Microsoft.Android.Build.TypeMap` project (fast inner dev loop)

Architecture: Separate task assembly

New project `src/Microsoft.Android.Build.TypeMap/` (`netstandard2.0`) keeps the scanner, generators, and MSBuild task in a dedicated assembly separate from `Xamarin.Android.Build.Tasks`. This enables a fast inner dev loop (~5s build+test) without building the full solution.

Incremental builds: Per-assembly typemap generation

Mono.Android.dll  ──→  _Mono.Android.TypeMap.dll     (only rebuilt when Mono.Android changes)
AndroidX.Core.dll ──→  _AndroidX.Core.TypeMap.dll    (only rebuilt when NuGet updates)
MyApp.dll         ──→  _MyApp.TypeMap.dll             (rebuilt on every app code change)
                  ──→  _Microsoft.Android.TypeMaps.dll (root: TypeMapAssemblyTarget refs + aliases)

Typical incremental build cost: <0.5s (only re-scan the app assembly + regenerate root).

Testing strategy

  • Side-by-side legacy comparison: Run legacy `XAJavaTypeScanner` + `TypeMapCecilAdapter` (Cecil) and new `JavaPeerScanner` (SRM) on the same assemblies, compare results
  • Hand-crafted test assembly (~20 types) for TDD inner loop (<1s)
  • Real Mono.Android.dll (~8000 types) smoke test (~5s)
  • Integration tests in existing `Xamarin.Android.Build.Tests` project

PR strategy: 3 PRs with stacked branches

PR Sub-issue Content Branch
PR1 #10798 Scanner + data model + test project + scanner tests `trimmabletypemap-03-scanner`
PR2 #10799 IL generator + JCW generator + generator tests `trimmabletypemap-04-generators` (stacked)
PR3 #10800 MSBuild task + targets wiring + integration tests `trimmabletypemap-05-task-and-targets` (stacked)

Sub-issues

References

Sub-issues

Metadata

Metadata

Assignees

Labels

Area: CoreCLRIssues that only occur when using CoreCLR.Area: NativeAOTIssues that only occur when using NativeAOT.needs-triageIssues that need to be assigned.trimmable-type-map

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions