[TrimmableTypeMap] Fix interface-peer proxy generation for NativeAOT#11769
[TrimmableTypeMap] Fix interface-peer proxy generation for NativeAOT#11769simonrozsival wants to merge 1 commit into
Conversation
552e290 to
d406bbc
Compare
|
Known limitation of this fix: interface peers now derive from the non-generic |
d406bbc to
3080560
Compare
…roxies
The generated proxy for an interface peer (e.g. a binding listener interface
like ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallback) derived from the
closed generic JavaPeerProxy<TInterface>. That base annotates its type parameter
with [DynamicallyAccessedMembers(PublicConstructors | NonPublicConstructors)] and
returns new JavaPeerContainerFactory<T>() from GetContainerFactory(). Closing the
generic over an interface -- which has no constructors -- makes ILC fail to load
the closed type ("Failed to load type JavaPeerProxy1<...INonMarshalingPreviewCallback>
from assembly Mono.Android"), which fails the whole NativeAOT build
(ManifestTest.RemovePermissionTest, which pulls in ZXing.Net.Mobile ->
ApxLabs.FastAndroidCamera).
Interface peers now derive from the non-generic JavaPeerProxy base (the same base
already used for open generic definitions), passing the interface as the TargetType
constructor argument so runtime TargetType identity is unchanged. Instances are
still created from the InvokerType in CreateInstance, so behaviour is preserved;
abstract classes keep the generic base since they have constructors.
Reproduced locally with ZXing.Net.Mobile (3.0.0-beta5): NativeAOT build failed with
the TypeLoadException before, builds successfully after. Basic Mono.Android listener
apps (IOnClickListener/IOnLongClickListener) and AndroidX.Fragment still build clean.
Fixes RemovePermissionTest.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
3080560 to
da1d643
Compare
|
Dropped the The remaining "will always throw" gap for binding/AndroidX interface listeners — the original motivation for the reverted direct-dispatch — is tracked in #11773 for a correct fix. |
Focused review subset of #11617
This is a small, focused PR carved out of #11617 (TrimmableTypeMap) to make review easier. It contains only the two interface-proxy fixes for the reflection-free NativeAOT typemap path. Its base branch is a snapshot of #11617 just before these two commits, so the diff shows only the interface-proxy changes (6 files).
#11617 remains the iteration branch; these ideas will land via small side PRs like this one.
What this fixes
Two distinct NativeAOT (ILC) failures caused by how generated proxies handle Java interface peers (e.g. binding listener interfaces from AndroidX / ZXing):
1. Interface-implementation methods use direct managed dispatch
Methods collected from an implemented Java interface (a listener
Implementor) forwarded through the interface'sprivate static n_*callback. That callback lives in the separately ILC-trimmed binding assembly and is unreferenced in the trimmable path, so ILC trims it and the generated proxy forwarder "will always throw."Fix: dispatch directly to the managed method (mirroring exactly what the static
n_*callback does —GetObject<TInterface>+callvirt), keeping the proxy self-contained.Reproduced with
Xamarin.AndroidX.Fragment(IOnBackStackChangedListeneret al.): 8+ "will always throw" ILC warnings → 0 after the fix. Fixes theMergeLibraryManifestNativeAOT test.2. Interface proxies derive from the non-generic
JavaPeerProxybaseGenerated interface proxies derived from
JavaPeerProxy<TInterface>, whose type parameter is annotated[DynamicallyAccessedMembers(PublicConstructors | NonPublicConstructors)]and which buildsnew JavaPeerContainerFactory<T>(). Closing that generic over a constructor-less interface makes ILC fail to load the closed type:which fails the entire NativeAOT build.
Fix: interface peers now derive from the non-generic
JavaPeerProxybase (the same base already used for open generic definitions), passing the interface as theTargetTypector argument so runtime identity is unchanged. Instances are still created from theInvokerType; abstract classes keep the generic base since they have constructors.Reproduced with
ZXing.Net.Mobile(3.0.0-beta5 → transitivelyApxLabs.FastAndroidCamera): NativeAOT build failed with theTypeLoadExceptionbefore, builds successfully after. Fixes theRemovePermissionTestNativeAOT test.Testing
Generate_InterfaceProxyType_UsesNonGenericJavaPeerProxyBaseand an interface-direct-dispatch assertion.IOnClickListener/IOnLongClickListener) andAndroidX.Fragmentstill build clean (no regression on the working path).