Commit 1f8f719
[CoreCLR] Implement GC bridge (#10198)
Replaces: #10185
Implements: dotnet/runtime#115506
Builds on top of: dotnet/runtime#116310
### Description
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, the `ManagedValueManager` 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:
* Do not access the `Target` of the reference tracking `GCHandles`.
Doing this could cause a race condition with the GC collecting
handles in background thread. Instead, always access the peers via
`WeakReference<IJavaPeerable>.Target` which blocks if there is an
ongoing bridge processing.
* Do not modify the `RegisteredInstances` during _bridge processing_.
Doing this would require taking a lock on `RegisteredInstances`
which might already be locked in some other method of
`ManagedValueManager` called from another thread (for example the
`AddPeer` method) which might be blocked waiting on
`WeakReference<IJavaPeerable>.Target` to return. For this reason, we
have a queue of known dead weak references stored in the
`RegisteredInstances` method which we fill at the end of bridge
processing. This queue needs to be periodically emptied before calls
to `AddPeer` and others to make sure that weak references stored in
`RegisteredInstances` aren't leaking.
* Do not trust the context pointers coming from the GC to be
`HandleContext*`. Anyone can call the
`JavaMarshal.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 in
`HandleContext` to validate the pointers we receive and also to map
the contexts to their corresponding handles before calling
`JavaMarshal.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 to
`JavaMarshal.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 an
`BridgeProcessing` 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 in
[`src/native/mono/monodroid/osbridge.cc`][0].
[0]: https://github.com/dotnet/android/blob/8c0ca82e407761fac7ea959fa4d4819fa6e4eeac/src/native/mono/monodroid/osbridge.cc
Co-authored-by: Jonathan Peppers <[email protected]>
Co-authored-by: Marek Habersack <[email protected]>1 parent 868acb2 commit 1f8f719
File tree
17 files changed
+1089
-111
lines changed- src
- Mono.Android
- Android.Runtime
- Microsoft.Android.Runtime
- Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base
- native/clr
- host
- include
- host
- runtime-base
17 files changed
+1089
-111
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
629 | 629 | | |
630 | 630 | | |
631 | 631 | | |
632 | | - | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
633 | 635 | | |
634 | 636 | | |
635 | 637 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | | - | |
68 | | - | |
69 | | - | |
| 67 | + | |
70 | 68 | | |
71 | 69 | | |
72 | 70 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | | - | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
92 | 93 | | |
93 | 94 | | |
94 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
95 | 101 | | |
96 | 102 | | |
97 | 103 | | |
| |||
0 commit comments