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");
19 mono_alc_init (MonoAssemblyLoadContext
*alc
, MonoDomain
*domain
, gboolean collectible
)
21 MonoLoadedImages
*li
= g_new0 (MonoLoadedImages
, 1);
22 mono_loaded_images_init (li
, alc
);
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
)
45 alc
= g_new0 (MonoAssemblyLoadContext
, 1);
46 mono_alc_init (alc
, domain
, collectible
);
48 domain
->alcs
= g_slist_prepend (domain
->alcs
, alc
);
50 domain
->default_alc
= alc
;
53 mono_domain_alcs_unlock (domain
);
58 mono_alc_create_default (MonoDomain
*domain
)
60 if (domain
->default_alc
)
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
;
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.
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
))
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
))
109 // Close the remaining assemblies
110 for (tmp
= alc
->loaded_assemblies
; tmp
; tmp
= tmp
->next
) {
111 MonoAssembly
*assembly
= (MonoAssembly
*)tmp
->data
;
114 if (!assembly
->image
|| image_is_dynamic (assembly
->image
))
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
))
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
;
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
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
178 mono_alc_free (MonoAssemblyLoadContext
*alc
)
180 mono_alc_cleanup (alc
);
185 mono_alc_assemblies_lock (MonoAssemblyLoadContext
*alc
)
187 mono_coop_mutex_lock (&alc
->assemblies_lock
);
191 mono_alc_assemblies_unlock (MonoAssemblyLoadContext
*alc
)
193 mono_coop_mutex_unlock (&alc
->assemblies_lock
);
197 mono_alc_memory_managers_lock (MonoAssemblyLoadContext
*alc
)
199 mono_coop_mutex_lock (&alc
->memory_managers_lock
);
203 mono_alc_memory_managers_unlock (MonoAssemblyLoadContext
*alc
)
205 mono_coop_mutex_unlock (&alc
->memory_managers_lock
);
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
);
221 alc
->gchandle
= this_gchandle
;
223 alc
= mono_alc_create_individual (domain
, this_gchandle
, collectible
, error
);
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
);
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
;
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
);
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
;
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 ())
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
;
295 gchandle
= (gpointer
)alc
->gchandle
;
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
);
307 HANDLE_FUNCTION_RETURN_VAL (result
);
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
)
325 return invoke_resolve_method (resolve
, alc
, aname
, error
);
329 mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
)
331 MonoAssembly
*result
= NULL
;
334 result
= mono_alc_invoke_resolve_using_load (alc
, aname
, 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
);
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
)
358 return invoke_resolve_method (resolve
, alc
, aname
, error
);
362 mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
)
364 MonoAssembly
*result
= NULL
;
367 result
= mono_alc_invoke_resolve_using_resolving_event (alc
, aname
, 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
);
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
)
391 return invoke_resolve_method (resolve
, alc
, aname
, error
);
395 mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext
*alc
, MonoAssemblyName
*aname
)
397 MonoAssembly
*result
= NULL
;
400 result
= mono_alc_invoke_resolve_using_resolve_satellite (alc
, aname
, 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
);
409 #endif /* ENABLE_NETCORE */
411 MONO_EMPTY_SOURCE_FILE (assembly_load_context
)