From b7da99d3322adeff839222adda1e5b607b9a02ba Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sun, 10 Aug 2025 13:11:27 -0700
Subject: [PATCH 01/11] Implement UnhandledException hook for finalizers in
Mono.
---
.../src/ILLink/ILLink.Descriptors.xml | 2 ++
.../src/System/Object.Mono.cs | 14 ++++++++++++++
src/mono/mono/metadata/gc.c | 7 ++++---
src/mono/mono/mini/aot-compiler.c | 2 +-
src/tests/issues.targets | 4 ++--
5 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
index 7ddd23d78de8ed..10aa896f1e06c0 100644
--- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
+++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
@@ -276,6 +276,8 @@
+
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index 582a55c7c4dfd7..06210a0dd2c2d9 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
namespace System
{
@@ -13,5 +14,18 @@ public partial class Object
[MethodImplAttribute(MethodImplOptions.InternalCall)]
protected extern object MemberwiseClone();
+ [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
+ private static extern void CallFinalize(object o);
+ private void GuardedFinalize()
+ {
+ try
+ {
+ CallFinalize(this);
+ }
+ catch (Exception ex) when (ExceptionHandling.IsHandledByGlobalHandler(ex))
+ {
+ // the handler returned "true" means the exception is now "handled" and we should continue.
+ }
+ }
}
}
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 9c49d2803cd95a..2a9cc586d48237 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -291,9 +291,10 @@ mono_gc_run_finalize (void *obj, void *data)
#ifndef HOST_WASM
if (!finalize_runtime_invoke) {
- MonoMethod *finalize_method = mono_class_get_method_from_name_checked (mono_defaults.object_class, "Finalize", 0, 0, error);
+ MonoMethod *finalize_method = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
+
mono_error_assert_ok (error);
- MonoMethod *invoke = mono_marshal_get_runtime_invoke (finalize_method, TRUE);
+ MonoMethod *invoke = mono_marshal_get_runtime_invoke_full (finalize_method, FALSE, TRUE);
finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
mono_error_assert_ok (error); /* expect this not to fail */
@@ -316,7 +317,7 @@ mono_gc_run_finalize (void *obj, void *data)
MONO_PROFILER_RAISE (gc_finalizing_object, (o));
#ifdef HOST_WASM
- MonoMethod* finalizer = mono_class_get_finalizer (o->vtable->klass);
+ MonoMethod* finalizer = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
if (finalizer) { // null finalizers work fine when using the vcall invoke as Object has an empty one
gpointer params [1];
params [0] = NULL;
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 033ef0d96b94b3..862e7394b2ef48 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "Finalize", 0, 0), TRUE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 591eb79f0fd68e..030a43941214f6 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -1732,8 +1732,8 @@
https://github.com/dotnet/runtime/issues/98628
-
- NYI on Mono
+
+ Test issue. The test relies on overriding the process return code.
From 912699d8de75712ffb0164a787e02678576ce12e Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sun, 10 Aug 2025 19:22:26 -0700
Subject: [PATCH 02/11] Cache the finalize method on wasm
---
src/mono/mono/metadata/gc.c | 19 ++++++++++---------
src/tests/issues.targets | 5 ++++-
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 2a9cc586d48237..f5385d0b826d01 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -81,6 +81,8 @@ static gboolean finalizer_thread_exited;
static MonoCoopCond exited_cond;
static MonoInternalThread *gc_thread;
+
+static MonoMethod *finalize_method;
#ifndef HOST_WASM
static RuntimeInvokeFunction finalize_runtime_invoke;
#endif
@@ -289,11 +291,13 @@ mono_gc_run_finalize (void *obj, void *data)
if (mono_log_finalizers)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o);
+ if (!finalize_method) {
+ finalize_method = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
+ mono_error_assert_ok (error);
+ }
+
#ifndef HOST_WASM
if (!finalize_runtime_invoke) {
- MonoMethod *finalize_method = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
-
- mono_error_assert_ok (error);
MonoMethod *invoke = mono_marshal_get_runtime_invoke_full (finalize_method, FALSE, TRUE);
finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
@@ -317,12 +321,9 @@ mono_gc_run_finalize (void *obj, void *data)
MONO_PROFILER_RAISE (gc_finalizing_object, (o));
#ifdef HOST_WASM
- MonoMethod* finalizer = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
- if (finalizer) { // null finalizers work fine when using the vcall invoke as Object has an empty one
- gpointer params [1];
- params [0] = NULL;
- mono_runtime_try_invoke (finalizer, o, params, &exc, error);
- }
+ gpointer params [1];
+ params [0] = NULL;
+ mono_runtime_try_invoke (finalize_method, o, params, &exc, error);
#else
runtime_invoke (o, NULL, &exc, NULL);
#endif
diff --git a/src/tests/issues.targets b/src/tests/issues.targets
index 030a43941214f6..53cdc97de4306e 100644
--- a/src/tests/issues.targets
+++ b/src/tests/issues.targets
@@ -1732,8 +1732,11 @@
https://github.com/dotnet/runtime/issues/98628
+
+ https://github.com/dotnet/runtime/issues/47624
+
- Test issue. The test relies on overriding the process return code.
+ Test issue. The test relies on overriding the process return code.
From 4e4503bebceff4e3fd2dc092cf3c14b2e32e0840 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Thu, 14 Aug 2025 08:02:03 -0700
Subject: [PATCH 03/11] Precompile invoke helper for GuardedFinalize
---
src/mono/mono/mini/aot-compiler.c | 2 +-
src/mono/mono/mini/mini-runtime.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 862e7394b2ef48..fc53de6d315f8c 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE));
+ add_method (acfg, mono_marshal_get_runtime_invoke_full (get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE, TRUE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c
index ddb1bfb6201bc2..05e8218926c6fe 100644
--- a/src/mono/mono/mini/mini-runtime.c
+++ b/src/mono/mono/mini/mini-runtime.c
@@ -5363,8 +5363,8 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
mono_error_cleanup (error); /* FIXME don't swallow the error */
continue;
}
- if (strcmp (method->name, "Finalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ if (strcmp (method->name, "GuardedFinalize") == 0) {
+ invoke = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
mono_compile_method_checked (invoke, error);
mono_error_assert_ok (error);
}
From 6fde69f42fe122bd1f6a1f9e4381d7be63772e2d Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Thu, 14 Aug 2025 14:34:42 -0700
Subject: [PATCH 04/11] only check for GuardedFinalize in corlib
---
src/mono/mono/mini/mini-runtime.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c
index 05e8218926c6fe..73b1226fbb4683 100644
--- a/src/mono/mono/mini/mini-runtime.c
+++ b/src/mono/mono/mini/mini-runtime.c
@@ -5363,10 +5363,12 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
mono_error_cleanup (error); /* FIXME don't swallow the error */
continue;
}
- if (strcmp (method->name, "GuardedFinalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
- mono_compile_method_checked (invoke, error);
- mono_error_assert_ok (error);
+ if (mono_is_corlib_image (image)) {
+ if (strcmp (method->name, "GuardedFinalize") == 0) {
+ invoke = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
+ mono_compile_method_checked (invoke, error);
+ mono_error_assert_ok (error);
+ }
}
}
From 7fa39cb6cbc53ff0841e7896a6f417a2d7c87fde Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Fri, 15 Aug 2025 19:18:45 -0700
Subject: [PATCH 05/11] make GuardedFinalize virtual
---
.../System.Private.CoreLib/src/System/Object.Mono.cs | 2 +-
src/mono/mono/metadata/gc.c | 2 +-
src/mono/mono/mini/aot-compiler.c | 2 +-
src/mono/mono/mini/mini-runtime.c | 10 ++++------
4 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index 06210a0dd2c2d9..e658c927e45c37 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -16,7 +16,7 @@ public partial class Object
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
private static extern void CallFinalize(object o);
- private void GuardedFinalize()
+ internal virtual void GuardedFinalize()
{
try
{
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index f5385d0b826d01..900c0af1faff4d 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -298,7 +298,7 @@ mono_gc_run_finalize (void *obj, void *data)
#ifndef HOST_WASM
if (!finalize_runtime_invoke) {
- MonoMethod *invoke = mono_marshal_get_runtime_invoke_full (finalize_method, FALSE, TRUE);
+ MonoMethod *invoke = mono_marshal_get_runtime_invoke (finalize_method, TRUE);
finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
mono_error_assert_ok (error); /* expect this not to fail */
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index fc53de6d315f8c..f809a9ca672a16 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, mono_marshal_get_runtime_invoke_full (get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE, TRUE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), TRUE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c
index 73b1226fbb4683..468534bc16ba41 100644
--- a/src/mono/mono/mini/mini-runtime.c
+++ b/src/mono/mono/mini/mini-runtime.c
@@ -5363,12 +5363,10 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
mono_error_cleanup (error); /* FIXME don't swallow the error */
continue;
}
- if (mono_is_corlib_image (image)) {
- if (strcmp (method->name, "GuardedFinalize") == 0) {
- invoke = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
- mono_compile_method_checked (invoke, error);
- mono_error_assert_ok (error);
- }
+ if (strcmp (method->name, "GuardedFinalize") == 0) {
+ invoke = mono_marshal_get_runtime_invoke (method, FALSE);
+ mono_compile_method_checked (invoke, error);
+ mono_error_assert_ok (error);
}
}
From f7b84463d6407ee2400e13f27a149e6dddf45410 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 16 Aug 2025 16:38:37 -0700
Subject: [PATCH 06/11] use mono_runtime_try_invoke, since we can wih instance
methods
---
.../src/System/Object.Mono.cs | 2 +-
src/mono/mono/metadata/gc.c | 19 ++++++++++++-------
src/mono/mono/mini/aot-compiler.c | 2 +-
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index e658c927e45c37..376a9ad2915f24 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -16,7 +16,7 @@ public partial class Object
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
private static extern void CallFinalize(object o);
- internal virtual void GuardedFinalize()
+ internal void GuardedFinalize()
{
try
{
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 900c0af1faff4d..9cf0320a6f11e3 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -297,14 +297,14 @@ mono_gc_run_finalize (void *obj, void *data)
}
#ifndef HOST_WASM
- if (!finalize_runtime_invoke) {
- MonoMethod *invoke = mono_marshal_get_runtime_invoke (finalize_method, TRUE);
+ //if (!finalize_runtime_invoke) {
+ // MonoMethod *invoke = mono_marshal_get_runtime_invoke (finalize_method, TRUE);
- finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
- mono_error_assert_ok (error); /* expect this not to fail */
- }
+ // finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
+ // mono_error_assert_ok (error); /* expect this not to fail */
+ //}
- RuntimeInvokeFunction runtime_invoke = finalize_runtime_invoke;
+ //RuntimeInvokeFunction runtime_invoke = finalize_runtime_invoke;
#endif
mono_runtime_class_init_full (o->vtable, error);
@@ -325,7 +325,12 @@ mono_gc_run_finalize (void *obj, void *data)
params [0] = NULL;
mono_runtime_try_invoke (finalize_method, o, params, &exc, error);
#else
- runtime_invoke (o, NULL, &exc, NULL);
+ // runtime_invoke (o, NULL, &exc, NULL);
+
+ gpointer params [1];
+ params [0] = NULL;
+ mono_runtime_try_invoke (finalize_method, o, params, &exc, error);
+
#endif
MONO_PROFILER_RAISE (gc_finalized_object, (o));
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index f809a9ca672a16..862e7394b2ef48 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), TRUE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
From 936bf4ea1c4e186856e0865b21e148b6b1916b4f Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 16 Aug 2025 16:52:28 -0700
Subject: [PATCH 07/11] comment out unused
---
src/mono/mono/metadata/gc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 9cf0320a6f11e3..dcfc63c750e5a7 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -84,7 +84,7 @@ static MonoInternalThread *gc_thread;
static MonoMethod *finalize_method;
#ifndef HOST_WASM
-static RuntimeInvokeFunction finalize_runtime_invoke;
+// static RuntimeInvokeFunction finalize_runtime_invoke;
#endif
/*
From 5ce38921eff6e3794374acb8df853f0c4bee66b8 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 16 Aug 2025 19:47:57 -0700
Subject: [PATCH 08/11] Move GuardedFinalize to a helper class
---
.../System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml | 4 ++++
src/mono/System.Private.CoreLib/src/System/Object.Mono.cs | 5 ++++-
src/mono/mono/metadata/class-internals.h | 1 +
src/mono/mono/metadata/domain.c | 3 +++
src/mono/mono/metadata/gc.c | 2 +-
src/mono/mono/mini/aot-compiler.c | 2 +-
6 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
index 10aa896f1e06c0..daf036ea072cdb 100644
--- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
+++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
@@ -276,6 +276,10 @@
+
+
+
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index 376a9ad2915f24..5039bb58bcd23e 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -13,10 +13,13 @@ public partial class Object
[MethodImplAttribute(MethodImplOptions.InternalCall)]
protected extern object MemberwiseClone();
+ }
+ internal sealed class FinalizerHelper
+ {
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
private static extern void CallFinalize(object o);
- internal void GuardedFinalize()
+ private void GuardedFinalize()
{
try
{
diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h
index 5fa79bcca9c6e7..d73381c97c0e5a 100644
--- a/src/mono/mono/metadata/class-internals.h
+++ b/src/mono/mono/metadata/class-internals.h
@@ -857,6 +857,7 @@ mono_generic_param_get_base_type (MonoClass *klass);
typedef struct {
MonoImage *corlib;
MonoClass *object_class;
+ MonoClass *finalizer_class;
MonoClass *object_class_array; // used via token pasting in mono_array_class_get_cached
MonoClass *byte_class;
MonoClass *void_class;
diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c
index 967e33f28df61c..259f800ade1212 100644
--- a/src/mono/mono/metadata/domain.c
+++ b/src/mono/mono/metadata/domain.c
@@ -154,6 +154,9 @@ mono_init_internal (const char *root_domain_name)
mono_defaults.object_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Object");
+ mono_defaults.finalizer_class = mono_class_load_from_name (
+ mono_defaults.corlib, "System", "FinalizerHelper");
+
mono_defaults.void_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Void");
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index dcfc63c750e5a7..8d0e50fecd48a8 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -292,7 +292,7 @@ mono_gc_run_finalize (void *obj, void *data)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o);
if (!finalize_method) {
- finalize_method = mono_class_get_method_from_name_checked (mono_defaults.object_class, "GuardedFinalize", 0, 0, error);
+ finalize_method = mono_class_get_method_from_name_checked (mono_defaults.finalizer_class, "GuardedFinalize", 0, 0, error);
mono_error_assert_ok (error);
}
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 862e7394b2ef48..85f8764b075f16 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.object_class, "GuardedFinalize", 0, 0), FALSE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.finalizer_class, "GuardedFinalize", 0, 0), FALSE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
From c1cc2b913b8f95fff9e3639c163cd4c409523dcb Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sat, 16 Aug 2025 23:51:23 -0700
Subject: [PATCH 09/11] make it static
---
.../System.Private.CoreLib/src/System/Object.Mono.cs | 4 ++--
src/mono/mono/metadata/gc.c | 10 +++++-----
src/mono/mono/mini/aot-compiler.c | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index 5039bb58bcd23e..b124ef01534424 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -19,11 +19,11 @@ internal sealed class FinalizerHelper
{
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
private static extern void CallFinalize(object o);
- private void GuardedFinalize()
+ private static void GuardedFinalize(object o)
{
try
{
- CallFinalize(this);
+ CallFinalize(o);
}
catch (Exception ex) when (ExceptionHandling.IsHandledByGlobalHandler(ex))
{
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 8d0e50fecd48a8..59b7e58b12a7fa 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -292,7 +292,7 @@ mono_gc_run_finalize (void *obj, void *data)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o);
if (!finalize_method) {
- finalize_method = mono_class_get_method_from_name_checked (mono_defaults.finalizer_class, "GuardedFinalize", 0, 0, error);
+ finalize_method = mono_class_get_method_from_name_checked (mono_defaults.finalizer_class, "GuardedFinalize", 1, 0, error);
mono_error_assert_ok (error);
}
@@ -322,14 +322,14 @@ mono_gc_run_finalize (void *obj, void *data)
#ifdef HOST_WASM
gpointer params [1];
- params [0] = NULL;
- mono_runtime_try_invoke (finalize_method, o, params, &exc, error);
+ params [0] = o;
+ mono_runtime_try_invoke (finalize_method, NULL, params, &exc, error);
#else
// runtime_invoke (o, NULL, &exc, NULL);
gpointer params [1];
- params [0] = NULL;
- mono_runtime_try_invoke (finalize_method, o, params, &exc, error);
+ params [0] = o;
+ mono_runtime_try_invoke (finalize_method, NULL, params, &exc, error);
#endif
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 85f8764b075f16..3116aa1517173d 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.finalizer_class, "GuardedFinalize", 0, 0), FALSE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.finalizer_class, "GuardedFinalize", 1, 0), FALSE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
From 11b41d33939832dd07e95fa5a0d59343a0ab2d32 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sun, 17 Aug 2025 10:23:54 -0700
Subject: [PATCH 10/11] some cleanup
---
.../src/ILLink/ILLink.Descriptors.xml | 4 +--
.../src/System/GC.Mono.cs | 15 ++++++++
.../src/System/Object.Mono.cs | 17 ---------
src/mono/mono/metadata/class-internals.h | 2 +-
src/mono/mono/metadata/domain.c | 6 ++--
src/mono/mono/metadata/gc.c | 35 +++----------------
src/mono/mono/mini/aot-compiler.c | 2 +-
7 files changed, 26 insertions(+), 55 deletions(-)
diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
index daf036ea072cdb..2e8bace4a47d8b 100644
--- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
+++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
@@ -278,8 +278,8 @@
-
-
+
+
diff --git a/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs b/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs
index 21eba8223fd0f9..77a4ac8b75d107 100644
--- a/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/GC.Mono.cs
@@ -4,6 +4,7 @@
using System.Diagnostics.Tracing;
using System.Runtime;
using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
namespace System
{
@@ -149,6 +150,20 @@ public static void ReRegisterForFinalize(object obj)
_ReRegisterForFinalize(obj);
}
+ [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
+ private static extern void CallFinalize(object o);
+ private static void GuardedFinalize(object o)
+ {
+ try
+ {
+ CallFinalize(o);
+ }
+ catch (Exception ex) when (ExceptionHandling.IsHandledByGlobalHandler(ex))
+ {
+ // the handler returned "true" means the exception is now "handled" and we should continue.
+ }
+ }
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern long GetTotalMemory(bool forceFullCollection);
diff --git a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
index b124ef01534424..582a55c7c4dfd7 100644
--- a/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Object.Mono.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
-using System.Runtime.ExceptionServices;
namespace System
{
@@ -13,22 +12,6 @@ public partial class Object
[MethodImplAttribute(MethodImplOptions.InternalCall)]
protected extern object MemberwiseClone();
- }
- internal sealed class FinalizerHelper
- {
- [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(Finalize))]
- private static extern void CallFinalize(object o);
- private static void GuardedFinalize(object o)
- {
- try
- {
- CallFinalize(o);
- }
- catch (Exception ex) when (ExceptionHandling.IsHandledByGlobalHandler(ex))
- {
- // the handler returned "true" means the exception is now "handled" and we should continue.
- }
- }
}
}
diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h
index d73381c97c0e5a..ba56a62ad6b818 100644
--- a/src/mono/mono/metadata/class-internals.h
+++ b/src/mono/mono/metadata/class-internals.h
@@ -857,7 +857,6 @@ mono_generic_param_get_base_type (MonoClass *klass);
typedef struct {
MonoImage *corlib;
MonoClass *object_class;
- MonoClass *finalizer_class;
MonoClass *object_class_array; // used via token pasting in mono_array_class_get_cached
MonoClass *byte_class;
MonoClass *void_class;
@@ -890,6 +889,7 @@ typedef struct {
MonoClass *threadabortexception_class;
MonoClass *thread_class;
MonoClass *internal_thread_class;
+ MonoClass *gc_class;
MonoClass *autoreleasepool_class;
MonoClass *mono_method_message_class;
MonoClass *field_info_class;
diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c
index 259f800ade1212..13bb7a408564f7 100644
--- a/src/mono/mono/metadata/domain.c
+++ b/src/mono/mono/metadata/domain.c
@@ -154,9 +154,6 @@ mono_init_internal (const char *root_domain_name)
mono_defaults.object_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Object");
- mono_defaults.finalizer_class = mono_class_load_from_name (
- mono_defaults.corlib, "System", "FinalizerHelper");
-
mono_defaults.void_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Void");
@@ -241,6 +238,9 @@ mono_init_internal (const char *root_domain_name)
/* There is only one thread class */
mono_defaults.internal_thread_class = mono_defaults.thread_class;
+ mono_defaults.gc_class = mono_class_load_from_name (
+ mono_defaults.corlib, "System", "GC");
+
#if defined(HOST_DARWIN)
mono_defaults.autoreleasepool_class = mono_class_try_load_from_name (
mono_defaults.corlib, "System.Threading", "AutoreleasePool");
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 59b7e58b12a7fa..10de4b6affd967 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -82,10 +82,7 @@ static MonoCoopCond exited_cond;
static MonoInternalThread *gc_thread;
-static MonoMethod *finalize_method;
-#ifndef HOST_WASM
-// static RuntimeInvokeFunction finalize_runtime_invoke;
-#endif
+static MonoMethod *finalize_helper;
/*
* This must be a GHashTable, since these objects can't be finalized
@@ -291,25 +288,11 @@ mono_gc_run_finalize (void *obj, void *data)
if (mono_log_finalizers)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o);
- if (!finalize_method) {
- finalize_method = mono_class_get_method_from_name_checked (mono_defaults.finalizer_class, "GuardedFinalize", 1, 0, error);
+ if (!finalize_helper) {
+ finalize_helper = mono_class_get_method_from_name_checked (mono_defaults.gc_class, "GuardedFinalize", 1, 0, error);
mono_error_assert_ok (error);
}
-#ifndef HOST_WASM
- //if (!finalize_runtime_invoke) {
- // MonoMethod *invoke = mono_marshal_get_runtime_invoke (finalize_method, TRUE);
-
- // finalize_runtime_invoke = (RuntimeInvokeFunction)mono_compile_method_checked (invoke, error);
- // mono_error_assert_ok (error); /* expect this not to fail */
- //}
-
- //RuntimeInvokeFunction runtime_invoke = finalize_runtime_invoke;
-#endif
-
- mono_runtime_class_init_full (o->vtable, error);
- goto_if_nok (error, unhandled_error);
-
if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size_internal (o),
o_ns, o_name);
@@ -320,25 +303,15 @@ mono_gc_run_finalize (void *obj, void *data)
MONO_PROFILER_RAISE (gc_finalizing_object, (o));
-#ifdef HOST_WASM
gpointer params [1];
params [0] = o;
- mono_runtime_try_invoke (finalize_method, NULL, params, &exc, error);
-#else
- // runtime_invoke (o, NULL, &exc, NULL);
-
- gpointer params [1];
- params [0] = o;
- mono_runtime_try_invoke (finalize_method, NULL, params, &exc, error);
-
-#endif
+ mono_runtime_try_invoke (finalize_helper, NULL, params, &exc, error);
MONO_PROFILER_RAISE (gc_finalized_object, (o));
if (mono_log_finalizers)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o_name, o);
-unhandled_error:
if (!is_ok (error))
exc = (MonoObject*)mono_error_convert_to_exception (error);
if (exc)
diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c
index 3116aa1517173d..67c4daaa835ca9 100644
--- a/src/mono/mono/mini/aot-compiler.c
+++ b/src/mono/mono/mini/aot-compiler.c
@@ -4977,7 +4977,7 @@ add_full_aot_wrappers (MonoAotCompile *acfg)
add_method (acfg, get_runtime_invoke_sig (csig));
/* runtime-invoke used by finalizers */
- add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.finalizer_class, "GuardedFinalize", 1, 0), FALSE));
+ add_method (acfg, get_runtime_invoke (acfg, get_method_nofail (mono_defaults.gc_class, "GuardedFinalize", 1, 0), FALSE));
/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
From a6605c2d0d4b26f90080421aa464b69d85c45757 Mon Sep 17 00:00:00 2001
From: vsadov <8218165+VSadov@users.noreply.github.com>
Date: Sun, 17 Aug 2025 22:44:04 -0700
Subject: [PATCH 11/11] remove no longer relevant comment
---
src/mono/mono/metadata/gc.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c
index 10de4b6affd967..7065b6fe85fabd 100644
--- a/src/mono/mono/metadata/gc.c
+++ b/src/mono/mono/metadata/gc.c
@@ -279,12 +279,6 @@ mono_gc_run_finalize (void *obj, void *data)
return;
}
-
- /*
- * To avoid the locking plus the other overhead of mono_runtime_invoke_checked (),
- * create and precompile a wrapper which calls the finalize method using
- * a CALLVIRT.
- */
if (mono_log_finalizers)
g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o_name, o);