-
Notifications
You must be signed in to change notification settings - Fork 552
[CoreCLR] Implement GC bridge #10198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs
Outdated
Show resolved
Hide resolved
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 introduces a new GC bridge to support improved garbage collection coordination between the managed and Java runtimes, replacing #10185 and aligning with the related runtime changes. Key changes include the implementation of GC bridge interfaces and processing logic in native code, updates to pinvoke tables and build configuration, and modifications in the ManagedValueManager and various JNI bridging files to use the new GC bridge callbacks.
Reviewed Changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
src/native/clr/include/host/gc-bridge.hh | Adds new structures and functions to support native GC bridge callbacks. |
src/native/clr/include/host/bridge-processing.hh | Introduces types and functions for processing cross-references. |
src/native/clr/host/pinvoke-tables.include | Updates the internal pinvoke table, increasing the expected count. |
src/native/clr/host/gc-bridge.cc | Implements the GC bridge’s processing thread and callback logic. |
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs | Transitions peer management to use the new GC bridge initialization. |
(Other JNI-related files) | Replaces outdated references to JNIEnvInit.ValueManager with JniEnvironment.Runtime.ValueManager for consistency. |
Comments suppressed due to low confidence (1)
src/Mono.Android/Android.Runtime/JNIEnvInit.cs:40
- Since all references now use JniEnvironment.Runtime.ValueManager, consider removing this unused field to avoid confusion and improve code maintainability.
}
) Context: #10198 This PR contains bits from #10198 which don't depend on new APIs in dotnet/runtime. * Turn `ManagedValueManager` into singleton, for safety/correctness, as we don't want to be calling `JavaMarsha.Initialize()` more than once. * Create `SimpleValueManager` for NativeAOT, which is the "simple" implementation that just leaks... Eventually, `ManagedValueManager` will use the new `JavaMarshal` APIs and `SimpleValueManager` will be used temporarily for NativeAOT. `SimpleValueManager` can be removed in the future when `JavaMarshal` is implemented for NativeAOT.
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs
Outdated
Show resolved
Hide resolved
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com> Co-authored-by: Marek Habersack <grendel@twistedcode.net>
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs
Outdated
Show resolved
Hide resolved
src/Mono.Android/Microsoft.Android.Runtime/ManagedValueManager.cs
Outdated
Show resolved
Hide resolved
ThrowIfDisposed (); | ||
|
||
while (CollectedContexts.TryDequeue (out IntPtr contextPtr)) { | ||
HandleContext* context = (HandleContext*)contextPtr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we validate contextPtr
? Is it possible for it to be IntPtr.Zero
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not possible for it to be Zero
here. We're only enqueuing non-zero contexts on line 448 and all the manipulation modifying the CollectedContexts
queue is encapsulated in ManagedValueManager
. We can add a Trace.Assert (contextPtr != IntPtr.Zero, "Context should never be null.");
of course to future-proof that invariant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, no need to add an assert - but can you add a comment describing why there can't be IntPtr.Zero
here?
Replaces #10185
Implements dotnet/runtime#115506
Builds on top of dotnet/runtime#116310 - this PR is expected to fail to build until this runtime PR is merged and flows into
main
- blocked by dotnet/dotnet#1392Description
This PR implements GC bridge for CoreCLR using the
JavaMarshal
APIs introduced in dotnet/runtime#116310. The code in this PR is CoreCLR specific and while it will build with other runtimes on .NET 10, theManagedValueManager
class will throw on any other runtime other than CoreCLR. In the future, the same GC bridge mechanism should be also supported by Native AOT, so this code might be reused for that platform as well at some point.The code of the GC bridge is placed in 3 main locations:
ManagedValueManager.cs
Code in this class interfaces with the
JavaMarshal
APIs.This class keeps a dictionary of mapping between .NET and Java objects
RegisteredInstances
.The class carefuly manages the lifetimes of the bridge objects and their associated native memory ("GC bridge context" -
HandleContext
). The implementation follows these rules:Target
of the reference trackingGCHandles
. Doing this could cause a race condition with the GC collecting handles in background thread. Instead, always access the peers viaWeakReference<IJavaPeerable>.Target
which blocks if there is an ongoing bridge processing.RegisteredInstances
during bridge processing. Doing this would require taking a lock onRegisteredInstances
which might already be locked in some other method ofManagedValueManager
called from another thread (for example theAddPeer
method) which might be blocked waiting onWeakReference<IJavaPeerable>.Target
to return. For this reason, we have a queue of known dead weak references stored in theRegisteredInstances
method which we fill at the end of bridge processing. This queue needs to be periodically emptied before calls toAddPeer
and others to make sure that weak references stored inRegisteredInstances
aren't leaking.HandleContext*
. Anyone can call theJavaMarshal.CreateReferenceTrackingHandle(...)
method and "poison" the contexts that will be passed to us by the GC with pointers to memory we don't own and can't guarantee the size of the memory or even the fact that the memory won't be freed before the GC passes the pointer to our bridge processing callback. We keep a static dictionary of all the contexts and their associated GCHandles inHandleContext
to validate the pointers we receive and also to map the contexts to their corresponding handles before callingJavaMarshal.FinishBridgeProcessing
.gc-bridge.hh+cc
This static class contains the main callback for the GC bridge (
GCBridge::mark_cross_references
). The GC expect this method to return immediately and do all the bridge processing in a separate thread. The input to this method is a pointer (MarkCrossReferencesArgs *args
) which needs to be later passed toJavaMarshal.FinishBridgeProcessing(...)
in order to be freed.This class also contains a background thread which waits for the next bridge processing event using a
std::binary_semaphore
. Once the thread is signaled there is a new bridge procesing event, it uses anBridgeProcessing
object to process it.bridge-processing.hh+cc
The
BridgeProcessing
class implements processing of a single bridge processing event. The code in this class is based on the Mono bridge processing algorithm implemented insrc/native/mono/monodroid/osbridge.cc
./cc @BrzVlad @jonathanpeppers @grendello