[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[TrimmableTypeMap] Reject open generic JNI construction - #11273

Merged
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation
May 6, 2026
Merged

[TrimmableTypeMap] Reject open generic JNI construction#11273
simonrozsival merged 7 commits into
mainfrom
trimmable-open-generic-activation

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented May 3, 2026

Copy link
Copy Markdown
Member

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

@simonrozsivalsimonrozsival changed the title Reject open generic JNI construction[TrimmableTypeMap] Reject open generic JNI constructionMay 3, 2026
@simonrozsivalsimonrozsival 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
CopilotAI review requested due to automatic review settings May 3, 2026 20:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

FileDescription
tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.csRemoves two Java.Interop tests from the trimmable typemap exclusion list so they run again.
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.csRemoves an outdated TODO tied to open-generic creation behavior.
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.csAdjusts generator tests to validate the marshal-method wrapper + exception regions for open-generic UCO constructor callbacks.
src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.csEmits a throwing UCO constructor callback for open-generic proxies instead of a no-op body.

@simonrozsivalsimonrozsival 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
simonrozsivaland 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
simonrozsivalforce-pushed the trimmable-open-generic-activation branch from 2f1b066 to 4b6aa5eCompareMay 4, 2026 18:31
@simonrozsivalsimonrozsival 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
simonrozsivaland 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>
@simonrozsivalsimonrozsival 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

github-actionsBot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Android PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

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

- 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>
@simonrozsival
simonrozsival disabled auto-merge May 6, 2026 08:19
@simonrozsival
simonrozsival merged commit cc00f2d into mainMay 6, 2026
3 checks passed
@simonrozsival
simonrozsival deleted the trimmable-open-generic-activation branch May 6, 2026 08:19
CopilotAI added a commit that referenced this pull request May 6, 2026
…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>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 5, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

copilot`copilot-cli` or other AIs were used to author thisready-to-reviewThis 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

@simonrozsival@jonathanpeppers