[TrimmableTypeMap] Reject open generic JNI construction#11273
[TrimmableTypeMap] Reject open generic JNI construction#11273simonrozsival wants to merge 7 commits intomainfrom
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. |
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
4b6aa5e
Compare
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>
|
/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
- 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>
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