This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 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
This repository was archived by the owner on Aug 27, 2026. It is now read-only.

Remove JniObjectReference SafeHandle backend - #1446

Merged
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles
Jun 8, 2026
Merged

Remove JniObjectReference SafeHandle backend#1446
jonathanpeppers merged 3 commits into
mainfrom
dev/simonrozsival/remove-jniobjectreference-safehandles

Conversation

@simonrozsival

@simonrozsivalsimonrozsival commented Jun 8, 2026

Copy link
Copy Markdown
Member

Related to dotnet/android#11843

Summary

Remove the unsupported JniObjectReference SafeHandle backend and make the existing IntPtr representation the only implementation:

  • remove FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES / FEATURE_JNIOBJECTREFERENCE_INTPTRS branching from Java.Interop
  • delete the unused JniReferenceSafeHandle, JniLocalReference, JniGlobalReference, JniWeakGlobalReference, and JniAllocObjectRef types
  • delete the excluded SafeHandle-specific test
  • remove the obsolete SafeHandle invocation strategy from jnienv-gen and regenerate tests/invocation-overhead/jni.cs
  • update docs to describe the SafeHandle path as a historical experiment, not a supported backend

Decision record

The SafeHandle backend was useful when Java.Interop was exploring how JNI object references should be represented. The architecture and invocation-overhead docs show the intended goals: stronger handle separation, possible GC cleanup of leaked JNI refs, and a way to compare a safer representation against an IntPtr representation.

That experiment has been rejected for the current runtime model:

  • the active project build always used the IntPtr-backed JniObjectReference path
  • trying to enable the SafeHandle object-reference symbol conflicts with the default FEATURE_JNIOBJECTREFERENCE_INTPTRS define
  • the SafeHandle-only test was explicitly excluded from both this repo's test project and the Android test project
  • the SafeHandle branch had stale code and was not maintained as a buildable configuration
  • historical benchmarks showed SafeHandle-based JNI invocation was materially slower due to allocation and thread-safety costs
  • Android now depends on the JniObjectReferenceControlBlock/IntPtr model for runtime and GC-bridge integration

Since there are no current plans to resurrect the SafeHandle backend, keeping it adds noise and gives a false impression that the configuration is supported. Git history preserves the experiment if it is ever needed again.

Validation

  • dotnet build -t:Prepare -nologo -m:1
  • dotnet build src/Java.Interop/Java.Interop.csproj -nologo
  • dotnet build build-tools/jnienv-gen/jnienv-gen.csproj -nologo
  • dotnet build tests/invocation-overhead/invocation-overhead.csproj -nologo -p:NativeToolchainSupported=false
  • dotnet test tests/Java.Interop-Tests/Java.Interop-Tests.csproj -nologo -p:NativeToolchainSupported=false
    • Passed: 671, Failed: 0, Skipped: 4

I also attempted dotnet build Java.Interop.sln -nologo. The local full-solution build is blocked by unrelated environment/baseline failures, including the native link step failing with ld: library 'c++' not found and unrelated generated Java.Base/Kotlin-Gradle failures.

The SafeHandle-backed object reference implementation was an old experiment kept for migration and performance comparison, but the active build has long used the IntPtr-backed JniObjectReference path only. Remove the unsupported feature switches, SafeHandle reference types, excluded tests, and the obsolete SafeHandle invocation-overhead strategy.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings June 8, 2026 09:39

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the previously experimental/unsupported SafeHandle-backed JniObjectReference implementation path so that the IntPtr representation is the sole supported backend across Java.Interop and related benchmark tooling/docs. This reduces conditional compilation branching, deletes unused SafeHandle-era types/tests, and updates the invocation-overhead benchmark to reflect only the currently supported invocation strategies.

Changes:

  • Removed SafeHandle backend code paths and deleted now-dead SafeHandle reference wrapper types from src/Java.Interop.
  • Removed the excluded SafeHandle-specific test and simplified test project configuration accordingly.
  • Removed SafeHandle strategy support from jnienv-gen, regenerated tests/invocation-overhead/jni.cs, and updated docs/benchmark README to describe SafeHandle as historical.
Show a summary per file
FileDescription
tests/Java.Interop-Tests/Java.Interop/JniReferenceSafeHandleTest.csDeletes the SafeHandle-only test fixture.
tests/Java.Interop-Tests/Java.Interop-Tests.csprojRemoves the explicit compile exclusion for the deleted SafeHandle test file.
tests/invocation-overhead/README.mdUpdates benchmark documentation to treat SafeHandle as historical and describe current strategies.
tests/invocation-overhead/jni.csRegenerates benchmark JNI bindings without the SafeHandle strategy.
tests/invocation-overhead/invocation-overhead.csprojDrops the SafeHandle feature define from the benchmark project.
tests/invocation-overhead/invocation-overhead.csRemoves SafeHandle benchmark implementation (SafeTiming) and related types/aliases.
src/Java.Interop/Java.Interop/JniWeakGlobalReference.csDeletes SafeHandle-backed weak-global reference wrapper type.
src/Java.Interop/Java.Interop/JniTransition.csRemoves SafeHandle-only local reference frame push/pop usage.
src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.csRemoves SafeHandle-only cross-thread local-ref invalidation logic.
src/Java.Interop/Java.Interop/JniReferenceSafeHandle.csDeletes base SafeHandle wrapper type and related helpers.
src/Java.Interop/Java.Interop/JniPeerMembers.csRemoves SafeHandle-only thread-safety checks for local refs.
src/Java.Interop/Java.Interop/JniObjectReference.csMakes JniObjectReference unconditionally IntPtr-backed and removes SafeHandle/feature-guarded branches.
src/Java.Interop/Java.Interop/JniLocalReference.csDeletes SafeHandle-backed local reference wrapper type.
src/Java.Interop/Java.Interop/JniGlobalReference.csDeletes SafeHandle-backed global reference wrapper type.
src/Java.Interop/Java.Interop/JniEnvironment.Types.csRemoves SafeHandle-only FindClass fallback logic and clarifies unsupported build-path behavior.
src/Java.Interop/Java.Interop/JniEnvironment.csRemoves SafeHandle-only local reference tracking/frame management code.
src/Java.Interop/Java.Interop/JniAllocObjectRef.csDeletes SafeHandle-only alloc-object local reference wrapper type.
src/Java.Interop/Java.Interop/JavaObject.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop/JavaException.csRemoves SafeHandle backend storage; keeps only control-block (IntPtr) peer reference storage.
src/Java.Interop/Java.Interop.csprojRemoves now-obsolete FEATURE_JNIOBJECTREFERENCE_INTPTRS constant from project defines.
Documentation/Architecture.mdUpdates architecture documentation to describe SafeHandle support as historical and the IntPtr model as supported.
build-tools/jnienv-gen/Generator.csRemoves SafeHandle emission path and updates generator preprocessor logic for remaining strategies.

Copilot's findings

  • Files reviewed: 21/22 changed files
  • Comments generated: 1

Comment threadbuild-tools/jnienv-gen/Generator.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@simonrozsival

Copy link
Copy Markdown
MemberAuthor

/review

@github-actions

github-actionsBot commented Jun 8, 2026

Copy link
Copy Markdown

Java.Interop PR Reviewer completed successfully!

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ LGTM — Clean removal of dead code

Well-executed cleanup that removes the unused SafeHandle-backed JniObjectReference experiment. The conditional compilation blocks were consistently removed, the jnienv-gen generator was properly updated, documentation accurately describes the SafeHandle path as historical, and no references to the removed feature flags remain in src/.

Positive callouts:

  • Thorough removal — all FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES, FEATURE_JNIOBJECTREFERENCE_INTPTRS, and FEATURE_JNIENVIRONMENT_SAFEHANDLES references are gone
  • The _NAMESPACE_PER_HANDLE logic in Generator.cs was correctly updated to detect when any two of the remaining four handle styles coexist, rather than only triggering on SafeHandle + another style
  • Good safety net: JniEnvironment.Types.cs now has a #else throw NotSupportedException(...) for unsupported build configurations
  • Clear PR description with decision record explaining why the code was removed

One inline comment on tests/invocation-overhead/jni.cs — the #endif comment on line 8 is missing !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS (the #if has four conditions, the comment only lists three). The updated Generator.cs fixes this, but jni.cs appears not to have been regenerated from it. Since it's regenerated at build time, this is low-impact.

Note (not in diff — can't comment inline):tests/Java.Interop-Tests/Java.Interop/JavaVMFixture.Partial.cs has a HaveSafeHandles field that uses reflection to check for the now-removed gcHandle field on JniObjectReference. It will always return false now. Tests relying on it (JniTransitionTest.Dispose_ClearsLocalReferences, GetValue_ReturnsNullWithInvalidSafeHandle) will always be skipped. Consider cleaning these up in a follow-up.

Generated by Java.Interop PR Reviewer for issue #1446 · ● 12.9M

Comment threadtests/invocation-overhead/jni.cs Outdated
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
#endif // !FEATURE_JNIENVIRONMENT_SAFEHANDLES && !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️Formatting#endif comment doesn't match the #if expression. The #if on line 6 has four conditions (including !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS), but this #endif comment only lists three. The updated Generator.cs (line 93) now correctly emits the full expression, but this file wasn't regenerated from it.

Since jni.cs is regenerated at build time via invocation-overhead.targets, this will fix itself on the next build, but the checked-in file should match the generator output. Consider re-running jnienv-gen to update this file.

Rule: #else/#endif comments must match the original expression

@simonrozsival

Copy link
Copy Markdown
MemberAuthor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d4-415ad84d81a6.ps1'
HEAD detached at origin/825a0b65d82ead999eede3c5dfb29e2c3ebcea62
Changes not staged for commit:
modified: tests/invocation-overhead/jni.cs
no changes added to commit
##[error]git tree has modified tracked files.
diff --git a/tests/invocation-overhead/jni.cs b/tests/invocation-overhead/jni.cs
index d52b558..7f8a432 100644
--- a/tests/invocation-overhead/jni.cs
+++ b/tests/invocation-overhead/jni.cs
@@ -5,7 +5,7 @@
#if !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#define FEATURE_JNIENVIRONMENT_JI_PINVOKES
-#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS
+#endif // !FEATURE_JNIENVIRONMENT_JI_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_PINVOKES && !FEATURE_JNIENVIRONMENT_XA_INTPTRS && !FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS
#if FEATURE_JNIENVIRONMENT_JI_INTPTRS && (FEATURE_JNIENVIRONMENT_JI_PINVOKES || FEATURE_JNIENVIRONMENT_XA_INTPTRS || FEATURE_JNIENVIRONMENT_JI_FUNCTION_POINTERS)
#define _NAMESPACE_PER_HANDLE

Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>

CopilotAI commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

@copilot address the build failure - it appears jni.cs needs to be regenerated:

/usr/local/bin/pwsh -NoLogo -NoProfile -NonInteractive -Command . '/Users/runner/work/_temp/e7ea884c-1831-4a74-a6d...

Fixed in 8267937.

tests/invocation-overhead/jni.cs is now regenerated with the updated #endif condition comment from jnienv-gen, and local regeneration/build prep no longer leaves jni.cs dirty.

@simonrozsivalsimonrozsival added the ready-to-review This PR is ready to review/merge, thanks! label Jun 8, 2026
@jonathanpeppers
jonathanpeppers merged commit b881d21 into mainJun 8, 2026
2 checks passed
@jonathanpeppers
jonathanpeppers deleted the dev/simonrozsival/remove-jniobjectreference-safehandles branch June 8, 2026 17:48
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-to-reviewThis PR is ready to review/merge, thanks!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@simonrozsival@jonathanpeppers