Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / assembly-load-context.c
blob90b8d5e26e4c2c4c41e0b0ce1574641276936002
1 #include "config.h"
2 #include "mono/utils/mono-compiler.h"
4 #ifdef ENABLE_NETCORE // MonoAssemblyLoadContext support only in netcore Mono
6 #include "mono/metadata/assembly.h"
7 #include "mono/metadata/domain-internals.h"
8 #include "mono/metadata/exception-internals.h"
9 #include "mono/metadata/icall-decl.h"
10 #include "mono/metadata/loader-internals.h"
11 #include "mono/metadata/loaded-images-internals.h"
12 #include "mono/metadata/mono-private-unstable.h"
13 #include "mono/utils/mono-error-internals.h"
14 #include "mono/utils/mono-logger-internals.h"
16 GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
18 static void
19 mono_alc_init (MonoAssemblyLoadContext *alc, MonoDomain *domain, gboolean collectible)
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 alc->memory_manager = mono_mem_manager_create_singleton (alc, domain, collectible);
27 alc->generic_memory_managers = g_ptr_array_new ();
28 mono_coop_mutex_init (&alc->memory_managers_lock);
29 alc->unloading = FALSE;
30 alc->collectible = collectible;
31 alc->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
32 mono_coop_mutex_init (&alc->assemblies_lock);
33 mono_coop_mutex_init (&alc->pinvoke_lock);
36 static MonoAssemblyLoadContext *
37 mono_alc_create (MonoDomain *domain, gboolean is_default, gboolean collectible)
39 MonoAssemblyLoadContext *alc = NULL;
41 mono_domain_alcs_lock (domain);
42 if (is_default && domain->default_alc)
43 goto leave;
45 alc = g_new0 (MonoAssemblyLoadContext, 1);
46 mono_alc_init (alc, domain, collectible);
48 domain->alcs = g_slist_prepend (domain->alcs, alc);
49 if (is_default)
50 domain->default_alc = alc;
52 leave:
53 mono_domain_alcs_unlock (domain);
54 return alc;
57 void
58 mono_alc_create_default (MonoDomain *domain)
60 if (domain->default_alc)
61 return;
62 mono_alc_create (domain, TRUE, FALSE);
65 MonoAssemblyLoadContext *
66 mono_alc_create_individual (MonoDomain *domain, MonoGCHandle this_gchandle, gboolean collectible, MonoError *error)
68 MonoAssemblyLoadContext *alc = mono_alc_create (domain, FALSE, collectible);
70 alc->gchandle = this_gchandle;
72 return alc;
75 static void
76 mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
78 // The minimum refcount on assemblies is 2: one for the domain and one for the ALC.
79 // The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now.
80 GSList *tmp;
81 MonoDomain *domain = alc->domain;
83 // Remove the assemblies from domain_assemblies
84 mono_domain_assemblies_lock (domain);
85 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
86 MonoAssembly *assembly = (MonoAssembly *)tmp->data;
87 domain->domain_assemblies = g_slist_remove (domain->domain_assemblies, assembly);
88 mono_assembly_decref (assembly);
89 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], removing assembly %s[%p] from domain_assemblies, ref_count=%d\n", alc, assembly->aname.name, assembly, assembly->ref_count);
91 mono_domain_assemblies_unlock (domain);
93 // Release the GC roots
94 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
95 MonoAssembly *assembly = (MonoAssembly *)tmp->data;
96 mono_assembly_release_gc_roots (assembly);
99 // Close dynamic assemblies
100 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
101 MonoAssembly *assembly = (MonoAssembly *)tmp->data;
102 if (!assembly->image || !image_is_dynamic (assembly->image))
103 continue;
104 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], dynamic assembly %s[%p], ref_count=%d", domain, assembly->aname.name, assembly, assembly->ref_count);
105 if (!mono_assembly_close_except_image_pools (assembly))
106 tmp->data = NULL;
109 // Close the remaining assemblies
110 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
111 MonoAssembly *assembly = (MonoAssembly *)tmp->data;
112 if (!assembly)
113 continue;
114 if (!assembly->image || image_is_dynamic (assembly->image))
115 continue;
116 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], non-dynamic assembly %s[%p], ref_count=%d", domain, assembly->aname.name, assembly, assembly->ref_count);
117 if (!mono_assembly_close_except_image_pools (assembly))
118 tmp->data = NULL;
121 // Complete the second closing pass on lingering assemblies
122 for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
123 MonoAssembly *assembly = (MonoAssembly *)tmp->data;
124 if (assembly)
125 mono_assembly_close_finish (assembly);
128 // Free the loaded_assemblies
129 g_slist_free (alc->loaded_assemblies);
130 alc->loaded_assemblies = NULL;
132 mono_coop_mutex_destroy (&alc->assemblies_lock);
134 mono_loaded_images_free (alc->loaded_images);
135 alc->loaded_images = NULL;
137 // TODO: free mempool stuff/jit info tables, see domain freeing for an example
140 static void
141 mono_alc_cleanup (MonoAssemblyLoadContext *alc)
143 MonoDomain *domain = alc->domain;
145 g_assert (alc != mono_domain_default_alc (domain));
146 g_assert (alc->collectible == TRUE);
148 // TODO: alc unloading profiler event
150 // Remove from domain list
151 mono_domain_alcs_lock (domain);
152 domain->alcs = g_slist_remove (domain->alcs, alc);
153 mono_domain_alcs_unlock (domain);
155 mono_alc_cleanup_assemblies (alc);
157 mono_mem_manager_free_singleton (alc->memory_manager, FALSE);
158 alc->memory_manager = NULL;
160 /*for (int i = 0; i < alc->generic_memory_managers->len; i++) {
161 MonoGenericMemoryManager *memory_manager = (MonoGenericMemoryManager *)alc->generic_memory_managers->pdata [i];
162 mono_mem_manager_free_generic (memory_manager, FALSE);
164 g_ptr_array_free (alc->generic_memory_managers, TRUE);
165 mono_coop_mutex_destroy (&alc->memory_managers_lock);
167 mono_gchandle_free_internal (alc->gchandle);
168 alc->gchandle = NULL;
170 g_hash_table_destroy (alc->pinvoke_scopes);
171 alc->pinvoke_scopes = NULL;
172 mono_coop_mutex_destroy (&alc->pinvoke_lock);
174 // TODO: alc unloaded profiler event
177 static void
178 mono_alc_free (MonoAssemblyLoadContext *alc)
180 mono_alc_cleanup (alc);
181 g_free (alc);
184 void
185 mono_alc_assemblies_lock (MonoAssemblyLoadContext *alc)
187 mono_coop_mutex_lock (&alc->assemblies_lock);
190 void
191 mono_alc_assemblies_unlock (MonoAssemblyLoadContext *alc)
193 mono_coop_mutex_unlock (&alc->assemblies_lock);
196 void
197 mono_alc_memory_managers_lock (MonoAssemblyLoadContext *alc)
199 mono_coop_mutex_lock (&alc->memory_managers_lock);
202 void
203 mono_alc_memory_managers_unlock (MonoAssemblyLoadContext *alc)
205 mono_coop_mutex_unlock (&alc->memory_managers_lock);
208 gpointer
209 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC (gpointer this_gchandle_ptr, MonoBoolean is_default_alc, MonoBoolean collectible, MonoError *error)
211 /* If the ALC is collectible, this_gchandle is weak, otherwise it's strong. */
212 MonoGCHandle this_gchandle = (MonoGCHandle)this_gchandle_ptr;
214 MonoDomain *domain = mono_domain_get ();
215 MonoAssemblyLoadContext *alc = NULL;
217 if (is_default_alc) {
218 alc = mono_domain_default_alc (domain);
219 g_assert (alc);
220 if (!alc->gchandle)
221 alc->gchandle = this_gchandle;
222 } else
223 alc = mono_alc_create_individual (domain, this_gchandle, collectible, error);
225 return alc;
228 void
229 ves_icall_System_Runtime_Loader_AssemblyLoadContext_PrepareForAssemblyLoadContextRelease (gpointer alc_pointer, gpointer strong_gchandle_ptr, MonoError *error)
231 MonoGCHandle strong_gchandle = (MonoGCHandle)strong_gchandle_ptr;
232 MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_pointer;
234 g_assert (alc->collectible);
235 g_assert (!alc->unloading);
236 g_assert (alc->gchandle);
238 alc->unloading = TRUE;
240 // Replace the weak gchandle with the new strong one to keep the managed ALC alive
241 MonoGCHandle weak_gchandle = alc->gchandle;
242 alc->gchandle = strong_gchandle;
243 mono_gchandle_free_internal (weak_gchandle);
246 gpointer
247 ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (MonoReflectionAssemblyHandle assm_obj, MonoError *error)
249 MonoAssembly *assm = MONO_HANDLE_GETVAL (assm_obj, assembly);
250 MonoAssemblyLoadContext *alc = mono_assembly_get_alc (assm);
252 return (gpointer)alc->gchandle;
255 gboolean
256 mono_alc_is_default (MonoAssemblyLoadContext *alc)
258 return alc == mono_alc_domain (alc)->default_alc;
261 MonoAssemblyLoadContext *
262 mono_alc_from_gchandle (MonoGCHandle alc_gchandle)
264 HANDLE_FUNCTION_ENTER ();
265 MonoManagedAssemblyLoadContextHandle managed_alc = MONO_HANDLE_CAST (MonoManagedAssemblyLoadContext, mono_gchandle_get_target_handle (alc_gchandle));
266 MonoAssemblyLoadContext *alc = MONO_HANDLE_GETVAL (managed_alc, native_assembly_load_context);
267 HANDLE_FUNCTION_RETURN_VAL (alc);
270 MonoGCHandle
271 mono_alc_get_default_gchandle (void)
273 // Because the default domain is never unloadable, this should be a strong handle and never change
274 return mono_domain_default_alc (mono_domain_get ())->gchandle;
277 static MonoAssembly*
278 invoke_resolve_method (MonoMethod *resolve_method, MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
280 MonoAssembly *result = NULL;
281 char* aname_str = NULL;
283 if (mono_runtime_get_no_exec ())
284 return NULL;
286 HANDLE_FUNCTION_ENTER ();
288 aname_str = mono_stringify_assembly_name (aname);
290 MonoStringHandle aname_obj = mono_string_new_handle (mono_alc_domain (alc), aname_str, error);
291 goto_if_nok (error, leave);
293 MonoReflectionAssemblyHandle assm;
294 gpointer gchandle;
295 gchandle = (gpointer)alc->gchandle;
296 gpointer args [2];
297 args [0] = &gchandle;
298 args [1] = MONO_HANDLE_RAW (aname_obj);
299 assm = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (resolve_method, NULL_HANDLE, args, error));
300 goto_if_nok (error, leave);
302 if (MONO_HANDLE_BOOL (assm))
303 result = MONO_HANDLE_GETVAL (assm, assembly);
305 leave:
306 g_free (aname_str);
307 HANDLE_FUNCTION_RETURN_VAL (result);
310 static MonoAssembly*
311 mono_alc_invoke_resolve_using_load (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
313 MONO_STATIC_POINTER_INIT (MonoMethod, resolve)
315 ERROR_DECL (local_error);
316 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
317 g_assert (alc_class);
318 resolve = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingLoad", -1, 0, local_error);
319 mono_error_assert_ok (local_error);
321 MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve)
323 g_assert (resolve);
325 return invoke_resolve_method (resolve, alc, aname, error);
328 MonoAssembly*
329 mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
331 MonoAssembly *result = NULL;
332 ERROR_DECL (error);
334 result = mono_alc_invoke_resolve_using_load (alc, aname, error);
335 if (!is_ok (error))
336 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Load(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
338 mono_error_cleanup (error);
340 return result;
343 static MonoAssembly*
344 mono_alc_invoke_resolve_using_resolving_event (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
346 MONO_STATIC_POINTER_INIT (MonoMethod, resolve)
348 ERROR_DECL (local_error);
349 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
350 g_assert (alc_class);
351 resolve = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
352 mono_error_assert_ok (local_error);
354 MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve)
356 g_assert (resolve);
358 return invoke_resolve_method (resolve, alc, aname, error);
361 MonoAssembly*
362 mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
364 MonoAssembly *result = NULL;
365 ERROR_DECL (error);
367 result = mono_alc_invoke_resolve_using_resolving_event (alc, aname, error);
368 if (!is_ok (error))
369 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Resolving(\"%s\") event: '%s'", aname->name, mono_error_get_message (error));
371 mono_error_cleanup (error);
373 return result;
376 static MonoAssembly*
377 mono_alc_invoke_resolve_using_resolve_satellite (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
379 MONO_STATIC_POINTER_INIT (MonoMethod, resolve)
381 ERROR_DECL (local_error);
382 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
383 g_assert (alc_class);
384 resolve = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolveSatelliteAssembly", -1, 0, local_error);
385 mono_error_assert_ok (local_error);
387 MONO_STATIC_POINTER_INIT_END (MonoMethod, resolve)
389 g_assert (resolve);
391 return invoke_resolve_method (resolve, alc, aname, error);
394 MonoAssembly*
395 mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
397 MonoAssembly *result = NULL;
398 ERROR_DECL (error);
400 result = mono_alc_invoke_resolve_using_resolve_satellite (alc, aname, error);
401 if (!is_ok (error))
402 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Error while invoking ALC ResolveSatelliteAssembly(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
404 mono_error_cleanup (error);
406 return result;
409 #endif /* ENABLE_NETCORE */
411 MONO_EMPTY_SOURCE_FILE (assembly_load_context)