Skip to content

Commit 4287453

Browse files
filipnavaraVSadov
andauthored
[Mono] Implement eager finalization of WeakReference (#76173)
* [Mono] Implement eager finalization of WeakReference * Make the finalization really eager * Move the eager finalization a bit earlier - to sgen_finalize_in_range (PR suggestion) Co-authored-by: vsadov <8218165+VSadov@users.noreply.github.com>
1 parent f518c05 commit 4287453

File tree

8 files changed

+40
-20
lines changed

8 files changed

+40
-20
lines changed

src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ private T? Target
130130
}
131131
}
132132

133-
// eager finalization is NYI on Mono
134-
#if !MONO
135133
// Note: While WeakReference<T> is formally a finalizable type, the finalizer does not actually run.
136134
// Instead the instances are treated specially in GC when scanning for no longer strongly-reachable
137135
// finalizable objects.
@@ -142,21 +140,6 @@ private T? Target
142140
}
143141
#pragma warning restore CA1821 // Remove empty Finalizers
144142

145-
#else
146-
// Free all system resources associated with this reference.
147-
~WeakReference()
148-
{
149-
IntPtr handle = Handle;
150-
if (handle != default(IntPtr))
151-
{
152-
GCHandle.InternalFree(handle);
153-
154-
// keep the bit that indicates whether this reference was tracking resurrection
155-
_handleAndKind &= TracksResurrectionBit;
156-
}
157-
}
158-
#endif
159-
160143
#endif
161144
}
162145
}

src/libraries/System.Private.CoreLib/src/System/WeakReference.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,7 @@ public virtual object? Target
150150
// Unlike WeakReference<T> case, the instance could be of a derived type and
151151
// in such case it is finalized via a finalizer.
152152

153-
// eager finalization is NYI on Mono
154-
#if !MONO
155153
Debug.Assert(this.GetType() != typeof(WeakReference));
156-
#endif
157154

158155
IntPtr handle = Handle;
159156
if (handle != default(IntPtr))

src/mono/mono/metadata/class-internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,8 @@ typedef struct {
921921
MonoClass *generic_ienumerator_class;
922922
MonoClass *alc_class;
923923
MonoClass *appcontext_class;
924+
MonoClass *weakreference_class;
925+
MonoClass *generic_weakreference_class;
924926
} MonoDefaults;
925927

926928
/* If you need a MonoType, use one of the mono_get_*_type () functions in class-inlines.h */

src/mono/mono/metadata/domain.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ mono_init_internal (const char *root_domain_name)
290290
mono_defaults.alc_class = mono_class_get_assembly_load_context_class ();
291291
mono_defaults.appcontext_class = mono_class_try_load_from_name (mono_defaults.corlib, "System", "AppContext");
292292

293+
mono_defaults.weakreference_class = mono_class_try_load_from_name (
294+
mono_defaults.corlib, "System", "WeakReference");
295+
mono_defaults.generic_weakreference_class = mono_class_try_load_from_name (
296+
mono_defaults.corlib, "System", "WeakReference`1");
297+
293298
// in the past we got a filename as the root_domain_name so try to get the basename
294299
domain->friendly_name = g_path_get_basename (root_domain_name);
295300

src/mono/mono/metadata/object-internals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,11 @@ typedef struct {
651651
guint32 intType;
652652
} MonoClassInterfaceAttribute;
653653

654+
typedef struct {
655+
MonoObject object;
656+
gsize handleAndKind;
657+
} MonoWeakReference;
658+
654659
/* Safely access System.Delegate from native code */
655660
TYPED_HANDLE_DECL (MonoDelegate);
656661

src/mono/mono/metadata/sgen-mono.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,21 @@ is_finalization_aware (MonoObject *obj)
454454
return (vt->gc_bits & SGEN_GC_BIT_FINALIZER_AWARE) == SGEN_GC_BIT_FINALIZER_AWARE;
455455
}
456456

457+
gboolean
458+
sgen_client_object_finalize_eagerly (GCObject *obj)
459+
{
460+
if (obj->vtable->klass == mono_defaults.weakreference_class ||
461+
obj->vtable->klass == mono_defaults.generic_weakreference_class) {
462+
MonoWeakReference *wr = (MonoWeakReference*)obj;
463+
MonoGCHandle gc_handle = (MonoGCHandle)(wr->handleAndKind & ~(gsize)1);
464+
mono_gchandle_free_internal (gc_handle);
465+
wr->handleAndKind &= (gsize)1;
466+
return TRUE;
467+
}
468+
469+
return FALSE;
470+
}
471+
457472
void
458473
sgen_client_object_queued_for_finalization (GCObject *obj)
459474
{

src/mono/mono/sgen/sgen-client.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ gboolean sgen_client_object_is_array_fill (GCObject *o);
4646
*/
4747
gboolean sgen_client_object_has_critical_finalizer (GCObject *obj);
4848

49+
/*
50+
* Called when object is ready for finalization. Returns whether the object was finalized
51+
* eagerly. Otherwise `sgen_client_object_queued_for_finalization` is called.
52+
*/
53+
gboolean sgen_client_object_finalize_eagerly (GCObject *obj);
54+
4955
/*
5056
* Called after an object is enqueued for finalization. This is a very low-level callback.
5157
* It should almost certainly be a NOP.

src/mono/mono/sgen/sgen-fin-weak-hash.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ sgen_finalize_in_range (int generation, ScanCopyContext ctx)
188188
object = tagged_object_get_object (object);
189189
if (!sgen_major_collector.is_object_live (object)) {
190190
gboolean is_fin_ready = sgen_gc_is_object_ready_for_finalization (object);
191+
if (is_fin_ready && sgen_client_object_finalize_eagerly (object)) {
192+
/* just remove an eagerly finalized object */
193+
SGEN_HASH_TABLE_FOREACH_REMOVE (TRUE);
194+
195+
SGEN_LOG (5, "Eagerly finalized object: %p (%s) (was at %p)", object, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (object)), object);
196+
continue;
197+
}
191198
GCObject *copy = object;
192199
copy_func (&copy, queue);
193200
if (is_fin_ready) {

0 commit comments

Comments
 (0)