diff --git a/external/Java.Interop b/external/Java.Interop index 81a9015fc42..40d27ebf3e4 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit 81a9015fc4213c6be5425002bf6daa07cc249bf2 +Subproject commit 40d27ebf3e492e77bb04c111f8a257b82e4f41b0 diff --git a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Java.Interop.xml b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Java.Interop.xml index 7ee32570100..3140d548e73 100644 --- a/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Java.Interop.xml +++ b/src/Microsoft.Android.Sdk.ILLink/PreserveLists/Java.Interop.xml @@ -2,14 +2,10 @@ - - - + - - - + diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index d8c722f48f2..9cffb809d0b 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -793,22 +793,15 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks MonodroidRuntime::lookup_bridge_info (MonoClass *klass, const OSBridge::MonoJavaGCBridgeType *type, OSBridge::MonoJavaGCBridgeInfo *info) noexcept { info->klass = klass; - 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->key_handle = mono_class_get_field_from_name (info->klass, const_cast ("key_handle")); + info->jniObjectReferenceControlBlock = mono_class_get_field_from_name (info->klass, const_cast("jniObjectReferenceControlBlock")); - // key_handle is optional, as Java.Interop.JavaObject doesn't currently have it - if (info->klass == nullptr || info->handle == nullptr || info->handle_type == nullptr || info->refs_added == nullptr) { + if (info->klass == nullptr || info->jniObjectReferenceControlBlock == nullptr) { Helpers::abort_application ( - Util::monodroid_strdup_printf ( - "The type `%s.%s` is missing required instance fields! handle=%p handle_type=%p refs_added=%p key_handle=%p", + std::format ( + "The type `{}.{} is missing required instance fields! jniObjectReferenceControlBlock={:p}", type->_namespace, type->_typename, - info->handle, - info->handle_type, - info->refs_added, - info->key_handle + static_cast(info->jniObjectReferenceControlBlock) ) ); } diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index 919506d3fda..938236841eb 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -42,9 +42,6 @@ const uint32_t OSBridge::NUM_GC_BRIDGE_TYPES = NUM_XA_GC_BRIDGE_TYPES + NUM_J OSBridge::MonoJavaGCBridgeInfo OSBridge::mono_java_gc_bridge_info [NUM_GC_BRIDGE_TYPES]; OSBridge::MonoJavaGCBridgeInfo OSBridge::empty_bridge_info = { - nullptr, - nullptr, - nullptr, nullptr, nullptr }; @@ -76,9 +73,14 @@ OSBridge::clear_mono_java_gc_bridge_info () for (uint32_t c = 0; c < NUM_GC_BRIDGE_TYPES; c++) { MonoJavaGCBridgeInfo *info = &mono_java_gc_bridge_info [c]; info->klass = nullptr; - info->handle = nullptr; - info->handle_type = nullptr; - info->refs_added = nullptr; + auto control_block = reinterpret_cast(info->jniObjectReferenceControlBlock); + if (control_block == nullptr) [[unlikely]] { + continue; + } + control_block->handle = nullptr; + control_block->handle_type = 0; + control_block->weak_handle = nullptr; + control_block->refs_added = 0; } } @@ -102,6 +104,19 @@ OSBridge::get_gc_bridge_index (MonoClass *klass) : -1; } +OSBridge::JniObjectReferenceControlBlock* +OSBridge::get_gc_control_block_for_object (MonoObject *obj) +{ + MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); + if (bridge_info == nullptr) { + return nullptr; + } + + JniObjectReferenceControlBlock *control_block = nullptr; + mono_field_get_value (obj, bridge_info->jniObjectReferenceControlBlock, &control_block); + return control_block; +} + OSBridge::MonoJavaGCBridgeInfo * OSBridge::get_gc_bridge_info_for_class (MonoClass *klass) { @@ -456,15 +471,15 @@ OSBridge::monodroid_disable_gc_hooks () mono_bool OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) { - jobject handle, weak; int type = JNIGlobalRefType; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { return 0; + } - mono_field_get_value (obj, bridge_info->handle, &weak); - handle = env->NewGlobalRef (weak); + jobject weak = control_block->handle; + jobject handle = env->NewGlobalRef (weak); if (gref_log) { fprintf (gref_log, "*try_take_global obj=%p -> wref=%p handle=%p\n", obj, weak, handle); fflush (gref_log); @@ -476,8 +491,8 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) " at [[gc:take_global_ref_jni]]", 0); } else if (Logger::gc_spew_enabled ()) [[unlikely]] { void *key_handle = nullptr; - if (bridge_info->key_handle) { - mono_field_get_value (obj, bridge_info->key_handle, &key_handle); + if (control_block->weak_handle != nullptr) { + key_handle = control_block->weak_handle; } MonoClass *klass = mono_object_get_class (obj); @@ -491,8 +506,8 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) free (message); } - mono_field_set_value (obj, bridge_info->handle, &handle); - mono_field_set_value (obj, bridge_info->handle_type, &type); + control_block->handle = handle; + control_block->handle_type = type; _monodroid_weak_gref_delete (weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_global_ref_jni]]", 0); @@ -504,26 +519,26 @@ OSBridge::take_global_ref_jni (JNIEnv *env, MonoObject *obj) mono_bool OSBridge::take_weak_global_ref_jni (JNIEnv *env, MonoObject *obj) { - jobject handle, weak; int type = JNIWeakGlobalRefType; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { return 0; + } - mono_field_get_value (obj, bridge_info->handle, &handle); + jobject handle = control_block->handle; if (gref_log) { fprintf (gref_log, "*take_weak obj=%p; handle=%p\n", obj, handle); fflush (gref_log); } - weak = env->NewWeakGlobalRef (handle); + jobject weak = env->NewWeakGlobalRef (handle); _monodroid_weak_gref_new (handle, get_object_ref_type (env, handle), weak, get_object_ref_type (env, weak), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); - mono_field_set_value (obj, bridge_info->handle, &weak); - mono_field_set_value (obj, bridge_info->handle_type, &type); + control_block->handle = weak; + control_block->handle_type = type; _monodroid_gref_log_delete (handle, get_object_ref_type (env, handle), "finalizer", gettid (), " at [[gc:take_weak_global_ref_jni]]", 0); @@ -558,14 +573,22 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) mono_bool OSBridge::gc_is_bridge_object (MonoObject *object) { - void *handle; + if (object == nullptr) [[unlikely]] { + log_debug (LOG_GC, "gc_is_bridge_object was passed a NULL object pointer"); + return FALSE; + } - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (object); - if (bridge_info == nullptr) - return 0; + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (object); + if (control_block == nullptr) { + return FALSE; + } - mono_field_get_value (object, bridge_info->handle, &handle); - if (handle == nullptr) { + if (control_block->handle == nullptr) { + log_warn (LOG_GC, "gc_is_bridge_object: control block's handle is NULL"); + return FALSE; + } + + if (control_block->handle == nullptr) { #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, @@ -574,10 +597,10 @@ OSBridge::gc_is_bridge_object (MonoObject *object) optional_string (mono_class_get_name (mclass)) ); #endif - return 0; + return FALSE; } - return 1; + return TRUE; } // Add a reference from an IGCUserPeer jobject to another jobject @@ -603,11 +626,17 @@ OSBridge::add_reference_jobject (JNIEnv *env, jobject handle, jobject reffed_han mono_bool OSBridge::load_reference_target (OSBridge::AddReferenceTarget target, OSBridge::MonoJavaGCBridgeInfo** bridge_info, jobject *handle) { + if (handle == nullptr) [[unlikely]] { + return FALSE; + } + if (target.is_mono_object) { - *bridge_info = get_gc_bridge_info_for_object (target.obj); - if (!*bridge_info) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) { return FALSE; - mono_field_get_value (target.obj, (*bridge_info)->handle, handle); + } + + *handle = control_block->handle; } else { *handle = target.jobj; } @@ -648,8 +677,11 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri // Flag MonoObjects so they can be cleared in gc_cleanup_after_java_collection. // Java temporaries do not need this because the entire GCUserPeer is discarded. if (success && target.is_mono_object) { - int ref_val = 1; - mono_field_set_value (target.obj, bridge_info->refs_added, &ref_val); + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (target.obj); + if (control_block == nullptr) { + return FALSE; + } + control_block->refs_added = 1; } #if DEBUG @@ -867,15 +899,15 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri sccs [i]->is_alive = 0; for (j = 0; j < sccs [i]->num_objs; j++) { - MonoJavaGCBridgeInfo *bridge_info; - obj = sccs [i]->objs [j]; - bridge_info = get_gc_bridge_info_for_object (obj); - if (bridge_info == nullptr) + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); + if (control_block == nullptr) { continue; - mono_field_get_value (obj, bridge_info->handle, &jref); - if (jref) { + } + + jref = control_block->handle; + if (jref != nullptr) { alive++; if (j > 0) { abort_unless ( @@ -884,8 +916,8 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri ); } sccs [i]->is_alive = 1; - mono_field_get_value (obj, bridge_info->refs_added, &refs_added); - if (refs_added) { + refs_added = control_block->refs_added; + if (refs_added != 0) { jclass java_class = env->GetObjectClass (jref); clear_method_id = env->GetMethodID (java_class, "monodroidClearReferences", "()V"); env->DeleteLocalRef (java_class); @@ -951,13 +983,13 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; - MonoJavaGCBridgeInfo *bridge_info = get_gc_bridge_info_for_object (obj); + JniObjectReferenceControlBlock *control_block = get_gc_control_block_for_object (obj); jobject handle = 0; void *key_handle = nullptr; - if (bridge_info != nullptr) { - mono_field_get_value (obj, bridge_info->handle, &handle); - if (bridge_info->key_handle != nullptr) { - mono_field_get_value (obj, bridge_info->key_handle, &key_handle); + if (control_block != nullptr) { + handle = control_block->handle; + if (control_block->weak_handle != nullptr) { + key_handle = control_block->weak_handle; } } MonoClass *klass = mono_object_get_class (obj); diff --git a/src/native/mono/monodroid/osbridge.hh b/src/native/mono/monodroid/osbridge.hh index 46f4af69ef8..f439a57aedd 100644 --- a/src/native/mono/monodroid/osbridge.hh +++ b/src/native/mono/monodroid/osbridge.hh @@ -37,10 +37,15 @@ namespace xamarin::android::internal struct MonoJavaGCBridgeInfo { MonoClass *klass; - MonoClassField *handle; - MonoClassField *handle_type; - MonoClassField *refs_added; - MonoClassField *key_handle; + MonoClassField *jniObjectReferenceControlBlock; + }; + + struct JniObjectReferenceControlBlock + { + jobject handle; + int handle_type; + jobject weak_handle; + int refs_added; }; // add_reference can work with objects which are either MonoObjects with java peers, or raw jobjects @@ -127,6 +132,7 @@ namespace xamarin::android::internal private: int get_gc_bridge_index (MonoClass *klass); + JniObjectReferenceControlBlock* get_gc_control_block_for_object (MonoObject *obj); MonoJavaGCBridgeInfo* get_gc_bridge_info_for_class (MonoClass *klass); MonoJavaGCBridgeInfo* get_gc_bridge_info_for_object (MonoObject *object); char get_object_ref_type (JNIEnv *env, void *handle);