Skip to content

[Java.Interop] JNI handles are now in a "control block" #1339

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

Merged
merged 7 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Java.Interop/Java.Interop/IJavaPeerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public interface IJavaPeerable : IDisposable
void Disposed ();
/// <include file="../Documentation/Java.Interop/IJavaPeerable.xml" path="/docs/member[@name='M:Finalized']/*" />
void Finalized ();

IntPtr JniObjectReferenceControlBlock => IntPtr.Zero;
}
}

29 changes: 19 additions & 10 deletions src/Java.Interop/Java.Interop/JavaException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@ unsafe public class JavaException : Exception, IJavaPeerable
JniObjectReference reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
IntPtr handle;
JniObjectReferenceType handle_type;
#pragma warning disable 0169
// Used by JavaInteropGCBridge
IntPtr weak_handle;
int refs_added;
#pragma warning restore 0169
unsafe JniObjectReferenceControlBlock* jniObjectReferenceControlBlock;
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS

protected static readonly JniObjectReference* InvalidJniObjectReference = null;
Expand Down Expand Up @@ -106,7 +100,11 @@ public JniObjectReference PeerReference {
return reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
return new JniObjectReference (handle, handle_type);
var c = jniObjectReferenceControlBlock;
if (c == null) {
return default;
}
return new JniObjectReference (c->handle, (JniObjectReferenceType) c->handle_type);
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}
}
Expand Down Expand Up @@ -137,8 +135,13 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
this.reference = reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
this.handle = reference.Handle;
this.handle_type = reference.Type;
var c = jniObjectReferenceControlBlock;
if (c == null) {
c = jniObjectReferenceControlBlock =
Java.Interop.JniObjectReferenceControlBlock.Alloc ();
}
c->handle = reference.Handle;
c->handle_type = (int) reference.Type;
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS

JniObjectReference.Dispose (ref reference, options);
Expand Down Expand Up @@ -167,6 +170,9 @@ protected virtual void Dispose (bool disposing)
if (inner != null) {
inner.Dispose ();
}
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock);
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}

public override bool Equals (object? obj)
Expand Down Expand Up @@ -282,6 +288,9 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
{
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
}

IntPtr IJavaPeerable.JniObjectReferenceControlBlock =>
(IntPtr) jniObjectReferenceControlBlock;
}
}

31 changes: 20 additions & 11 deletions src/Java.Interop/Java.Interop/JavaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,7 @@ unsafe public class JavaObject : IJavaPeerable
[NonSerialized] JniObjectReference reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
[NonSerialized] IntPtr handle;
[NonSerialized] JniObjectReferenceType handle_type;
#pragma warning disable 0169
// Used by JavaInteropGCBridge
[NonSerialized] IntPtr weak_handle;
[NonSerialized] int refs_added;
#pragma warning restore 0169
unsafe JniObjectReferenceControlBlock* jniObjectReferenceControlBlock;
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS

protected static readonly JniObjectReference* InvalidJniObjectReference = null;
Expand All @@ -41,13 +35,17 @@ unsafe public class JavaObject : IJavaPeerable
JniEnvironment.Runtime.ValueManager.FinalizePeer (this);
}

public JniObjectReference PeerReference {
public unsafe JniObjectReference PeerReference {
get {
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
return reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
return new JniObjectReference (handle, handle_type);
var c = jniObjectReferenceControlBlock;
if (c == null) {
return default;
}
return new JniObjectReference (c->handle, (JniObjectReferenceType) c->handle_type);
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}
}
Expand Down Expand Up @@ -92,8 +90,13 @@ protected void SetPeerReference (ref JniObjectReference reference, JniObjectRefe
this.reference = reference;
#endif // FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
this.handle = reference.Handle;
this.handle_type = reference.Type;
var c = jniObjectReferenceControlBlock;
if (c == null) {
c = jniObjectReferenceControlBlock =
Java.Interop.JniObjectReferenceControlBlock.Alloc ();
}
c->handle = reference.Handle;
c->handle_type = (int) reference.Type;
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS

JniObjectReference.Dispose (ref reference, options);
Expand All @@ -118,6 +121,9 @@ public virtual void DisposeUnlessReferenced ()

protected virtual void Dispose (bool disposing)
{
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock);
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}

public override bool Equals (object? obj)
Expand Down Expand Up @@ -170,6 +176,9 @@ void IJavaPeerable.SetPeerReference (JniObjectReference reference)
{
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
}

IntPtr IJavaPeerable.JniObjectReferenceControlBlock =>
(IntPtr) jniObjectReferenceControlBlock;
}
}

27 changes: 27 additions & 0 deletions src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Runtime.InteropServices;

namespace Java.Interop;

internal struct JniObjectReferenceControlBlock {
public IntPtr handle;
public int handle_type;
public IntPtr weak_handle;
public int refs_added;

public static readonly int Size = Marshal.SizeOf<JniObjectReferenceControlBlock>();

public static unsafe JniObjectReferenceControlBlock* Alloc ()
{
return (JniObjectReferenceControlBlock*) NativeMemory.AllocZeroed (1, (uint) Size);
}

public static unsafe void Free (ref JniObjectReferenceControlBlock* value)
{
if (value == null) {
return;
}
NativeMemory.Free (value);
value = null;
}
}
1 change: 1 addition & 0 deletions src/Java.Interop/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Java.Interop.JniRuntime.JniTypeManager.GetInvokerType(System.Type! type) -> Syst
Java.Interop.JniRuntime.JniValueManager.GetPeer(Java.Interop.JniObjectReference reference, System.Type? targetType = null) -> Java.Interop.IJavaPeerable?
Java.Interop.JniTypeSignatureAttribute.InvokerType.get -> System.Type?
Java.Interop.JniTypeSignatureAttribute.InvokerType.set -> void
Java.Interop.IJavaPeerable.JniObjectReferenceControlBlock.get -> nint
Loading