Uh oh!
There was an error while loading. Please reload this page.
[TrimmableTypeMap] Reject open generic JNI construction - #11273
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the trimmable typemap generator to reject Java-side construction of open generic managed types (mirroring legacy typemap behavior) by emitting a generated UCO constructor callback that throws within the standard marshal-method wrapper, and re-enables previously-excluded Java.Interop runtime tests under the trimmable typemap.
Changes:
- Re-enabled trimmable typemap execution of the Java.Interop tests covering open-generic construction failures by removing them from the instrumentation exclusion list and deleting an obsolete TODO.
- Updated the typemap assembly emitter to generate a throwing
nctor_*_ucocallback for open-generic proxies using the existing Begin/EndMarshalMethod + try/catch/finally pattern. - Updated generator tests to assert the open-generic UCO constructor wrapper has exception regions and uses the marshal-method pattern.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs | Removes two Java.Interop tests from the trimmable typemap exclusion list so they run again. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs | Removes an outdated TODO tied to open-generic creation behavior. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs | Adjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs | Emits a throwing UCO constructor callback for open-generic proxies instead of a no-op body. |
Uh oh!
There was an error while loading. Please reload this page.
Open generic managed types cannot be constructed from Java because the runtime cannot infer their type arguments. Match the existing TypeManager activation guard in JNIEnv.StartCreateInstance(Type, ...) and re-enable the trimmable tests that cover both managed and Java activation paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match the legacy typemap behavior by rejecting open generic Java construction from the generated constructor activation callback instead of JNIEnv.StartCreateInstance(). This keeps JNIEnv allocation-only and makes Java-side construction fail when the constructor callback runs, just like TypeManager.n_Activate(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the open-generic UCO constructor test to assert the generated callback throws inside the marshal-method wrapper and calls OnUserUnhandledException. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assert the generated nctor_*_uco body constructs and throws NotSupportedException, rather than only checking assembly-level references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2f1b066 to
4b6aa5eCompareRemove the stale trimmable typemap exclusion for NewOpenGenericTypeThrows and drop the unrelated GetType exclusion added during rebase conflict resolution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the stale trimmable typemap exclusion for CannotCreateGenericHolderFromJava now that open generic Java construction is rejected correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
commented
May 5, 2026
/review |
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
✅ LGTM — solid change
The approach is well-designed: open generic UCO constructors now throw NotSupportedException inside the standard BeginMarshalMethod/try/catch/finally/EndMarshalMethod wrapper, so the exception is surfaced via OnUserUnhandledException instead of crossing the JNI boundary. This correctly mirrors the legacy typemap's behavior.
Highlights:
- Clean separation: the emitter lambda plugs neatly into
EmitUcoConstructorBodyWithMarshal - Thorough generator test — verifies exception regions, type refs, and IL token sequences for all key calls
- Re-enabling the two device tests with exclusion removal is a nice cleanup
CI:license/cla ✅ · dotnet-android ✅
Only two minor suggestions on the new test helper (formatting consistency and magic bytes → enum).
Generated by Android PR Reviewer for issue #11273 · ● 2.5M
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Replace magic bytes 0x28, 0x6F with (byte) ILOpCode.Call, (byte) ILOpCode.Callvirt for consistency with ILContainsNewobjToken - Add missing spaces before [ on array accesses in ILContainsOpcodeToken Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
…ttribute Resolve merge conflicts: - TypeMapAssemblyEmitter.cs: keep ExportMethodDispatchEmitter field + new array handling fields from main - FixtureTestBase.cs: take refactored ILContainsOpcodeToken helper from main - NUnitInstrumentation.cs: remove stale test exclusions fixed in main (#11238, #11273) Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Open generic managed types cannot be constructed from Java because Java construction cannot provide the missing type arguments.
The legacy typemap rejects this in
TypeManager.n_Activate()after Java calls the managed activation native method. This PR mirrors that behavior for the trimmable typemap by emitting a throwing generated constructor callback for open generic proxies, while keepingJNIEnv.StartCreateInstance(Type, ...)allocation-only.The generated open-generic constructor callback uses the same marshal-method wrapper as normal UCO constructors:
BeginMarshalMethod,try/catch/finally,JniRuntime.OnUserUnhandledException(ref envp, e), andEndMarshalMethod. The generator tests assert that the open-genericnctor_*_ucomethod has catch/finally regions and callsOnUserUnhandledException, so the managed exception is converted to a pending JNI exception instead of crossing the JNI boundary directly.Re-enables the trimmable tests for:
Java.InteropTests.JnienvTest.NewOpenGenericTypeThrowsJava.InteropTests.JniTypeManagerTests.CannotCreateGenericHolderFromJavaValidation:
dotnet test tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj -v minimalmake prepare CONFIGURATION=Release && make all CONFIGURATION=ReleaseMSBUILDDISABLENODEREUSE=1 ./dotnet-local.sh build -t:RunTestApp tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj -c Release -p:_AndroidTypeMapImplementation=trimmable -p:UseMonoRuntime=false -nr:falsePassed: 837, Failed: 0, Skipped: 50, Inconclusive: 0, Total: 887, Filtered: 887NewOpenGenericTypeThrowsran and passedCannotCreateGenericHolderFromJavaran and passedRelated issues