Skip to content

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

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

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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;
}
}

35 changes: 24 additions & 11 deletions src/Java.Interop/Java.Interop/JavaException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Java.Interop
{
[JniTypeSignature (JniTypeName, GenerateJavaPeer=false)]
unsafe public class JavaException : Exception, IJavaPeerable
unsafe public partial class JavaException : Exception, IJavaPeerable
{
internal const string JniTypeName = "java/lang/Throwable";
readonly static JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaException));
Expand All @@ -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 @@ -260,11 +263,13 @@ protected void SetJavaStackTrace (JniObjectReference peerReferenceOverride = def

void IJavaPeerable.Disposed ()
{
JniManagedPeerState |= Disposed;
Dispose (disposing: true);
}

void IJavaPeerable.Finalized ()
{
JniManagedPeerState |= Disposed;
Dispose (disposing: false);
}

Expand All @@ -281,7 +286,15 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
void IJavaPeerable.SetPeerReference (JniObjectReference reference)
{
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);
#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
if (!reference.IsValid && JniManagedPeerState.HasFlag (Disposed)) {
Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock);
}
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}

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

38 changes: 26 additions & 12 deletions src/Java.Interop/Java.Interop/JavaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Java.Interop
{
[JniTypeSignature ("java/lang/Object", GenerateJavaPeer=false)]
[Serializable]
unsafe public class JavaObject : IJavaPeerable
unsafe public partial class JavaObject : IJavaPeerable
{
internal const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;

Expand All @@ -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 @@ -91,8 +89,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 @@ -147,11 +150,13 @@ public override unsafe int GetHashCode ()

void IJavaPeerable.Disposed ()
{
managedPeerState |= Disposed;
Dispose (disposing: true);
}

void IJavaPeerable.Finalized ()
{
managedPeerState |= Disposed;
Dispose (disposing: false);
}

Expand All @@ -168,7 +173,16 @@ void IJavaPeerable.SetJniManagedPeerState (JniManagedPeerStates value)
void IJavaPeerable.SetPeerReference (JniObjectReference reference)
{
SetPeerReference (ref reference, JniObjectReferenceOptions.Copy);

#if FEATURE_JNIOBJECTREFERENCE_INTPTRS
if (!reference.IsValid && managedPeerState.HasFlag (Disposed)) {
Java.Interop.JniObjectReferenceControlBlock.Free (ref jniObjectReferenceControlBlock);
}
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
}

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

8 changes: 8 additions & 0 deletions src/Java.Interop/Java.Interop/JniManagedPeerStates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,12 @@ public enum JniManagedPeerStates {
/// <include file="../Documentation/Java.Interop/JniManagedPeerStates.xml" path="/docs/member[@name='F:Replaceable']/*" />
Replaceable = (1 << 1),
}

partial class JavaObject {
const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2);
}

partial class JavaException {
const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2);
}
}
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