Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@
<method name="GetHashCode" />
</type>

<!-- domain.c: mono_defaults.gc_class -->
<type fullname="System.GC">
<!-- gc.c: mono_gc_run_finalize -->
<method name="GuardedFinalize" />
</type>

<!-- appdomain.c (create_domain_objects) domain->out_of_memory_ex -->
<type fullname="System.OutOfMemoryException">
<!-- mono_exception_from_name_two_strings (only one string in the signature since NULL is used as the 2nd parameter) -->
Expand Down
15 changes: 15 additions & 0 deletions src/mono/System.Private.CoreLib/src/System/GC.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics.Tracing;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;

namespace System
{
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -889,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;
Expand Down
3 changes: 3 additions & 0 deletions src/mono/mono/metadata/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,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");
Expand Down
40 changes: 7 additions & 33 deletions src/mono/mono/metadata/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ static gboolean finalizer_thread_exited;
static MonoCoopCond exited_cond;

static MonoInternalThread *gc_thread;
#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
Expand Down Expand Up @@ -280,31 +279,14 @@ 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);

#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);
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);
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);
Expand All @@ -315,23 +297,15 @@ 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);
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);
}
#else
runtime_invoke (o, NULL, &exc, NULL);
#endif
gpointer params [1];
params [0] = o;
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)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.gc_class, "GuardedFinalize", 1, 0), FALSE));

/* This is used by mono_runtime_capture_context () */
method = mono_get_context_capture_method ();
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -5363,7 +5363,7 @@ 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) {
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);
Expand Down
13 changes: 11 additions & 2 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1714,8 +1714,11 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/opt/Structs/MemsetMemcpyNullref/*">
<Issue>https://github.com/dotnet/runtime/issues/98628</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/baseservices/exceptions/UnhandledExceptionHandler/**">
<Issue>NYI on Mono</Issue>
<ExcludeList Include="$(XunitTestBinBase)/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows/*">
<Issue>https://github.com/dotnet/runtime/issues/47624</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread/*">
<Issue>Test issue. The test relies on overriding the process return code.</Issue>
</ExcludeList>
</ItemGroup>

Expand Down Expand Up @@ -2193,6 +2196,12 @@
<ExcludeList Include = "$(XunitTestBinBase)/Exceptions/ForeignThread/ForeignThreadExceptions/**">
<Issue>llvmfullaot: EH problem</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/baseservices/exceptions/UnhandledExceptionHandler/Foreign/**">
<Issue>llvmfullaot: EH problem</Issue>
</ExcludeList>
<ExcludeList Include = "$(XunitTestBinBase)/baseservices/exceptions/UnhandledExceptionHandler/PInvoke/**">
<Issue>llvmfullaot: EH problem</Issue>
</ExcludeList>

<ExcludeList Include = "$(XunitTestBinBase)/JIT/Directed/nullabletypes/Desktop/boxunboxvaluetype_*/**">
<Issue>https://github.com/dotnet/runtime/issues/57353</Issue>
Expand Down
Loading