Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mono] Implement eager finalization of WeakReference #76173

Merged
merged 3 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ private T? Target
}
}

// eager finalization is NYI on Mono
#if !MONO
// Note: While WeakReference<T> 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.
Expand All @@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,7 @@ public virtual object? Target
// Unlike WeakReference<T> 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))
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,8 @@ typedef struct {
MonoClass *generic_ienumerator_class;
MonoClass *alc_class;
MonoClass *appcontext_class;
MonoClass *weakreference_class;
MonoClass *generic_weakreference_class;
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
} MonoDefaults;

/* If you need a MonoType, use one of the mono_get_*_type () functions in class-inlines.h */
Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/metadata/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
15 changes: 15 additions & 0 deletions src/mono/mono/metadata/sgen-mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 6 additions & 0 deletions src/mono/mono/sgen/sgen-client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 5 additions & 3 deletions src/mono/mono/sgen/sgen-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2819,11 +2819,13 @@ sgen_gc_is_object_ready_for_finalization (GCObject *object)
void
sgen_queue_finalization_entry (GCObject *obj)
{
gboolean critical = sgen_client_object_has_critical_finalizer (obj);
if (!sgen_client_object_finalize_eagerly (obj)) {
gboolean critical = sgen_client_object_has_critical_finalizer (obj);

sgen_pointer_queue_add (critical ? &critical_fin_queue : &fin_ready_queue, obj);
sgen_pointer_queue_add (critical ? &critical_fin_queue : &fin_ready_queue, obj);

sgen_client_object_queued_for_finalization (obj);
sgen_client_object_queued_for_finalization (obj);
}
}

gboolean
Expand Down