Skip to content

[TrimmableTypeMap] Reject open generic JNI construction#11273

Open
simonrozsival wants to merge 7 commits intomainfrom
trimmable-open-generic-activation
Open

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival wants to merge 7 commits intomainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented May 3, 2026

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 keeping JNIEnv.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), and EndMarshalMethod. The generator tests assert that the open-generic nctor_*_uco method has catch/finally regions and calls OnUserUnhandledException, 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.NewOpenGenericTypeThrows
  • Java.InteropTests.JniTypeManagerTests.CannotCreateGenericHolderFromJava

Validation:

  • dotnet test tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj -v minimal
  • make prepare CONFIGURATION=Release && make all CONFIGURATION=Release
  • MSBUILDDISABLENODEREUSE=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:false
    • device NUnit log: Passed: 837, Failed: 0, Skipped: 50, Inconclusive: 0, Total: 887, Filtered: 887
    • confirmed NewOpenGenericTypeThrows ran and passed
    • confirmed CannotCreateGenericHolderFromJava ran and passed

Related issues

@simonrozsival simonrozsival changed the title Reject open generic JNI construction [TrimmableTypeMap] Reject open generic JNI construction May 3, 2026
@simonrozsival simonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map labels May 3, 2026
@simonrozsival simonrozsival marked this pull request as ready for review May 3, 2026 20:59
Copilot AI review requested due to automatic review settings May 3, 2026 20:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_*_uco callback 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.

@simonrozsival simonrozsival added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label May 4, 2026
simonrozsival and others added 4 commits May 4, 2026 20:31
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>
@simonrozsival simonrozsival force-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5e Compare May 4, 2026 18:31
@simonrozsival simonrozsival removed the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label May 4, 2026
simonrozsival and others added 2 commits May 4, 2026 23:09
Remove 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>
@simonrozsival simonrozsival added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label May 5, 2026
@simonrozsival simonrozsival enabled auto-merge (squash) May 5, 2026 10:48
@jonathanpeppers
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

Android PR Reviewer completed successfully!

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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

Comment thread tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/FixtureTestBase.cs Outdated
Comment thread tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/FixtureTestBase.cs Outdated
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot `copilot-cli` or other AIs were used to author this ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). trimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants