Skip to content

Drop global Instance of JavaMarshalValueManager#11524

Merged
jonathanpeppers merged 1 commit into
mainfrom
dev/simonrozsival/java-marshal-value-manager-cleanup
May 28, 2026
Merged

Drop global Instance of JavaMarshalValueManager#11524
jonathanpeppers merged 1 commit into
mainfrom
dev/simonrozsival/java-marshal-value-manager-cleanup

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented May 27, 2026

Summary

  • pass the JavaMarshalValueManager handle through CoreCLR GC bridge initialization
  • remove the static JavaMarshalValueManager.Instance singleton lookup from bridge processing
  • update managed and native bridge callback signatures to use the instance handle

@simonrozsival simonrozsival marked this pull request as ready for review May 28, 2026 06:40
Copilot AI review requested due to automatic review settings May 28, 2026 06:40
@simonrozsival simonrozsival added Area: CoreCLR Issues that only occur when using CoreCLR. ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). labels May 28, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the managed JavaMarshalValueManager.Instance singleton lookup and passes the active value-manager handle through the CoreCLR GC bridge so bridge completion processing can operate on the correct instance.

Changes:

  • Threads a JavaMarshalValueManager GC handle through managed/native GC bridge initialization and completion callbacks.
  • Converts bridge completion context processing from static singleton lookup to instance-based processing.
  • Updates NativeAOT/CoreCLR value-manager creation paths to instantiate JavaMarshalValueManager directly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/native/clr/include/runtime-base/internal-pinvokes.hh Updates native P/Invoke declaration to accept the value-manager handle.
src/native/clr/include/host/gc-bridge.hh Stores the value-manager handle and updates the finished callback signature.
src/native/clr/host/internal-pinvokes-shared.cc Forwards the value-manager handle into GC bridge initialization.
src/native/clr/host/gc-bridge.cc Passes the stored handle when invoking bridge completion.
src/Mono.Android/Microsoft.Android.Runtime/JavaMarshalValueManager.cs Removes singleton access and resolves bridge completion through a GC handle.
src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs Updates managed native method and callback signatures.
src/Mono.Android/Android.Runtime/JNIEnvInit.cs Splits CoreCLR and NativeAOT value-manager creation branches.
src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs Replaces singleton fallback with direct JavaMarshalValueManager construction.

Comment thread src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs
@simonrozsival
Copy link
Copy Markdown
Member Author

/review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 28, 2026

Android PR Reviewer completed successfully!

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ LGTM (with minor suggestions)

Good cleanup — removing the static singleton and threading the instance handle through the native GC bridge callback is a solid improvement for testability and clarity.

Summary of findings:

  • ⚠️ (1) The GCHandle created in the constructor is never stored/freed — likely fine for a process-lifetime singleton but worth making explicit
  • 💡 (2) Minor formatting/organization nits

The native ↔ managed boundary changes are consistent across all files (C#, C++, headers, pinvoke declarations). The callback signature updates match correctly.

Generated by Android PR Reviewer for issue #11524 · ● 8.1M


ReadOnlySpan<GCHandle> handlesToFree = instance.ProcessCollectedContexts (mcr);


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 — Extra blank line here (two consecutive blank lines).

Rule: Minimal diffs

Comment on lines +190 to 195
if (RuntimeFeature.IsCoreClrRuntime) {
return new JavaMarshalValueManager ();
}

if (RuntimeFeature.IsNativeAotRuntime) {
return new JavaMarshalValueManager ();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 💡 Code organization — These two branches have identical bodies. Unless there's a planned divergence (different JavaMarshalValueManager configuration per runtime), this could stay as the original if (RuntimeFeature.IsCoreClrRuntime || RuntimeFeature.IsNativeAotRuntime). If there is a plan to diverge, a comment explaining why they're split would help future readers.

Rule: Remove unused code / YAGNI


// There can only be one instance because JavaMarshal.Initialize can only be called once.
var mark_cross_references_ftn = RuntimeNativeMethods.clr_initialize_gc_bridge (&BridgeProcessingStarted, &BridgeProcessingFinished);
var javaMarshalValueManagerHandle = new GCHandle<JavaMarshalValueManager> (this);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 ⚠️ Resource management — The GCHandle<JavaMarshalValueManager> is created here but never stored as a field, so it can never be freed in Dispose(). This keeps the managed object pinned for the entire process lifetime.

Since there's only ever one JavaMarshalValueManager and it lives for the app's lifetime, this is probably acceptable — but it should be explicit. Consider storing it as a field and freeing it in Dispose(bool), or at minimum adding a comment explaining why the handle is intentionally leaked (e.g., "the native side holds this handle for the process lifetime; freeing it in Dispose would race with GC bridge callbacks").

Rule: Resource management (Postmortem #11)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is the same as before, we could do this in Dispose(), but that will never get called anyway.

@jonathanpeppers jonathanpeppers merged commit 2c61d37 into main May 28, 2026
4 checks passed
@jonathanpeppers jonathanpeppers deleted the dev/simonrozsival/java-marshal-value-manager-cleanup branch May 28, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: CoreCLR Issues that only occur when using CoreCLR. ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants