diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs index 648a89def9a11e..3d48ec61d811b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs @@ -130,8 +130,6 @@ private T? Target } } -// eager finalization is NYI on Mono -#if !MONO // Note: While WeakReference is formally a finalizable type, the finalizer does not actually run. // Instead the instances are treated specially in GC when scanning for no longer strongly-reachable // finalizable objects. @@ -142,21 +140,6 @@ private T? Target } #pragma warning restore CA1821 // Remove empty Finalizers -#else - // Free all system resources associated with this reference. - ~WeakReference() - { - IntPtr handle = Handle; - if (handle != default(IntPtr)) - { - GCHandle.InternalFree(handle); - - // keep the bit that indicates whether this reference was tracking resurrection - _handleAndKind &= TracksResurrectionBit; - } - } -#endif - #endif } } diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs index 77c83d8e8d3e29..2f56806b48c837 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs @@ -150,10 +150,7 @@ public virtual object? Target // Unlike WeakReference case, the instance could be of a derived type and // in such case it is finalized via a finalizer. -// eager finalization is NYI on Mono -#if !MONO Debug.Assert(this.GetType() != typeof(WeakReference)); -#endif IntPtr handle = Handle; if (handle != default(IntPtr)) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index d0158da21a67c6..68a21cdf9d4f3f 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -921,6 +921,8 @@ typedef struct { MonoClass *generic_ienumerator_class; MonoClass *alc_class; MonoClass *appcontext_class; + MonoClass *weakreference_class; + MonoClass *generic_weakreference_class; } MonoDefaults; /* If you need a MonoType, use one of the mono_get_*_type () functions in class-inlines.h */ diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c index ce643bd129c50b..7360b9e36e5733 100644 --- a/src/mono/mono/metadata/domain.c +++ b/src/mono/mono/metadata/domain.c @@ -290,6 +290,11 @@ mono_init_internal (const char *root_domain_name) mono_defaults.alc_class = mono_class_get_assembly_load_context_class (); mono_defaults.appcontext_class = mono_class_try_load_from_name (mono_defaults.corlib, "System", "AppContext"); + mono_defaults.weakreference_class = mono_class_try_load_from_name ( + mono_defaults.corlib, "System", "WeakReference"); + mono_defaults.generic_weakreference_class = mono_class_try_load_from_name ( + mono_defaults.corlib, "System", "WeakReference`1"); + // in the past we got a filename as the root_domain_name so try to get the basename domain->friendly_name = g_path_get_basename (root_domain_name); diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index d484a9edd9d059..7725b25946369f 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -651,6 +651,11 @@ typedef struct { guint32 intType; } MonoClassInterfaceAttribute; +typedef struct { + MonoObject object; + gsize handleAndKind; +} MonoWeakReference; + /* Safely access System.Delegate from native code */ TYPED_HANDLE_DECL (MonoDelegate); diff --git a/src/mono/mono/metadata/sgen-mono.c b/src/mono/mono/metadata/sgen-mono.c index 44dfc42f2d3ab6..373c8f886a50c9 100644 --- a/src/mono/mono/metadata/sgen-mono.c +++ b/src/mono/mono/metadata/sgen-mono.c @@ -454,6 +454,21 @@ is_finalization_aware (MonoObject *obj) return (vt->gc_bits & SGEN_GC_BIT_FINALIZER_AWARE) == SGEN_GC_BIT_FINALIZER_AWARE; } +gboolean +sgen_client_object_finalize_eagerly (GCObject *obj) +{ + if (obj->vtable->klass == mono_defaults.weakreference_class || + obj->vtable->klass == mono_defaults.generic_weakreference_class) { + MonoWeakReference *wr = (MonoWeakReference*)obj; + MonoGCHandle gc_handle = (MonoGCHandle)(wr->handleAndKind & ~(gsize)1); + mono_gchandle_free_internal (gc_handle); + wr->handleAndKind &= (gsize)1; + return TRUE; + } + + return FALSE; +} + void sgen_client_object_queued_for_finalization (GCObject *obj) { diff --git a/src/mono/mono/sgen/sgen-client.h b/src/mono/mono/sgen/sgen-client.h index f21ba5f2a30c3b..d4dfb4a39842c2 100644 --- a/src/mono/mono/sgen/sgen-client.h +++ b/src/mono/mono/sgen/sgen-client.h @@ -46,6 +46,12 @@ gboolean sgen_client_object_is_array_fill (GCObject *o); */ gboolean sgen_client_object_has_critical_finalizer (GCObject *obj); +/* + * Called when object is ready for finalization. Returns whether the object was finalized + * eagerly. Otherwise `sgen_client_object_queued_for_finalization` is called. + */ +gboolean sgen_client_object_finalize_eagerly (GCObject *obj); + /* * Called after an object is enqueued for finalization. This is a very low-level callback. * It should almost certainly be a NOP. diff --git a/src/mono/mono/sgen/sgen-fin-weak-hash.c b/src/mono/mono/sgen/sgen-fin-weak-hash.c index e1a85926950c10..b523c786164846 100644 --- a/src/mono/mono/sgen/sgen-fin-weak-hash.c +++ b/src/mono/mono/sgen/sgen-fin-weak-hash.c @@ -188,6 +188,13 @@ sgen_finalize_in_range (int generation, ScanCopyContext ctx) object = tagged_object_get_object (object); if (!sgen_major_collector.is_object_live (object)) { gboolean is_fin_ready = sgen_gc_is_object_ready_for_finalization (object); + if (is_fin_ready && sgen_client_object_finalize_eagerly (object)) { + /* just remove an eagerly finalized object */ + SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE); + + SGEN_LOG (5, "Eagerly finalized object: %p (%s) (was at %p)", object, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (object)), object); + continue; + } GCObject *copy = object; copy_func (©, queue); if (is_fin_ready) {