Skip to content

Commit 55632c3

Browse files
committed
[native, Mono.Android] Remove WeakReference support
Context: dotnet/java-interop#1255 Context: xamarin/monodroid@a5c5290 Context: https://issuetracker.google.com/issues/36986478 Context: https://github.com/dotnet/android/blob/b56d68fe2a2c2dffa47eb7e41ae08a00fda86367/Documentation/workflow/SystemProperties.md#debugmonowref Android did not support [JNI Weak Global References][0] until API-8 (Android 2.2). To allow Mono for Android applications to run on API-7 and earlier devices, while using JNI Weak Global References when possible (fewer GC allocations, better performance), the GC bridge supported two modes of operation: * `debug.mono.wref=jni`: Use JNI Weak Global References. * `debug.mono.wref=java`: Use [`java.lang.ref.WeakReference`][1]. With the exception of a ["minor" (lol) issue][2] in KitKat v4.4.2 (API-19) -- in which `JNIEnv::NewGlobalRef()` around a collected JNI Weak Global Reference would return a non-`NULL` value, which would result in app crashes; xamarin/monodroid@a5c52905 added a workaround to use the `WeakReference` backend on Android 4.4.2 -- the `debug.mono.wref=java` backend has not been used since *2014*. Apps *could* use [`@(AndroidEnvironment)`][3] to set `debug.mono.wref=java`, but there is no reason to do so (worse performance!), [nor has anyone done so on GitHub.com][4] (no matches for `debug.mono.wref` within files that would be used with `@(AndroidEnvironment)`). Cleanup src/native and src/Mono.Android, and *remove* support for the `debug.mono.wref=java` backend. [0]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#weak_global_references [1]: https://developer.android.com/reference/java/lang/ref/WeakReference [2]: https://issuetracker.google.com/issues/36986478 [3]: https://learn.microsoft.com/dotnet/android/building-apps/build-items#androidenvironment [4]: https://github.com/search?type=code&q=debug.mono.wref
1 parent b56d68f commit 55632c3

File tree

7 files changed

+5
-128
lines changed

7 files changed

+5
-128
lines changed

src/Microsoft.Android.Sdk.ILLink/PreserveLists/Java.Interop.xml

-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
<field name="handle" />
66
<field name="handle_type" />
77
<field name="refs_added" />
8-
<field name="weak_handle" />
98
</type>
109
<type fullname="Java.Interop.JavaException">
1110
<field name="handle" />
1211
<field name="handle_type" />
1312
<field name="refs_added" />
14-
<field name="weak_handle" />
1513
</type>
1614
</assembly>
1715
</linker>

src/Microsoft.Android.Sdk.ILLink/PreserveLists/Mono.Android.xml

-2
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,12 @@
3939
<field name="handle" />
4040
<field name="handle_type" />
4141
<field name="refs_added" />
42-
<field name="weak_handle" />
4342
<method name="SetHandleOnDeserialized" />
4443
</type>
4544
<type fullname="Java.Lang.Throwable">
4645
<field name="handle" />
4746
<field name="handle_type" />
4847
<field name="refs_added" />
49-
<field name="weak_handle" />
5048
</type>
5149
</assembly>
5250
</linker>

src/Mono.Android/Java.Lang/Object.cs

-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public partial class Object : IDisposable, IJavaObject, IJavaObjectEx
2121
{
2222
[NonSerialized] IntPtr key_handle;
2323
#pragma warning disable CS0649, CS0169, CS0414 // Suppress fields are never used warnings, these fields are used directly by monodroid-glue.cc
24-
[NonSerialized] IntPtr weak_handle;
2524
[NonSerialized] int refs_added;
2625
#pragma warning restore CS0649, CS0169, CS0414
2726
[NonSerialized] JObjectRefType handle_type;
@@ -117,9 +116,6 @@ public virtual JniPeerMembers JniPeerMembers {
117116
[EditorBrowsable (EditorBrowsableState.Never)]
118117
public IntPtr Handle {
119118
get {
120-
if (weak_handle != IntPtr.Zero)
121-
Logger.Log (LogLevel.Warn, "Mono.Android.dll", "Accessing object which is out for collection via original handle");
122-
123119
return handle;
124120
}
125121
}

src/Mono.Android/Java.Lang/Throwable.cs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public partial class Throwable : global::System.Exception, IJavaObject, IDisposa
2121
IntPtr key_handle;
2222
JObjectRefType handle_type;
2323
#pragma warning disable CS0649, CS0169, CS0414 // Suppress fields are never used warnings, these fields are used directly by monodroid-glue.cc
24-
IntPtr weak_handle;
2524
int refs_added;
2625
#pragma warning restore CS0649, CS0169, CS0414
2726

src/native/monodroid/monodroid-glue.cc

+3-5
Original file line numberDiff line numberDiff line change
@@ -781,17 +781,15 @@ MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJava
781781
info->handle = mono_class_get_field_from_name (info->klass, const_cast<char*> ("handle"));
782782
info->handle_type = mono_class_get_field_from_name (info->klass, const_cast<char*> ("handle_type"));
783783
info->refs_added = mono_class_get_field_from_name (info->klass, const_cast<char*> ("refs_added"));
784-
info->weak_handle = mono_class_get_field_from_name (info->klass, const_cast<char*> ("weak_handle"));
785-
if (info->klass == nullptr || info->handle == nullptr || info->handle_type == nullptr || info->refs_added == nullptr || info->weak_handle == nullptr) {
784+
if (info->klass == nullptr || info->handle == nullptr || info->handle_type == nullptr || info->refs_added == nullptr) {
786785
Helpers::abort_application (
787786
Util::monodroid_strdup_printf (
788-
"The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p weak_handle=%p",
787+
"The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p",
789788
type->_namespace,
790789
type->_typename,
791790
info->handle,
792791
info->handle_type,
793-
info->refs_added,
794-
info->weak_handle
792+
info->refs_added
795793
)
796794
);
797795
}

src/native/monodroid/osbridge.cc

+2-110
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ OSBridge::MonoJavaGCBridgeInfo OSBridge::empty_bridge_info = {
4747
nullptr,
4848
nullptr,
4949
nullptr,
50-
nullptr,
5150
nullptr
5251
};
5352

@@ -81,7 +80,6 @@ OSBridge::clear_mono_java_gc_bridge_info ()
8180
info->handle = nullptr;
8281
info->handle_type = nullptr;
8382
info->refs_added = nullptr;
84-
info->weak_handle = nullptr;
8583
}
8684
}
8785

@@ -443,67 +441,6 @@ OSBridge::monodroid_disable_gc_hooks ()
443441
gc_disabled = 1;
444442
}
445443

446-
mono_bool
447-
OSBridge::take_global_ref_2_1_compat (JNIEnv *env, MonoObject *obj)
448-
{
449-
jobject handle, weak;
450-
int type = JNIGlobalRefType;
451-
452-
MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj);
453-
if (bridge_info == nullptr)
454-
return 0;
455-
456-
mono_field_get_value (obj, bridge_info->weak_handle, &weak);
457-
handle = env->CallObjectMethod (weak, weakrefGet);
458-
if (gref_log) {
459-
fprintf (gref_log, "*try_take_global_2_1 obj=%p -> wref=%p handle=%p\n", obj, weak, handle);
460-
fflush (gref_log);
461-
}
462-
if (handle) {
463-
void* h = env->NewGlobalRef (handle);
464-
env->DeleteLocalRef (handle);
465-
handle = reinterpret_cast <jobject> (h);
466-
_monodroid_gref_log_new (weak, get_object_ref_type (env, weak),
467-
handle, get_object_ref_type (env, handle), "finalizer", gettid (), __PRETTY_FUNCTION__, 0);
468-
}
469-
_monodroid_weak_gref_delete (weak, get_object_ref_type (env, weak), "finalizer", gettid(), __PRETTY_FUNCTION__, 0);
470-
env->DeleteGlobalRef (weak);
471-
weak = nullptr;
472-
mono_field_set_value (obj, bridge_info->weak_handle, &weak);
473-
474-
mono_field_set_value (obj, bridge_info->handle, &handle);
475-
mono_field_set_value (obj, bridge_info->handle_type, &type);
476-
return handle != nullptr;
477-
}
478-
479-
mono_bool
480-
OSBridge::take_weak_global_ref_2_1_compat (JNIEnv *env, MonoObject *obj)
481-
{
482-
jobject weaklocal;
483-
jobject handle, weakglobal;
484-
485-
MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj);
486-
if (bridge_info == nullptr)
487-
return 0;
488-
489-
mono_field_get_value (obj, bridge_info->handle, &handle);
490-
weaklocal = env->NewObject (weakrefClass, weakrefCtor, handle);
491-
weakglobal = env->NewGlobalRef (weaklocal);
492-
env->DeleteLocalRef (weaklocal);
493-
if (gref_log) {
494-
fprintf (gref_log, "*take_weak_2_1 obj=%p -> wref=%p handle=%p\n", obj, weakglobal, handle);
495-
fflush (gref_log);
496-
}
497-
_monodroid_weak_gref_new (handle, get_object_ref_type (env, handle),
498-
weakglobal, get_object_ref_type (env, weakglobal), "finalizer", gettid (), __PRETTY_FUNCTION__, 0);
499-
500-
_monodroid_gref_log_delete (handle, get_object_ref_type (env, handle), "finalizer", gettid (), __PRETTY_FUNCTION__, 0);
501-
502-
env->DeleteGlobalRef (handle);
503-
mono_field_set_value (obj, bridge_info->weak_handle, &weakglobal);
504-
return 1;
505-
}
506-
507444
mono_bool
508445
OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj)
509446
{
@@ -1001,58 +938,13 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre
1001938
set_bridge_processing_field (domains_list, 0);
1002939
}
1003940

1004-
int
1005-
OSBridge::platform_supports_weak_refs (void)
1006-
{
1007-
char *value;
1008-
int api_level = 0;
1009-
1010-
if (AndroidSystem::monodroid_get_system_property ("ro.build.version.sdk", &value) > 0) {
1011-
api_level = atoi (value);
1012-
free (value);
1013-
}
1014-
1015-
if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_WREF_PROPERTY, &value) > 0) {
1016-
int use_weak_refs = 0;
1017-
if (!strcmp ("jni", value))
1018-
use_weak_refs = 1;
1019-
else if (!strcmp ("java", value))
1020-
use_weak_refs = 0;
1021-
else {
1022-
use_weak_refs = -1;
1023-
log_warn (LOG_GC, "Unsupported debug.mono.wref value '%s'; "
1024-
"supported values are 'jni' and 'java'. Ignoring...",
1025-
value);
1026-
}
1027-
free (value);
1028-
1029-
if (use_weak_refs && api_level < 8)
1030-
log_warn (LOG_GC, "Using JNI weak references instead of "
1031-
"java.lang.WeakReference on API-%i. Are you sure you want to do this? "
1032-
"The GC may be compromised.",
1033-
api_level);
1034-
1035-
if (use_weak_refs >= 0)
1036-
return use_weak_refs;
1037-
}
1038-
1039-
return 1;
1040-
}
1041-
1042941
void
1043942
OSBridge::register_gc_hooks (void)
1044943
{
1045944
MonoGCBridgeCallbacks bridge_cbs;
1046945

1047-
if (platform_supports_weak_refs ()) {
1048-
take_global_ref = &OSBridge::take_global_ref_jni;
1049-
take_weak_global_ref = &OSBridge::take_weak_global_ref_jni;
1050-
log_info (LOG_GC, "environment supports jni NewWeakGlobalRef");
1051-
} else {
1052-
take_global_ref = &OSBridge::take_global_ref_2_1_compat;
1053-
take_weak_global_ref = &OSBridge::take_weak_global_ref_2_1_compat;
1054-
log_info (LOG_GC, "environment does not support jni NewWeakGlobalRef");
1055-
}
946+
take_global_ref = &OSBridge::take_global_ref_jni;
947+
take_weak_global_ref = &OSBridge::take_weak_global_ref_jni;
1056948

1057949
bridge_cbs.bridge_version = SGEN_BRIDGE_VERSION;
1058950
bridge_cbs.bridge_class_kind = gc_bridge_class_kind_cb;

src/native/monodroid/osbridge.hh

-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ namespace xamarin::android::internal
4040
MonoClassField *handle;
4141
MonoClassField *handle_type;
4242
MonoClassField *refs_added;
43-
MonoClassField *weak_handle;
4443
};
4544

4645
// add_reference can work with objects which are either MonoObjects with java peers, or raw jobjects
@@ -134,8 +133,6 @@ namespace xamarin::android::internal
134133
int _monodroid_gref_dec ();
135134
char* _get_stack_trace_line_end (char *m);
136135
void _write_stack_trace (FILE *to, char *from, LogCategories = LOG_NONE);
137-
mono_bool take_global_ref_2_1_compat (JNIEnv *env, MonoObject *obj);
138-
mono_bool take_weak_global_ref_2_1_compat (JNIEnv *env, MonoObject *obj);
139136
mono_bool take_global_ref_jni (JNIEnv *env, MonoObject *obj);
140137
mono_bool take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj);
141138
mono_bool add_reference_jobject (JNIEnv *env, jobject handle, jobject reffed_handle);
@@ -152,7 +149,6 @@ namespace xamarin::android::internal
152149
void gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBridgeSCC **sccs);
153150
void java_gc (JNIEnv *env);
154151
void set_bridge_processing_field (MonodroidBridgeProcessingInfo *list, mono_bool value);
155-
int platform_supports_weak_refs ();
156152

157153
#if DEBUG
158154
char* describe_target (AddReferenceTarget target);

0 commit comments

Comments
 (0)