[TrimmableTypeMap] Re-enable JavaCast / JavaAs tests under trimmable typemap#11225
Draft
simonrozsival wants to merge 7 commits intomainfrom
Draft
[TrimmableTypeMap] Re-enable JavaCast / JavaAs tests under trimmable typemap#11225simonrozsival wants to merge 7 commits intomainfrom
simonrozsival wants to merge 7 commits intomainfrom
Conversation
Base automatically changed from
dev/simonrozsival/trimmable-test-plumbing
to
main
April 27, 2026 21:15
An error occurred while trying to automatically change base from
dev/simonrozsival/trimmable-test-plumbing
to
main
April 27, 2026 21:15
ced5233 to
f69f27b
Compare
…te closed generics Improve JavaCast/JavaAs behavior under the trimmable typemap: 1. Bad-cast disambiguation: When proxy lookup fails, distinguish between incompatible Java types (return null → InvalidCastException in JavaCast) and missing typemap entries (NotSupportedException). Previously all failures threw NotSupportedException. 2. Closed-generic activation: Add Object.ActivatePeer() which uses GetUninitializedObject + UnsafeAccessor to call the Java.Lang.Object activation ctor on closed generic types (e.g. JavaList<int>). Open-generic proxies can't newobj closed instantiations in IL, so CreatePeer falls back to this path when the proxy's TargetType is an open generic definition. 3. Type resolution: Add ResolvePeerType to map universal interfaces (IJavaPeerable, object, Exception) to concrete peer types before proxy lookup, mirroring the legacy GetPeerType behavior. 4. TargetTypeMatches: Restructure to check open-generic proxy match first (closed instantiation of the definition), avoiding incorrect IsAssignableFrom matches on unrelated open generics. 5. FindClass safety: Catch ClassNotFoundException in TryGetProxyFromTargetType for types whose Java peer class is not in the APK. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Interface peers have no constructors of their own, so the activation ctor resolution returns null. Add TryResolveActivationCtorOnInvoker to resolve the ctor from the invoker type, so the generator can pick the correct ctor signature (XamarinAndroid vs JavaInterop style). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The GetThis.java class in the Java.Interop submodule uses ManagedPeer.registerNativeMembers which the trimmable typemap path rejects. Add a parallel Android-trimmable variant that uses mono.android.Runtime.register instead, conditionally swapped in via Java.Interop-Tests.targets when _AndroidTypeMapImplementation is 'trimmable'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-enable 5 tests that now pass: - JavaCast_BadInterfaceCast - JavaCast_BaseToGenericWrapper (closed-generic via ActivatePeer) - JavaCast_CheckForManagedSubclasses - JavaCast_InvalidTypeCastThrows - DisposeAccessesThis (via trimmable GetThis.java) Update exclusion comments with accurate root-cause descriptions for the remaining excluded tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
885680d to
01577a3
Compare
Match legacy behavior: Type.GetConstructor() doesn't find inherited constructors in .NET. When the activation ctor is on a base type (IsOnLeafType=false) and there's no invoker type, emit NoActivation (return null) instead of synthesizing via the inherited ctor. This fixes JavaAs_Exceptions which expects NotSupportedException when the target type has no own activation ctor. Re-enables JavaAs_Exceptions test (6 total tests re-enabled in PR). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ResolvePeerType now handles null input directly - Remove redundant `?? targetType` fallback (resolvedTargetType is null iff targetType is null after ResolvePeerType handles null) - Rename `idx` → `assembly` in TryResolveActivationCtorOnInvoker and document assemblyCache size (10–30 entries, O(1) dict probe) - Add remarks to ActivatePeer documenting why calling Java.Lang.Object::.ctor directly is safe for closed generics Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
18db335 to
bb1bfc9
Compare
- Catch JniException specifically instead of bare catch in TryGetProxyFromTargetType FindClass fallback - Document why UnsafeAccessorKind.Method (not Constructor) is used for InvokeActivationCtor — calls ctor on existing object - Add comment noting TestJarEntry conditional swap requires clean rebuild when switching _AndroidTypeMapImplementation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bb1bfc9 to
4a2262f
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
Fix
JavaCast/JavaAsbehavior under the trimmable typemap and re-enable 5 device tests that were previously excluded.Cast error disambiguation
When a trimmable typemap proxy lookup fails,
CreatePeernow distinguishes between:null(JavaCast wraps toInvalidCastException, JavaAs returnsnull)ArgumentExceptionNotSupportedExceptionPreviously all failures threw
NotSupportedException, which brokeJavaCast/JavaAscontracts.Also adds
ResolvePeerTypeto map universal interfaces (IJavaPeerable,object,Exception) to concrete peer types before proxy lookup, and wrapsFindClassintry/catchso missing Java classes surface asArgumentExceptionrather than leakingClassNotFoundException.Closed-generic peer activation
Open-generic proxies (e.g.
JavaList<>) cannotnewobjclosed instantiations (e.g.JavaList<int>) in generated IL. AddsObject.ActivatePeer()which usesRuntimeHelpers.GetUninitializedObjectto allocate the closed type, then calls theJava.Lang.Object(IntPtr, JniHandleOwnership)activation ctor via[UnsafeAccessor]. No reflection, fully AOT/trim-safe.TargetTypeMatchesis restructured so open-generic proxies match only closed instantiations of their definition — preventing incorrect matches likeJavaArray<>matching anyJavaObject-targeted cast.Interface invoker activation ctor
Interface peers have no constructors.
TryResolveActivationCtorOnInvokerresolves the activation ctor from the invoker type so the generator picks the correct ctor signature (XA-style vs JI-style).Trimmable GetThis.java
The
net.dot.jni.test.GetThisJava class (in the Java.Interop submodule) registers native methods viaManagedPeer.registerNativeMemberswhich the trimmable path rejects. Adds an Android-trimmable variant that omits the desktop static block.Java.Interop-Tests.targetsswaps variants based on_AndroidTypeMapImplementation.Test exclusion updates
Re-enabled (5 tests):
JavaCast_BadInterfaceCastJavaCast_BaseToGenericWrapper(closed-generic activation)JavaCast_CheckForManagedSubclassesJavaCast_InvalidTypeCastThrowsDisposeAccessesThis(trimmable GetThis.java)Updated remaining exclusion comments with accurate root-cause descriptions. The
JavaProxyObject/JavaProxyThrowableexclusions are tracked at #11170.Test results
Trimmable + CoreCLR lane: 917 total, 0 errors, 3 failures (pre-existing
TryGetJniNameForManagedType_*, out of scope).