Skip to content

Commit

Permalink
Clean up managed dependencies for Mono's domain/loader context (#46323)
Browse files Browse the repository at this point in the history
Co-authored-by: Aleksey Kliger (λgeek) <akliger@gmail.com>
  • Loading branch information
marek-safar and lambdageek authored Dec 27, 2020
1 parent 02fe1d7 commit 5078dd6
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ private enum InternalState
s_allContexts;

#region private data members
// If you modify any of these fields, you must also update the
// If you modify this field, you must also update the
// AssemblyLoadContextBaseObject structure in object.h
// and MonoManagedAssemblyLoadContext in object-internals.h

// Contains the reference to VM's representation of the AssemblyLoadContext
private readonly IntPtr _nativeAssemblyLoadContext;
#endregion

// synchronization primitive to protect against usage of this instance while unloading
private readonly object _unloadLock;

Expand All @@ -54,17 +58,13 @@ private enum InternalState

private readonly string? _name;

// Contains the reference to VM's representation of the AssemblyLoadContext
private readonly IntPtr _nativeAssemblyLoadContext;

// Id used by s_allContexts
private readonly long _id;

// Indicates the state of this ALC (Alive or in Unloading state)
private InternalState _state;

private readonly bool _isCollectible;
#endregion

protected AssemblyLoadContext() : this(false, false, null)
{
Expand Down Expand Up @@ -180,6 +180,9 @@ public IEnumerable<Assembly> Assemblies
// Returns: A handle to the loaded native library
public event Func<Assembly, string, IntPtr>? ResolvingUnmanagedDll
{
#if MONO
[DynamicDependency(nameof(MonoResolveUnmanagedDllUsingEvent))]
#endif
add
{
_resolvingUnmanagedDll += value;
Expand All @@ -198,6 +201,9 @@ public event Func<Assembly, string, IntPtr>? ResolvingUnmanagedDll
// Returns: The Loaded assembly object.
public event Func<AssemblyLoadContext, AssemblyName, Assembly?>? Resolving
{
#if MONO
[DynamicDependency(nameof(MonoResolveUsingResolvingEvent))]
#endif
add
{
_resolving += value;
Expand All @@ -222,16 +228,28 @@ public event Action<AssemblyLoadContext>? Unloading

#region AppDomainEvents
// Occurs when an Assembly is loaded
#if MONO
[method: DynamicDependency(nameof(OnAssemblyLoad))]
#endif
internal static event AssemblyLoadEventHandler? AssemblyLoad;

// Occurs when resolution of type fails
#if MONO
[method: DynamicDependency(nameof(OnTypeResolve))]
#endif
internal static event ResolveEventHandler? TypeResolve;

// Occurs when resolution of resource fails
#if MONO
[method: DynamicDependency(nameof(OnResourceResolve))]
#endif
internal static event ResolveEventHandler? ResourceResolve;

// Occurs when resolution of assembly fails
// This event is fired after resolve events of AssemblyLoadContext fails
#if MONO
[method: DynamicDependency(nameof(OnAssemblyResolve))]
#endif
internal static event ResolveEventHandler? AssemblyResolve;
#endregion

Expand Down
56 changes: 42 additions & 14 deletions src/mono/mono/metadata/appdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,15 @@ add_assembly_to_alc (MonoAssemblyLoadContext *alc, MonoAssembly *ass);

#endif

#ifndef ENABLE_NETCORE

static MonoAppDomainHandle
mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);

static MonoDomain *
mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);

#endif

static void
mono_context_set_default_context (MonoDomain *domain);
Expand Down Expand Up @@ -596,6 +599,8 @@ mono_runtime_quit_internal (void)
quit_function (mono_get_root_domain (), NULL);
}

#ifndef ENABLE_NETCORE

/**
* mono_domain_create_appdomain:
* \param friendly_name The friendly name of the appdomain to create
Expand Down Expand Up @@ -651,6 +656,8 @@ mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_f
HANDLE_FUNCTION_RETURN_VAL (result);
}

#endif

/**
* mono_domain_set_config:
* \param domain \c MonoDomain initialized with the appdomain we want to change
Expand Down Expand Up @@ -913,13 +920,21 @@ mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, M

MONO_STATIC_POINTER_INIT (MonoMethod, method)

MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnTypeResolve", -1, 0, error);
static gboolean inited;
// avoid repeatedly calling mono_class_get_method_from_name_checked
if (!inited) {
ERROR_DECL (local_error);
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnTypeResolve", -1, 0, local_error);
mono_error_cleanup (local_error);
inited = TRUE;
}

MONO_STATIC_POINTER_INIT_END (MonoMethod, method)

goto_if_nok (error, return_null);
if (!method)
goto return_null;

g_assert (domain);
g_assert (MONO_HANDLE_BOOL (name));
Expand Down Expand Up @@ -1489,14 +1504,21 @@ mono_try_assembly_resolve_handle (MonoAssemblyLoadContext *alc, MonoStringHandle
MONO_STATIC_POINTER_INIT (MonoMethod, method)

ERROR_DECL (local_error);
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyResolve", -1, 0, local_error);
mono_error_assert_ok (local_error);
static gboolean inited;
if (!inited) {
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyResolve", -1, 0, local_error);
inited = TRUE;
}
mono_error_cleanup (local_error);

MONO_STATIC_POINTER_INIT_END (MonoMethod, method)

g_assert (method);
if (!method) {
ret = NULL;
goto leave;
}

MonoReflectionAssemblyHandle requesting_handle;
if (requesting) {
Expand Down Expand Up @@ -1626,12 +1648,19 @@ mono_domain_fire_assembly_load_event (MonoDomain *domain, MonoAssembly *assembly
#ifdef ENABLE_NETCORE
MONO_STATIC_POINTER_INIT (MonoMethod, method)

MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyLoad", -1, 0, error);
static gboolean inited;
if (!inited) {
ERROR_DECL (local_error);
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
method = mono_class_get_method_from_name_checked (alc_class, "OnAssemblyLoad", -1, 0, local_error);
mono_error_cleanup (local_error);
inited = TRUE;
}

MONO_STATIC_POINTER_INIT_END (MonoMethod, method)
goto_if_nok (error, exit);
if (!method)
goto exit;

MonoReflectionAssemblyHandle assembly_handle;
assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
Expand Down Expand Up @@ -3524,4 +3553,3 @@ mono_runtime_install_appctx_properties (void)
}

#endif

15 changes: 10 additions & 5 deletions src/mono/mono/metadata/assembly-load-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,19 @@ mono_alc_invoke_resolve_using_resolving_event (MonoAssemblyLoadContext *alc, Mon
MONO_STATIC_POINTER_INIT (MonoMethod, resolve)

ERROR_DECL (local_error);
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
resolve = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
mono_error_assert_ok (local_error);
static gboolean inited;
if (!inited) {
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
resolve = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
inited = TRUE;
}
mono_error_cleanup (local_error);

MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve)

g_assert (resolve);
if (!resolve)
return NULL;

return invoke_resolve_method (resolve, alc, aname, error);
}
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 @@ -1003,7 +1003,9 @@ typedef struct {
MonoClass *iremotingtypeinfo_class;
#endif
MonoClass *mono_method_message_class;
#ifndef ENABLE_NETCORE
MonoClass *appdomain_class;
#endif
MonoClass *field_info_class;
MonoClass *method_info_class;
MonoClass *stack_frame_class;
Expand Down
4 changes: 1 addition & 3 deletions src/mono/mono/metadata/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,9 +735,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char *
mono_defaults.corlib, "System.Threading", "ThreadAbortException");
#endif

#ifdef ENABLE_NETCORE
mono_defaults.appdomain_class = mono_defaults.object_class;
#else
#ifndef ENABLE_NETCORE
mono_defaults.appdomain_class = mono_class_get_appdomain_class ();
#endif

Expand Down
15 changes: 11 additions & 4 deletions src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -5566,13 +5566,20 @@ try_resource_resolve_name (MonoReflectionAssemblyHandle assembly_handle, MonoStr

MONO_STATIC_POINTER_INIT (MonoMethod, resolve_method)

MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
resolve_method = mono_class_get_method_from_name_checked (alc_class, "OnResourceResolve", -1, 0, error);
static gboolean inited;
if (!inited) {
MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
g_assert (alc_class);
resolve_method = mono_class_get_method_from_name_checked (alc_class, "OnResourceResolve", -1, 0, error);
inited = TRUE;
}
mono_error_cleanup (error);
error_init_reuse (error);

MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve_method)

goto_if_nok (error, return_null);
if (!resolve_method)
goto return_null;

gpointer args [2];
args [0] = MONO_HANDLE_RAW (assembly_handle);
Expand Down
16 changes: 11 additions & 5 deletions src/mono/mono/metadata/native-library.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,13 +568,19 @@ netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext *alc, MonoAsse
MONO_STATIC_POINTER_INIT (MonoMethod, resolve)

ERROR_DECL (local_error);
MonoClass *native_lib_class = mono_class_get_native_library_class ();
g_assert (native_lib_class);
resolve = mono_class_get_method_from_name_checked (native_lib_class, "MonoLoadLibraryCallbackStub", -1, 0, local_error);
mono_error_assert_ok (local_error);
static gboolean inited;
if (!inited) {
MonoClass *native_lib_class = mono_class_get_native_library_class ();
g_assert (native_lib_class);
resolve = mono_class_get_method_from_name_checked (native_lib_class, "MonoLoadLibraryCallbackStub", -1, 0, local_error);
inited = TRUE;
}
mono_error_cleanup (local_error);

MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve)
g_assert (resolve);

if (!resolve)
return NULL;

if (mono_runtime_get_no_exec ())
return NULL;
Expand Down
8 changes: 0 additions & 8 deletions src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1660,15 +1660,7 @@ typedef enum {
// Keep in sync with System.Runtime.Loader.AssemblyLoadContext
typedef struct {
MonoObject object;
MonoObject *unload_lock;
MonoEvent *resolving_unmaned_dll;
MonoEvent *resolving;
MonoEvent *unloading;
MonoString *name;
MonoAssemblyLoadContext *native_assembly_load_context;
gint64 id;
gint32 internal_state;
MonoBoolean is_collectible;
} MonoManagedAssemblyLoadContext;

TYPED_HANDLE_DECL (MonoManagedAssemblyLoadContext);
Expand Down
22 changes: 18 additions & 4 deletions src/mono/mono/metadata/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -5080,11 +5080,17 @@ mono_first_chance_exception_checked (MonoObjectHandle exc, MonoError *error)

MONO_STATIC_POINTER_INIT (MonoClassField, field)

field = mono_class_get_field_from_name_full (mono_defaults.appcontext_class, "FirstChanceException", NULL);
g_assert (field);
static gboolean inited;
if (!inited) {
field = mono_class_get_field_from_name_full (mono_defaults.appcontext_class, "FirstChanceException", NULL);
inited = TRUE;
}

MONO_STATIC_POINTER_INIT_END (MonoClassField, field)

if (!field)
return;

MonoVTable *vt = mono_class_vtable_checked (domain, mono_defaults.appcontext_class, error);
return_if_nok (error);

Expand Down Expand Up @@ -5141,13 +5147,18 @@ mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
#ifndef ENABLE_NETCORE
field = mono_class_get_field_from_name_full (mono_defaults.appdomain_class, "UnhandledException", NULL);
#else
field = mono_class_get_field_from_name_full (mono_defaults.appcontext_class, "UnhandledException", NULL);
static gboolean inited;
if (!inited) {
field = mono_class_get_field_from_name_full (mono_defaults.appcontext_class, "UnhandledException", NULL);
inited = TRUE;
}
#endif
g_assert (field);

MONO_STATIC_POINTER_INIT_END (MonoClassField, field)

#ifndef ENABLE_NETCORE
g_assert (field);

MonoDomain *root_domain;
MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);

Expand All @@ -5172,6 +5183,9 @@ mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
mono_threads_end_abort_protected_block ();
}
#else
if (!field)
goto leave;

MonoObject *delegate = NULL;
MonoObjectHandle delegate_handle;
MonoVTable *vt = mono_class_vtable_checked (current_domain, mono_defaults.appcontext_class, error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,13 @@

<!-- assembly-load-context.c: -->
<!-- object-internals.h: MonoManagedAssemblyLoadContext -->
<type fullname="System.Runtime.Loader.AssemblyLoadContext" preserve="fields">
<type fullname="System.Runtime.Loader.AssemblyLoadContext">
<!-- assembly-load-context.c: mono_alc_invoke_resolve_using_load -->
<method name="MonoResolveUsingLoad" />
<!-- assembly-load-context.c: mono_alc_invoke_resolve_using_resolving_event -->
<method name="MonoResolveUsingResolvingEvent" />
<!-- assembly-load-context.c: mono_alc_invoke_resolve_using_resolve_satellite -->
<method name="MonoResolveUsingResolveSatelliteAssembly" />
<!-- native-library.c: netcore_resolve_with_load () -->
<method name="MonoResolveUnmanagedDll" />
<!-- native-library.c: netcore_resolve_with_resolving_event () -->
<method name="MonoResolveUnmanagedDllUsingEvent" />
<!-- appdomain.c: mono_domain_fire_assembly_load_event -->
<method name="OnAssemblyLoad" />
<!-- appdomain.c: mono_try_assembly_resolve_handle () -->
<method name="OnAssemblyResolve" />
<!-- appdomain.c: mono_domain_try_type_resolve_name -->
<method name="OnTypeResolve" />
<!-- icall.c: try_resource_resolve_name -->
<method name="OnResourceResolve" />
</type>

<!-- exception.c (mono_get_exception_argument) -->
Expand Down Expand Up @@ -643,10 +631,6 @@
<method name="OnProcessExit"/>
<!-- appdomain.c: get_app_context_base_directory -->
<method name="get_BaseDirectory"/>
<!-- object.c: mono_unhandled_exception_checked -->
<field name="UnhandledException"/>
<!-- object.c: mono_first_chance_exception_checked -->
<field name="FirstChanceException"/>
</type>

<!-- mono_method_has_unmanaged_callers_only_attribute () -->
Expand Down
Loading

0 comments on commit 5078dd6

Please sign in to comment.