[netcore] Make the load hook ALC-aware (#16012)
[mono-project.git] / mono / metadata / assembly-load-context.c
blobe33ba7f615c74df51549073bcab5916a8a844937
1 #include "config.h"
2 #include "mono/metadata/assembly.h"
3 #include "mono/metadata/domain-internals.h"
4 #include "mono/metadata/icall-decl.h"
5 #include "mono/metadata/loader-internals.h"
6 #include "mono/metadata/loaded-images-internals.h"
7 #include "mono/utils/mono-error-internals.h"
8 #include "mono/utils/mono-logger-internals.h"
10 #ifdef ENABLE_NETCORE
11 /* MonoAssemblyLoadContext support only in netcore Mono */
13 static
14 GENERATE_GET_CLASS_WITH_CACHE_DECL (assembly_load_context);
16 GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
18 void
19 mono_alc_init (MonoAssemblyLoadContext *alc, MonoDomain *domain)
21 MonoLoadedImages *li = g_new0 (MonoLoadedImages, 1);
22 mono_loaded_images_init (li, alc);
23 alc->domain = domain;
24 alc->loaded_images = li;
25 alc->loaded_assemblies = NULL;
26 mono_coop_mutex_init (&alc->assemblies_lock);
29 void
30 mono_alc_cleanup (MonoAssemblyLoadContext *alc)
33 * As it stands, ALC and domain cleanup is probably broken on netcore. Without ALC collectability, this should not
34 * be hit. I've documented roughly the things that still need to be accomplish, but the implementation is TODO and
35 * the ideal order and locking unclear.
37 * For now, this makes two important assumptions:
38 * 1. The minimum refcount on assemblies is 2: one for the domain and one for the ALC. The domain refcount might
39 * be less than optimal on netcore, but its removal is too likely to cause issues for now.
40 * 2. An ALC will have been removed from the domain before cleanup.
42 GSList *tmp;
43 MonoDomain *domain = alc->domain;
46 * Missing steps:
48 * + Release GC roots for all assemblies in the ALC
49 * + Iterate over the domain_assemblies and remove ones that belong to the ALC, which will probably require
50 * converting domain_assemblies to a doubly-linked list, ideally GQueue
51 * + Close dynamic and then remaining assemblies, potentially nulling the data field depending on refcount
52 * + Second pass to call mono_assembly_close_finish on remaining assemblies
53 * + Free the loaded_assemblies list itself
56 alc->loaded_assemblies = NULL;
57 mono_coop_mutex_destroy (&alc->assemblies_lock);
59 mono_loaded_images_free (alc->loaded_images);
61 g_assert_not_reached ();
64 void
65 mono_alc_assemblies_lock (MonoAssemblyLoadContext *alc)
67 mono_coop_mutex_lock (&alc->assemblies_lock);
70 void
71 mono_alc_assemblies_unlock (MonoAssemblyLoadContext *alc)
73 mono_coop_mutex_unlock (&alc->assemblies_lock);
76 gpointer
77 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC (gpointer this_gchandle_ptr, MonoBoolean is_default_alc, MonoBoolean collectible, MonoError *error)
79 /* If the ALC is collectible, this_gchandle is weak, otherwise it's strong. */
80 uint32_t this_gchandle = (uint32_t)GPOINTER_TO_UINT (this_gchandle_ptr);
81 if (collectible) {
82 mono_error_set_execution_engine (error, "Collectible AssemblyLoadContexts are not yet supported by MonoVM");
83 return NULL;
86 MonoDomain *domain = mono_domain_get ();
87 MonoAssemblyLoadContext *alc = NULL;
89 if (is_default_alc) {
90 alc = mono_domain_default_alc (domain);
91 g_assert (alc);
92 if (!alc->gchandle)
93 alc->gchandle = this_gchandle;
94 } else {
95 /* create it */
96 alc = mono_domain_create_individual_alc (domain, this_gchandle, collectible, error);
98 return alc;
101 gpointer
102 ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (MonoReflectionAssemblyHandle assm_obj, MonoError *error)
104 MonoAssembly *assm = MONO_HANDLE_GETVAL (assm_obj, assembly);
105 MonoAssemblyLoadContext *alc = mono_assembly_get_alc (assm);
107 return GUINT_TO_POINTER (alc->gchandle);
110 gboolean
111 mono_alc_is_default (MonoAssemblyLoadContext *alc)
113 return alc == mono_alc_domain (alc)->default_alc;
116 static MonoAssembly*
117 invoke_resolve_method (MonoMethod *resolve_method, MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
119 MonoAssembly *result = NULL;
120 char* aname_str = NULL;
121 HANDLE_FUNCTION_ENTER ();
123 aname_str = mono_stringify_assembly_name (aname);
125 MonoStringHandle aname_obj = mono_string_new_handle (mono_domain_get (), aname_str, error);
126 goto_if_nok (error, leave);
128 MonoReflectionAssemblyHandle assm;
129 gpointer args[2];
130 args [0] = GUINT_TO_POINTER (alc->gchandle);
131 args [1] = MONO_HANDLE_RAW (aname_obj);
132 assm = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (resolve_method, NULL_HANDLE, args, error));
133 goto_if_nok (error, leave);
135 if (MONO_HANDLE_BOOL (assm))
136 result = MONO_HANDLE_GETVAL (assm, assembly);
138 leave:
139 g_free (aname_str);
140 HANDLE_FUNCTION_RETURN_VAL (result);
143 static MonoAssembly*
144 mono_alc_invoke_resolve_using_load (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
146 static MonoMethod *resolve;
148 if (!resolve) {
149 ERROR_DECL (local_error);
150 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
151 g_assert (alc_class);
152 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingLoad", -1, 0, local_error);
153 mono_error_assert_ok (local_error);
154 resolve = m;
156 g_assert (resolve);
158 return invoke_resolve_method (resolve, alc, aname, error);
161 MonoAssembly*
162 mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
164 MonoAssembly *result = NULL;
165 ERROR_DECL (error);
167 result = mono_alc_invoke_resolve_using_load (alc, aname, error);
168 if (!is_ok (error))
169 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Load(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
171 mono_error_cleanup (error);
173 return result;
176 static MonoAssembly*
177 mono_alc_invoke_resolve_using_resolving_event (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
179 static MonoMethod *resolve;
181 if (!resolve) {
182 ERROR_DECL (local_error);
183 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
184 g_assert (alc_class);
185 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
186 mono_error_assert_ok (local_error);
187 resolve = m;
189 g_assert (resolve);
191 return invoke_resolve_method (resolve, alc, aname, error);
194 MonoAssembly*
195 mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
197 MonoAssembly *result = NULL;
198 ERROR_DECL (error);
200 result = mono_alc_invoke_resolve_using_resolving_event (alc, aname, error);
201 if (!is_ok (error))
202 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Resolving(\"%s\") event: '%s'", aname->name, mono_error_get_message (error));
204 mono_error_cleanup (error);
206 return result;
209 static MonoAssembly*
210 mono_alc_invoke_resolve_using_resolve_satellite (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
212 static MonoMethod *resolve;
214 if (!resolve) {
215 ERROR_DECL (local_error);
216 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
217 g_assert (alc_class);
218 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolveSatelliteAssembly", -1, 0, local_error);
219 mono_error_assert_ok (local_error);
220 resolve = m;
222 g_assert (resolve);
224 return invoke_resolve_method (resolve, alc, aname, error);
227 MonoAssembly*
228 mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
230 MonoAssembly *result = NULL;
231 ERROR_DECL (error);
233 result = mono_alc_invoke_resolve_using_resolve_satellite (alc, aname, error);
234 if (!is_ok (error))
235 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC ResolveSatelliteAssembly(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
237 mono_error_cleanup (error);
239 return result;
244 #endif /* ENABLE_NETCORE */