[TrimmableTypeMap] Implement alias support in codegen and runtime#11122
Open
simonrozsival wants to merge 8 commits intomainfrom
Open
[TrimmableTypeMap] Implement alias support in codegen and runtime#11122simonrozsival wants to merge 8 commits intomainfrom
simonrozsival wants to merge 8 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Implements end-to-end alias support for the Trimmable TypeMap pipeline (codegen + runtime), enabling multiple managed types to share a single JNI name via an alias-holder indirection and indexed alias keys.
Changes:
- Add
IJavaPeerAliasesand generate alias-holder proxy types + indexed TypeMap entries +TypeMapAssociationrecords for alias groups. - Update runtime lookup/activation paths (
TrimmableTypeMap*) to expand alias holders into their concrete alias entries. - Add/expand unit tests and fixture types covering 2-way/3-way aliases and emission round-trips.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestTypes.cs | Adds fixture types that intentionally share a JNI name to form a 3-way alias group. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapModelBuilderTests.cs | Updates/extends model-builder tests for indexed alias entries, alias holders, and associations. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs | Adds a round-trip emission test asserting alias-related typemap artifacts are present in emitted metadata. |
| src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMapTypeManager.cs | Switches to enumerating all types for a JNI name (to support alias expansion). |
| src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs | Adds alias-aware type enumeration and alias resolution for proxy lookup and activation. |
| src/Mono.Android/Java.Interop/JavaPeerProxy.cs | Introduces IJavaPeerAliases used by generated alias-holder proxy types. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs | Emits alias-holder types and self-applies proxy/holder attributes for AOT-safe GetCustomAttribute instantiation. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ModelBuilder.cs | Generates alias holders, base-entry indirection, indexed alias keys, and associations for duplicate JNI-name groups. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/Model/TypeMapAssemblyData.cs | Extends the model to carry alias-holder emission data. |
9e8ae03 to
64d3228
Compare
…1103) Add alias holder approach for typemap aliases: when multiple .NET types map to the same JNI name, generate an alias holder class extending JavaPeerProxy + IJavaPeerAliases with explicit alias key list. Build-time: - IJavaPeerAliases interface with string[] Aliases property - AliasHolderData in the codegen model - ModelBuilder generates alias holder, [0]-based indexed entries, TypeMapAssociation links to holder - Emitter emits alias holder class with TargetType/CreateInstance throwing NotSupportedException, Aliases property returning key array - Self-application (AddCustomAttribute) for proxy and alias holder types Runtime: - GetProxyForManagedType: if (proxy is IJavaPeerAliases) -> iterate exact keys from Aliases property (zero cost for non-alias types) - GetAllTypesForJniName: detect alias holder, enumerate listed keys - ActivateInstance: same alias holder detection Tests: - 3 alias fixture types (3-way alias group) - Model builder tests for alias holders, 3-way aliases, mixed activation - Fixture scanner and integration tests Fixes: #11103 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rarchy walking - Rename ResolveAlias -> GetProxyFromAliases, use IsAssignableFrom - GetProxyForJavaType: return sentinel for alias holders (not real proxies) - TryGetProxyFromHierarchy: resolve alias groups when targetType is available - Add GetAliasesForJniName helper - Fix NotSupportedException IL: push string arg before newobj Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Don't extend JavaPeerProxy for alias holders — this keeps the fast path (GetCustomAttribute<JavaPeerProxy>()) clean with zero alias checks. - Replace IJavaPeerAliases interface with JavaPeerAliasesAttribute - Alias holder is now a plain class (extends Object, not JavaPeerProxy) - [JavaPeerAliases] attribute encodes alias keys in the metadata blob - No ctor/CreateInstance/TargetType methods on alias holder (not needed) - Runtime: only checks JavaPeerAliasesAttribute when JavaPeerProxy is null Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace TryGetTargetType(string, out Type?) with TryGetTargetTypes(string, out Type[]?) — returns all surviving target types for alias groups, false when no mapping or all trimmed - GetProxyFromAliases: exact type equality (==) not IsAssignableFrom - TryGetProxyFromHierarchy: resolve aliases even without targetType (returns first surviving proxy) - TypeManager: single TryGetTargetTypes call, no alias awareness - Remove dead methods: GetTargetTypesForAliasedJniName, GetAliasedTargetTypes - Add GetFirstProxyFromAliases for targetType-less resolution - 3 new integration tests: - alias holder extends Object not JavaPeerProxy - JavaPeerAliasesAttribute deserializes to correct keys - proxy types have self-applied attribute (MethodDef ctor) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A single-proxy-per-JNI-name cache violates the principle that one JNI name can map to multiple types. Replace with GetProxyForJniClass(string, Type?) which handles both direct entries and alias groups in a single call, with no per-JNI-name caching. - Remove _peerProxyCache (cached single proxy per JNI name) - Remove GetProxyForJavaType (returned single proxy) - Remove GetAliasesForJniName (no longer needed as separate method) - Add GetProxyForJniClass(className, targetType) that resolves direct proxies or alias groups based on targetType - Simplify TryGetProxyFromHierarchy to single GetProxyForJniClass call Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use GetProxiesForJniName to resolve all proxies (including aliases) and register natives for each ACW proxy. Previously, alias holders returned null from GetCustomAttribute<JavaPeerProxy>() and native registration was silently skipped for aliased types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Commit 64d3228 accidentally bumped external/Java.Interop and external/xamarin-android-tools submodule pointers. The newer xamarin-android-tools commit removed the 'log' parameter from Files.ExtractAll, causing CI build failures: ResolveLibraryProjectImports.cs(300,13): error CS1739: The best overload for 'ExtractAll' does not have a parameter named 'log' Reset both submodules back to origin/main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
348a100 to
2b159e5
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.
Summary
Implements trimmable typemap alias support end-to-end, covering both generated metadata/code and runtime lookup/activation.
Fixes #11103
Part of #10788
Changes
New:
IJavaPeerAliasesinterface (JavaPeerProxy.cs)string[] Aliases { get; }— lists the exact TypeMap keys for an alias groupBuild-time (ModelBuilder + Emitter)
For alias groups (≥2 .NET types sharing a JNI name, e.g.,
JavaCollection/JavaCollection<T>):JavaPeerProxy+IJavaPeerAliases[0]-based indexed entry:"jni/Name[0]","jni/Name[1]", ...TypeMapAssociationlinks each type to the alias holder (keeps holder alive when any alias survives trimming)TargetType/CreateInstancethrowNotSupportedException(alias holder is never used for peer creation)AddCustomAttributeontypeDefHandle) for all proxy types — required forGetCustomAttribute<JavaPeerProxy>()to work at runtimeRuntime (
TrimmableTypeMap.cs)GetProxyForManagedType():if (proxy is IJavaPeerAliases aliases)→ iterate exact keys fromAliasespropertyGetAllTypesForJniName(): detect alias holder, enumerate listed keysActivateInstance(): same alias holder detectionischeck that's false, no dictionary probingGenerated output for an alias group
Tests
331 passing (+9 new):
JavaCollection/JavaCollection<T>pattern)IJavaPeerAliasesin emitted PE