Skip to content

Commit 8f04692

Browse files
committed
[Java.Interop] JNI handles are now in a "control block"
Context: dotnet/runtime#114184 Context: dotnet/android#10125 Context: dotnet/android#10125 (comment) Part of adding a GC bridge to CoreCLR are the new APIs: namespace System.Runtime.InteropServices.Java; public struct ComponentCrossReference { public nint SourceGroupIndex, DestinationGroupIndex; } public unsafe struct StronglyConnectedComponent { public nint Count; public IntPtr* Context; } public static partial class JavaMarshal { public static unsafe void Initialize( delegate* unmanaged< System.IntPtr, // sccsLen StronglyConnectedComponent*, // sccs System.IntPtr, // ccrsLen ComponentCrossReference*, // ccrs void> markCrossReferences); public static GCHandle CreateReferenceTrackingHandle(object obj, IntPtr context); public static IntPtr GetContext(GCHandle obj); } Of note is the "data flow" of `context`: * `JavaMarshal.CreateReferenceTrackingHandle()` has a "`context`" parameter. * The `context` parameter to `JavaMarshal.CreateReferenceTrackingHandle()` is the return value of `JavaMarshal.GetContext()` * The `context` parameter to `JavaMarshal.CreateReferenceTrackingHandle()` is stored within `StronglyConnectedComponent.Context`. * The `markCrossReferences` parameter of `JavaMarshal.Initialize()` is called by the GC bridge and given a native array of `StronglyConnectedComponent` instances, which contains `Context`. The short of it is that the proposed GC bridge doesn't contain direct access to the `IJavaPeerable` instances in play. Instead, it has access to "context" which must contain the JNI Object Reference information that the `markCrossReferences` callback needs access to. Furthermore, the `context` pointer value *cannot change*, i.e. it needs to be a native pointer value a'la **malloc**(3), ***not*** a value which can be moved by the GC. (The *contents* can change; the pointer value cannot.)) While we're still prototyping this, what we currently believe we need is the JNI object reference, JNI object reference type, and (maybe?) the JNI Weak Global Reference value and "refs added" values. Update `IJavaPeerable` to add a `JniObjectReferenceControlBlock` property which can be used as the `context` parameter: partial interface IJavaPeerable { IntPtr JniObjectReferenceControlBlock => 0; } This supports usage of: IJavaPeerable value = … GCHandle handle = JavaMarshal.CreateReferenceTrackingHandle( value, value.JniObjectReferenceControlBlock );
1 parent d909947 commit 8f04692

File tree

3 files changed

+26
-11
lines changed

3 files changed

+26
-11
lines changed

src/Java.Interop/Java.Interop/IJavaPeerable.cs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public interface IJavaPeerable : IDisposable
3737
void Disposed ();
3838
/// <include file="../Documentation/Java.Interop/IJavaPeerable.xml" path="/docs/member[@name='M:Finalized']/*" />
3939
void Finalized ();
40+
41+
IntPtr JniObjectReferenceControlBlock => IntPtr.Zero;
4042
}
4143
}
4244

src/Java.Interop/Java.Interop/JavaObject.cs

+23-11
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,9 @@ unsafe public class JavaObject : IJavaPeerable
2525
[NonSerialized] JniObjectReference reference;
2626
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
2727
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
28-
[NonSerialized] IntPtr handle;
29-
[NonSerialized] JniObjectReferenceType handle_type;
30-
#pragma warning disable 0169
31-
// Used by JavaInteropGCBridge
32-
[NonSerialized] IntPtr weak_handle;
33-
[NonSerialized] int refs_added;
34-
#pragma warning restore 0169
28+
IntPtr jniObjectReferenceControlBlock;
29+
unsafe JniObjectReferenceControlBlock* JniObjectReferenceControlBlock =>
30+
(JniObjectReferenceControlBlock*) jniObjectReferenceControlBlock;
3531
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
3632

3733
protected static readonly JniObjectReference* InvalidJniObjectReference = null;
@@ -41,13 +37,17 @@ unsafe public class JavaObject : IJavaPeerable
4137
JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
4238
}
4339

44-
public JniObjectReference PeerReference {
40+
public unsafe JniObjectReference PeerReference {
4541
get {
4642
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
4743
return reference;
4844
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
4945
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
50-
return new JniObjectReference (handle, handle_type);
46+
var c = JniObjectReferenceControlBlock;
47+
if (c == null) {
48+
return default;
49+
}
50+
return new JniObjectReference (c->handle, (JniObjectReferenceType) c->handle_type);
5151
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
5252
}
5353
}
@@ -91,8 +91,14 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
9191
this.reference = reference;
9292
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
9393
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
94-
this.handle = reference.Handle;
95-
this.handle_type = reference.Type;
94+
var c = JniObjectReferenceControlBlock;
95+
if (c == null) {
96+
jniObjectReferenceControlBlock =
97+
Java.Interop.JniObjectReferenceControlBlock.Alloc ();
98+
c = JniObjectReferenceControlBlock;
99+
}
100+
c->handle = reference.Handle;
101+
c->handle_type = (int) reference.Type;
96102
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
97103

98104
JniObjectReference.Dispose (ref reference, options);
@@ -117,6 +123,9 @@ public virtual void DisposeUnlessReferenced ()
117123

118124
protected virtual void Dispose (bool disposing)
119125
{
126+
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
127+
Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock);
128+
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
120129
}
121130

122131
public override bool Equals (object? obj)
@@ -169,6 +178,9 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
169178
{
170179
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
171180
}
181+
182+
IntPtr IJavaPeerable.JniObjectReferenceControlBlock =>
183+
jniObjectReferenceControlBlock;
172184
}
173185
}
174186

src/Java.Interop/PublicAPI.Unshipped.txt

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ Java.Interop.JniRuntime.JniTypeManager.GetInvokerType(System.Type! type) -> Syst
1111
Java.Interop.JniRuntime.JniValueManager.GetPeer(Java.Interop.JniObjectReference reference, System.Type? targetType = null) -> Java.Interop.IJavaPeerable?
1212
Java.Interop.JniTypeSignatureAttribute.InvokerType.get -> System.Type?
1313
Java.Interop.JniTypeSignatureAttribute.InvokerType.set -> void
14+
Java.Interop.IJavaPeerable.JniObjectReferenceControlBlock.get -> nint

0 commit comments

Comments
 (0)