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);