diff --git a/src/Java.Interop/Java.Interop/IJavaPeerable.cs b/src/Java.Interop/Java.Interop/IJavaPeerable.cs
index 612744b10..a1888e7e8 100644
--- a/src/Java.Interop/Java.Interop/IJavaPeerable.cs
+++ b/src/Java.Interop/Java.Interop/IJavaPeerable.cs
@@ -37,6 +37,8 @@ public interface IJavaPeerable : IDisposable
void Disposed ();
///
void Finalized ();
+
+ IntPtr JniObjectReferenceControlBlock => IntPtr.Zero;
}
}
diff --git a/src/Java.Interop/Java.Interop/JavaException.cs b/src/Java.Interop/Java.Interop/JavaException.cs
index b07735b5a..23280e05c 100644
--- a/src/Java.Interop/Java.Interop/JavaException.cs
+++ b/src/Java.Interop/Java.Interop/JavaException.cs
@@ -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));
@@ -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;
@@ -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
}
}
@@ -137,8 +135,14 @@ 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 (reference);
+ } else {
+ c->handle = reference.Handle;
+ c->handle_type = (int) reference.Type;
+ }
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
JniObjectReference.Dispose (ref reference, options);
@@ -260,11 +264,13 @@ protected void SetJavaStackTrace (JniObjectReference peerReferenceOverride = def
void IJavaPeerable.Disposed ()
{
+ JniManagedPeerState |= Disposed;
Dispose (disposing: true);
}
void IJavaPeerable.Finalized ()
{
+ JniManagedPeerState |= Disposed;
Dispose (disposing: false);
}
@@ -281,7 +287,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;
}
}
diff --git a/src/Java.Interop/Java.Interop/JavaObject.cs b/src/Java.Interop/Java.Interop/JavaObject.cs
index fd3d68d3e..04a14861f 100644
--- a/src/Java.Interop/Java.Interop/JavaObject.cs
+++ b/src/Java.Interop/Java.Interop/JavaObject.cs
@@ -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;
@@ -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
+ [NonSerialized] unsafe JniObjectReferenceControlBlock* jniObjectReferenceControlBlock;
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
protected static readonly JniObjectReference* InvalidJniObjectReference = null;
@@ -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
}
}
@@ -92,8 +90,14 @@ 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 (reference);
+ } else {
+ c->handle = reference.Handle;
+ c->handle_type = (int) reference.Type;
+ }
#endif // FEATURE_JNIOBJECTREFERENCE_INTPTRS
JniObjectReference.Dispose (ref reference, options);
@@ -148,11 +152,13 @@ public override unsafe int GetHashCode ()
void IJavaPeerable.Disposed ()
{
+ managedPeerState |= Disposed;
Dispose (disposing: true);
}
void IJavaPeerable.Finalized ()
{
+ managedPeerState |= Disposed;
Dispose (disposing: false);
}
@@ -169,7 +175,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;
}
}
diff --git a/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs b/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs
index 765fb0b2d..b4f1fba3c 100644
--- a/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs
+++ b/src/Java.Interop/Java.Interop/JniManagedPeerStates.cs
@@ -11,4 +11,12 @@ public enum JniManagedPeerStates {
///
Replaceable = (1 << 1),
}
+
+ partial class JavaObject {
+ const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2);
+ }
+
+ partial class JavaException {
+ const JniManagedPeerStates Disposed = (JniManagedPeerStates) (1 << 2);
+ }
}
diff --git a/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs b/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs
new file mode 100644
index 000000000..3f2d6f8ec
--- /dev/null
+++ b/src/Java.Interop/Java.Interop/JniObjectReferenceControlBlock.cs
@@ -0,0 +1,30 @@
+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();
+
+ public static unsafe JniObjectReferenceControlBlock* Alloc (JniObjectReference reference)
+ {
+ var value = (JniObjectReferenceControlBlock*) NativeMemory.AllocZeroed (1, (uint) Size);
+ value->handle = reference.Handle;
+ value->handle_type = (int) reference.Type;
+ return value;
+ }
+
+ public static unsafe void Free (ref JniObjectReferenceControlBlock* value)
+ {
+ if (value == null) {
+ return;
+ }
+ NativeMemory.Free (value);
+ value = null;
+ }
+}
diff --git a/src/Java.Interop/PublicAPI.Unshipped.txt b/src/Java.Interop/PublicAPI.Unshipped.txt
index 90cde5ae6..90fda8ff8 100644
--- a/src/Java.Interop/PublicAPI.Unshipped.txt
+++ b/src/Java.Interop/PublicAPI.Unshipped.txt
@@ -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
diff --git a/src/java-interop/java-interop-gc-bridge-mono.cc b/src/java-interop/java-interop-gc-bridge-mono.cc
index aca306c60..cebe8ece9 100644
--- a/src/java-interop/java-interop-gc-bridge-mono.cc
+++ b/src/java-interop/java-interop-gc-bridge-mono.cc
@@ -30,12 +30,16 @@ using namespace xamarin::android;
typedef struct MonoJavaGCBridgeInfo {
MonoClass *klass;
- MonoClassField *handle;
- MonoClassField *handle_type;
- MonoClassField *refs_added;
- MonoClassField *weak_handle;
+ MonoClassField *jniObjectReferenceControlBlock;
} MonoJavaGCBridgeInfo;
+typedef struct JniObjectReferenceControlBlock {
+ jobject handle;
+ int handle_type;
+ jobject weak_handle;
+ int refs_added;
+} JniObjectReferenceControlBlock;
+
#define NUM_GC_BRIDGE_TYPES (4)
struct JavaInteropGCBridge {
@@ -72,6 +76,8 @@ struct JavaInteropGCBridge {
char *gref_path, *lref_path;
int gref_log_level, lref_log_level;
int gref_cleanup, lref_cleanup;
+
+ JavaInteropMarkCrossReferencesCallback mark_cross_references;
};
static jobject
@@ -366,13 +372,10 @@ java_interop_gc_bridge_register_bridgeable_type (
MonoJavaGCBridgeInfo *info = &bridge->mono_java_gc_bridge_info [i];
info->klass = mono_class_from_mono_type (type);
- info->handle = mono_class_get_field_from_name (info->klass, const_cast ("handle"));
- info->handle_type = mono_class_get_field_from_name (info->klass, const_cast ("handle_type"));
- info->refs_added = mono_class_get_field_from_name (info->klass, const_cast ("refs_added"));
- info->weak_handle = mono_class_get_field_from_name (info->klass, const_cast ("weak_handle"));
- if (info->klass == NULL || info->handle == NULL || info->handle_type == NULL ||
- info->refs_added == NULL || info->weak_handle == NULL)
+ info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast ("jniObjectReferenceControlBlock"));
+
+ if (info->klass == NULL || info->jniObjectReferenceControlBlock == NULL)
return -1;
bridge->num_bridge_types++;
return 0;
@@ -780,6 +783,18 @@ get_gc_bridge_info_for_object (JavaInteropGCBridge *bridge, MonoObject *object)
return get_gc_bridge_info_for_class (bridge, mono_object_get_class (object));
}
+static JniObjectReferenceControlBlock*
+get_gc_control_block_for_object (JavaInteropGCBridge *bridge, MonoObject *obj)
+{
+ MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
+ if (bridge_info == NULL)
+ return NULL;
+
+ JniObjectReferenceControlBlock *control_block;
+ mono_field_get_value (obj, bridge_info->jniObjectReferenceControlBlock, &control_block);
+ return control_block;
+}
+
typedef mono_bool (*MonodroidGCTakeRefFunc) (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, const char *thread_name, int64_t thread_id);
static MonodroidGCTakeRefFunc take_global_ref;
@@ -788,12 +803,11 @@ static MonodroidGCTakeRefFunc take_weak_global_ref;
static mono_bool
take_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, const char *thread_name, int64_t thread_id)
{
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
- if (bridge_info == NULL)
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, obj);
+ if (control_block == NULL)
return 0;
- jobject weak;
- mono_field_get_value (obj, bridge_info->weak_handle, &weak);
+ jobject weak = control_block->weak_handle;
jobject handle = env->CallObjectMethod (weak, bridge->WeakReference_get);
log_gref (bridge, "*try_take_global_2_1 obj=%p -> wref=%p handle=%p\n", obj, weak, handle);
@@ -808,12 +822,10 @@ take_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj,
java_interop_gc_bridge_weak_gref_log_delete (bridge, weak, get_object_ref_type (env, weak), thread_name, thread_id, "take_global_ref_java");
env->DeleteGlobalRef (weak);
weak = NULL;
- mono_field_set_value (obj, bridge_info->weak_handle, &weak);
- mono_field_set_value (obj, bridge_info->handle, &handle);
-
- int type = JNIGlobalRefType;
- mono_field_set_value (obj, bridge_info->handle_type, &type);
+ control_block->weak_handle = weak;
+ control_block->handle = handle;
+ control_block->handle_type = JNIGlobalRefType;
return handle != NULL;
}
@@ -821,12 +833,11 @@ take_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj,
static mono_bool
take_weak_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, const char *thread_name, int64_t thread_id)
{
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
- if (bridge_info == NULL)
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, obj);
+ if (control_block == NULL)
return 0;
- jobject handle;
- mono_field_get_value (obj, bridge_info->handle, &handle);
+ jobject handle = control_block->handle;
jobject weaklocal = env->NewObject (bridge->WeakReference_class, bridge->WeakReference_init, handle);
jobject weakglobal = env->NewGlobalRef (weaklocal);
@@ -838,8 +849,8 @@ take_weak_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject
java_interop_gc_bridge_gref_log_delete (bridge, handle, get_object_ref_type (env, handle), thread_name, thread_id, "take_weak_global_ref_2_1_compat");
env->DeleteGlobalRef (handle);
-
- mono_field_set_value (obj, bridge_info->weak_handle, &weakglobal);
+ control_block->handle = NULL;
+ control_block->weak_handle = weakglobal;
return 1;
}
@@ -847,13 +858,11 @@ take_weak_global_ref_java (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject
static mono_bool
take_global_ref_jni (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, const char *thread_name, int64_t thread_id)
{
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
- if (bridge_info == NULL)
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, obj);
+ if (control_block == NULL)
return 0;
- jobject weak;
- mono_field_get_value (obj, bridge_info->handle, &weak);
-
+ jobject weak = control_block->handle;
jobject handle = env->NewGlobalRef (weak);
log_gref (bridge, "*try_take_global obj=%p -> wref=%p handle=%p\n", obj, weak, handle);
@@ -868,22 +877,20 @@ take_global_ref_jni (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj,
thread_name, thread_id, "take_global_ref_jni");
env->DeleteWeakGlobalRef (weak);
- mono_field_set_value (obj, bridge_info->handle, &handle);
+ control_block->handle = handle;
+ control_block->handle_type = JNIGlobalRefType;
- int type = JNIGlobalRefType;
- mono_field_set_value (obj, bridge_info->handle_type, &type);
return handle != NULL;
}
static mono_bool
take_weak_global_ref_jni (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, const char *thread_name, int64_t thread_id)
{
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
- if (bridge_info == NULL)
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, obj);
+ if (control_block == NULL)
return 0;
- jobject handle;
- mono_field_get_value (obj, bridge_info->handle, &handle);
+ jobject handle = control_block->handle;
log_gref (bridge, "*take_weak obj=%p; handle=%p\n", obj, handle);
@@ -896,10 +903,8 @@ take_weak_global_ref_jni (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *
thread_name, thread_id, "take_weak_global_ref_jni");
env->DeleteGlobalRef (handle);
- mono_field_set_value (obj, bridge_info->handle, &weak);
-
- int type = JNIWeakGlobalRefType;
- mono_field_set_value (obj, bridge_info->handle_type, &type);
+ control_block->handle = weak;
+ control_block->handle_type = JNIWeakGlobalRefType;
return 1;
}
@@ -921,17 +926,18 @@ get_add_reference_method (JavaInteropGCBridge *bridge, JNIEnv *env, jobject obj,
}
static mono_bool
-add_reference (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, MonoJavaGCBridgeInfo *bridge_info, MonoObject *reffed_obj)
+add_reference (JavaInteropGCBridge *bridge, JNIEnv *env, MonoObject *obj, JniObjectReferenceControlBlock *control_block, MonoObject *reffed_obj)
{
MonoClass *klass = mono_object_get_class (obj);
- jobject handle;
- mono_field_get_value (obj, bridge_info->handle, &handle);
+ jobject handle = control_block->handle;
jmethodID add_method_id = get_add_reference_method (bridge, env, handle, klass);
if (add_method_id) {
- jobject reffed_handle;
- mono_field_get_value (reffed_obj, bridge_info->handle, &reffed_handle);
+ JniObjectReferenceControlBlock *reffed_control_block = get_gc_control_block_for_object (bridge, reffed_obj);
+ if (reffed_control_block == NULL)
+ return 0;
+ jobject reffed_handle = reffed_control_block->handle;
env->CallVoidMethod (handle, add_method_id, reffed_handle);
#if DEBUG
if (bridge->gref_log_level > 1)
@@ -979,28 +985,30 @@ gc_prepare_for_java_collection (JavaInteropGCBridge *bridge, JNIEnv *env, int nu
/* add java refs for items on the list which reference each other */
for (int i = 0; i < num_sccs; i++) {
MonoGCBridgeSCC *scc = sccs [i];
- MonoJavaGCBridgeInfo *bridge_info = NULL;
+
+ JniObjectReferenceControlBlock *control_block = NULL;
+
/* start at the second item, ref j from j-1 */
for (int j = 1; j < scc->num_objs; j++) {
- bridge_info = get_gc_bridge_info_for_object (bridge, scc->objs [j-1]);
- if (bridge_info != NULL && add_reference (bridge, env, scc->objs [j-1], bridge_info, scc->objs [j])) {
- mono_field_set_value (scc->objs [j-1], bridge_info->refs_added, &ref_val);
+ control_block = get_gc_control_block_for_object (bridge, scc->objs [j-1]);
+ if (control_block != NULL && add_reference (bridge, env, scc->objs [j-1], control_block, scc->objs [j])) {
+ control_block->refs_added = ref_val;
}
}
/* ref the first from the last */
if (scc->num_objs > 1) {
- bridge_info = get_gc_bridge_info_for_object (bridge, scc->objs [scc->num_objs-1]);
- if (bridge_info != NULL && add_reference (bridge, env, scc->objs [scc->num_objs-1], bridge_info, scc->objs [0])) {
- mono_field_set_value (scc->objs [scc->num_objs-1], bridge_info->refs_added, &ref_val);
+ control_block = get_gc_control_block_for_object (bridge, scc->objs [scc->num_objs-1]);
+ if (control_block != NULL && add_reference (bridge, env, scc->objs [scc->num_objs-1], control_block, scc->objs [0])) {
+ control_block->refs_added = ref_val;
}
}
}
/* add the cross scc refs */
for (int i = 0; i < num_xrefs; i++) {
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, sccs [xrefs [i].src_scc_index]->objs [0]);
- if (bridge_info != NULL && add_reference (bridge, env, sccs [xrefs [i].src_scc_index]->objs [0], bridge_info, sccs [xrefs [i].dst_scc_index]->objs [0])) {
- mono_field_set_value (sccs [xrefs [i].src_scc_index]->objs [0], bridge_info->refs_added, &ref_val);
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, sccs [xrefs [i].src_scc_index]->objs [0]);
+ if (control_block != NULL && add_reference (bridge, env, sccs [xrefs [i].src_scc_index]->objs [0], control_block, sccs [xrefs [i].dst_scc_index]->objs [0])) {
+ control_block->refs_added = ref_val;
}
}
@@ -1041,19 +1049,18 @@ gc_cleanup_after_java_collection (JavaInteropGCBridge *bridge, JNIEnv *env, int
sccs [i]->is_alive = 0;
for (int j = 0; j < sccs [i]->num_objs; j++) {
MonoObject *obj = sccs [i]->objs [j];
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (bridge, obj);
- if (bridge_info == NULL)
+
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (bridge, obj);
+ if (control_block == NULL)
continue;
- jobject jref;
- mono_field_get_value (obj, bridge_info->handle, &jref);
+ jobject jref = control_block->handle;
if (jref) {
alive++;
if (j > 0)
assert (sccs [i]->is_alive);
sccs [i]->is_alive = 1;
- int refs_added;
- mono_field_get_value (obj, bridge_info->refs_added, &refs_added);
+ int refs_added = control_block->refs_added;
if (refs_added) {
jmethodID clear_method_id = get_clear_references_method (bridge, env, jref);
if (clear_method_id) {
@@ -1201,13 +1208,12 @@ gc_bridge_class_kind (MonoClass *klass)
static mono_bool
gc_is_bridge_object (MonoObject *object)
{
- void *handle;
- MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (mono_bridge, object);
- if (bridge_info == NULL)
- return 0;
+ JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (mono_bridge, object);
+ if (control_block == NULL)
+ return 0;;
- mono_field_get_value (object, bridge_info->handle, &handle);
+ void *handle = control_block->handle;
if (handle == NULL) {
#if DEBUG
MonoClass *mclass = mono_object_get_class (object);
@@ -1279,6 +1285,46 @@ gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGC
free (thread_name);
}
+static void
+managed_gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
+{
+ if (mono_bridge->mark_cross_references == NULL) {
+ assert (!"mono_bridge->mark_cross_references is NULL; WE SHOULD NOT BE EXECUTING");
+ return;
+ }
+ int i;
+
+ Srij_MarkCrossReferences cross_references = {};
+
+ cross_references.ComponentsLen = (void*) (intptr_t) num_sccs;
+ cross_references.Components = (Srij_StronglyConnectedComponent*) calloc (num_sccs, sizeof (Srij_StronglyConnectedComponent));
+ for (i = 0; i < num_sccs; ++i) {
+ Srij_StronglyConnectedComponent *scc = &cross_references.Components [i];
+
+ scc->Count = (void*) (intptr_t) sccs [i]->num_objs;
+ scc->Context = (void**) calloc (sccs [i]->num_objs, sizeof (void*));
+ for (int j = 0; j < sccs [i]->num_objs; ++j) {
+ MonoObject *obj = sccs [i]->objs [j];
+ scc->Context [j] = get_gc_control_block_for_object (mono_bridge, obj);
+ }
+ }
+
+ cross_references.CrossReferencesLen = (void*) (intptr_t) num_xrefs;
+ cross_references.CrossReferences = (Srij_ComponentCrossReference*) calloc (num_xrefs, sizeof (Srij_ComponentCrossReference));
+ for (i = 0; i < num_xrefs; ++i) {
+ Srij_ComponentCrossReference *xref = &cross_references.CrossReferences [i];
+ xref->SourceGroupIndex = (void*) (intptr_t) xrefs [i].src_scc_index;
+ xref->DestinationGroupIndex = (void*) (intptr_t) xrefs [i].dst_scc_index;
+ }
+
+ mono_bridge->mark_cross_references (&cross_references);
+
+ for (i = 0; i < num_sccs; ++i) {
+ Srij_StronglyConnectedComponent *scc = &cross_references.Components [i];
+ sccs [i]->is_alive = scc->IsAlive;
+ }
+}
+
int
java_interop_gc_bridge_register_hooks (JavaInteropGCBridge *bridge, int weak_ref_kind)
{
@@ -1312,7 +1358,9 @@ java_interop_gc_bridge_register_hooks (JavaInteropGCBridge *bridge, int weak_ref
bridge_cbs.bridge_version = SGEN_BRIDGE_VERSION;
bridge_cbs.bridge_class_kind = gc_bridge_class_kind;
bridge_cbs.is_bridge_object = gc_is_bridge_object;
- bridge_cbs.cross_references = gc_cross_references;
+ bridge_cbs.cross_references = bridge->mark_cross_references
+ ? managed_gc_cross_references
+ : gc_cross_references;
mono_gc_register_bridge_callbacks (&bridge_cbs);
@@ -1328,3 +1376,24 @@ java_interop_gc_bridge_wait_for_bridge_processing (JavaInteropGCBridge *bridge)
mono_gc_wait_for_bridge_processing ();
return 0;
}
+
+int
+java_interop_gc_bridge_set_mark_cross_references (JavaInteropGCBridge *bridge, JavaInteropMarkCrossReferencesCallback markCrossReferences)
+{
+ if (bridge == NULL)
+ return -1;
+
+ bridge->mark_cross_references = markCrossReferences;
+
+ return 0;
+}
+
+int
+java_interop_gc_bridge_release_mark_cross_references_resources (JavaInteropGCBridge *bridge, Srij_MarkCrossReferences *crossReferences)
+{
+ if (bridge == NULL || crossReferences == NULL)
+ return -1;
+
+ // leak it…
+ return 0;
+}
diff --git a/src/java-interop/java-interop-gc-bridge.h b/src/java-interop/java-interop-gc-bridge.h
index 8c8444cb6..6715b33be 100644
--- a/src/java-interop/java-interop-gc-bridge.h
+++ b/src/java-interop/java-interop-gc-bridge.h
@@ -19,6 +19,26 @@ struct JavaInterop_System_RuntimeTypeHandle {
void *value;
};
+typedef struct Srij_ComponentCrossReference {
+ void *SourceGroupIndex;
+ void *DestinationGroupIndex;
+} Srij_ComponentCrossReference;
+
+typedef struct Srij_StronglyConnectedComponent {
+ int IsAlive;
+ void *Count;
+ void **Context;
+} Srij_StronglyConnectedComponent;
+
+typedef struct Srij_MarkCrossReferences {
+ void *ComponentsLen;
+ Srij_StronglyConnectedComponent *Components;
+ void* CrossReferencesLen;
+ Srij_ComponentCrossReference *CrossReferences;
+} Srij_MarkCrossReferences;
+
+typedef void (*JavaInteropMarkCrossReferencesCallback) (Srij_MarkCrossReferences *crossReferences);
+
JAVA_INTEROP_API JavaInteropGCBridge *java_interop_gc_bridge_get_current (void);
JAVA_INTEROP_API int java_interop_gc_bridge_set_current_once (JavaInteropGCBridge *bridge);
@@ -32,6 +52,10 @@ JAVA_INTEROP_API int java_interop_gc_bridge_add_current_a
JAVA_INTEROP_API int java_interop_gc_bridge_remove_current_app_domain (JavaInteropGCBridge *bridge);
JAVA_INTEROP_API int java_interop_gc_bridge_set_bridge_processing_field (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle, char *field_name);
+
+JAVA_INTEROP_API int java_interop_gc_bridge_set_mark_cross_references (JavaInteropGCBridge *bridge, JavaInteropMarkCrossReferencesCallback markCrossReferences);
+JAVA_INTEROP_API int java_interop_gc_bridge_release_mark_cross_references_resources (JavaInteropGCBridge *bridge, Srij_MarkCrossReferences *crossReferences);
+
JAVA_INTEROP_API int java_interop_gc_bridge_register_bridgeable_type (JavaInteropGCBridge *bridge, struct JavaInterop_System_RuntimeTypeHandle type_handle);
JAVA_INTEROP_API int java_interop_gc_bridge_enable (JavaInteropGCBridge *bridge, int enable);
diff --git a/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs b/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs
index f02bbc06b..896c1c9a6 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs
@@ -39,6 +39,30 @@ protected override bool SequenceEqual (IEnumerable a, IEnumerable b)
{
return JniMarshal.RecursiveEquals (a, b);
}
+
+ int beforeTestGrefCount;
+
+ [SetUp]
+ public void LogBeginCurrentTestGrefCount ()
+ {
+ beforeTestGrefCount = JniEnvironment.Runtime.GlobalReferenceCount;
+ JniEnvironment.Runtime.ObjectReferenceManager.WriteGlobalReferenceLine(
+ "{0}",
+ $"Begin {TestContext.CurrentContext.Test.FullName}; " +
+ $"GREFs={beforeTestGrefCount}; "
+ );
+ }
+
+ [TearDown]
+ public void LogEndCurrentTestToGrefCount ()
+ {
+ int afterTestGrefCount = JniEnvironment.Runtime.GlobalReferenceCount;
+ JniEnvironment.Runtime.ObjectReferenceManager.WriteGlobalReferenceLine(
+ "{0}",
+ $"End {TestContext.CurrentContext.Test.FullName}; " +
+ $"GREFs={afterTestGrefCount}; diff={afterTestGrefCount - beforeTestGrefCount}"
+ );
+ }
}
[TestFixture]
diff --git a/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs b/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs
index d90d5846f..33dac36fe 100644
--- a/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs
+++ b/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs
@@ -50,12 +50,12 @@ public void UnregisterFromRuntime ()
using (o = new JavaObject ()) {
l = o.PeerReference.NewLocalRef ();
Assert.AreEqual (JniObjectReferenceType.Global, o.PeerReference.Type);
- Assert.AreEqual (registeredCount+1, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count);
+ Assert.AreEqual (registeredCount+1, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count, "registeredCount+1 should match!");
Assert.IsNotNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (l));
Assert.AreNotSame (l, o.PeerReference);
Assert.AreSame (o, JniRuntime.CurrentRuntime.ValueManager.PeekValue (l));
}
- Assert.AreEqual (registeredCount, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count);
+ Assert.AreEqual (registeredCount, JniRuntime.CurrentRuntime.ValueManager.GetSurfacedPeers ().Count, "registeredCount should match!");
Assert.IsNull (JniRuntime.CurrentRuntime.ValueManager.PeekValue (l));
JniObjectReference.Dispose (ref l);
Assert.Throws (() => o.UnregisterFromRuntime ());