[cxx][netcore] Goto around init. (#17348)
[mono-project.git] / mono / metadata / assembly-load-context.c
blob7c972cffeacfb9f3add7a2b8e6e3e6a0d796da1e
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/utils/mono-error-internals.h"
13 #include "mono/utils/mono-logger-internals.h"
15 GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
17 void
18 mono_alc_init (MonoAssemblyLoadContext *alc, MonoDomain *domain)
20 MonoLoadedImages *li = g_new0 (MonoLoadedImages, 1);
21 mono_loaded_images_init (li, alc);
22 alc->domain = domain;
23 alc->loaded_images = li;
24 alc->loaded_assemblies = NULL;
25 mono_coop_mutex_init (&alc->assemblies_lock);
28 void
29 mono_alc_cleanup (MonoAssemblyLoadContext *alc)
32 * As it stands, ALC and domain cleanup is probably broken on netcore. Without ALC collectability, this should not
33 * be hit. I've documented roughly the things that still need to be accomplish, but the implementation is TODO and
34 * the ideal order and locking unclear.
36 * For now, this makes two important assumptions:
37 * 1. The minimum refcount on assemblies is 2: one for the domain and one for the ALC. The domain refcount might
38 * be less than optimal on netcore, but its removal is too likely to cause issues for now.
39 * 2. An ALC will have been removed from the domain before cleanup.
41 //GSList *tmp;
42 //MonoDomain *domain = alc->domain;
45 * Missing steps:
47 * + Release GC roots for all assemblies in the ALC
48 * + Iterate over the domain_assemblies and remove ones that belong to the ALC, which will probably require
49 * converting domain_assemblies to a doubly-linked list, ideally GQueue
50 * + Close dynamic and then remaining assemblies, potentially nulling the data field depending on refcount
51 * + Second pass to call mono_assembly_close_finish on remaining assemblies
52 * + Free the loaded_assemblies list itself
55 alc->loaded_assemblies = NULL;
56 mono_coop_mutex_destroy (&alc->assemblies_lock);
58 mono_loaded_images_free (alc->loaded_images);
60 g_assert_not_reached ();
63 void
64 mono_alc_assemblies_lock (MonoAssemblyLoadContext *alc)
66 mono_coop_mutex_lock (&alc->assemblies_lock);
69 void
70 mono_alc_assemblies_unlock (MonoAssemblyLoadContext *alc)
72 mono_coop_mutex_unlock (&alc->assemblies_lock);
75 gpointer
76 ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC (gpointer this_gchandle_ptr, MonoBoolean is_default_alc, MonoBoolean collectible, MonoError *error)
78 /* If the ALC is collectible, this_gchandle is weak, otherwise it's strong. */
79 uint32_t this_gchandle = (uint32_t)GPOINTER_TO_UINT (this_gchandle_ptr);
80 if (collectible) {
81 mono_error_set_execution_engine (error, "Collectible AssemblyLoadContexts are not yet supported by MonoVM");
82 return NULL;
85 MonoDomain *domain = mono_domain_get ();
86 MonoAssemblyLoadContext *alc = NULL;
88 if (is_default_alc) {
89 alc = mono_domain_default_alc (domain);
90 g_assert (alc);
91 if (!alc->gchandle)
92 alc->gchandle = this_gchandle;
93 } else {
94 /* create it */
95 alc = mono_domain_create_individual_alc (domain, this_gchandle, collectible, error);
97 return alc;
100 gpointer
101 ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (MonoReflectionAssemblyHandle assm_obj, MonoError *error)
103 MonoAssembly *assm = MONO_HANDLE_GETVAL (assm_obj, assembly);
104 MonoAssemblyLoadContext *alc = mono_assembly_get_alc (assm);
106 return GUINT_TO_POINTER (alc->gchandle);
109 gboolean
110 mono_alc_is_default (MonoAssemblyLoadContext *alc)
112 return alc == mono_alc_domain (alc)->default_alc;
115 static MonoAssembly*
116 invoke_resolve_method (MonoMethod *resolve_method, MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
118 MonoAssembly *result = NULL;
119 char* aname_str = NULL;
121 if (mono_runtime_get_no_exec ())
122 return NULL;
124 HANDLE_FUNCTION_ENTER ();
126 aname_str = mono_stringify_assembly_name (aname);
128 MonoStringHandle aname_obj = mono_string_new_handle (mono_alc_domain (alc), aname_str, error);
129 goto_if_nok (error, leave);
131 MonoReflectionAssemblyHandle assm;
132 gpointer gchandle;
133 gchandle = GUINT_TO_POINTER (alc->gchandle);
134 gpointer args [2];
135 args [0] = &gchandle;
136 args [1] = MONO_HANDLE_RAW (aname_obj);
137 assm = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (resolve_method, NULL_HANDLE, args, error));
138 goto_if_nok (error, leave);
140 if (MONO_HANDLE_BOOL (assm))
141 result = MONO_HANDLE_GETVAL (assm, assembly);
143 leave:
144 g_free (aname_str);
145 HANDLE_FUNCTION_RETURN_VAL (result);
148 static MonoAssembly*
149 mono_alc_invoke_resolve_using_load (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
151 static MonoMethod *resolve;
153 if (!resolve) {
154 ERROR_DECL (local_error);
155 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
156 g_assert (alc_class);
157 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingLoad", -1, 0, local_error);
158 mono_error_assert_ok (local_error);
159 resolve = m;
161 g_assert (resolve);
163 return invoke_resolve_method (resolve, alc, aname, error);
166 MonoAssembly*
167 mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
169 MonoAssembly *result = NULL;
170 ERROR_DECL (error);
172 result = mono_alc_invoke_resolve_using_load (alc, aname, error);
173 if (!is_ok (error))
174 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Load(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
176 mono_error_cleanup (error);
178 return result;
181 static MonoAssembly*
182 mono_alc_invoke_resolve_using_resolving_event (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
184 static MonoMethod *resolve;
186 if (!resolve) {
187 ERROR_DECL (local_error);
188 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
189 g_assert (alc_class);
190 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
191 mono_error_assert_ok (local_error);
192 resolve = m;
194 g_assert (resolve);
196 return invoke_resolve_method (resolve, alc, aname, error);
199 MonoAssembly*
200 mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
202 MonoAssembly *result = NULL;
203 ERROR_DECL (error);
205 result = mono_alc_invoke_resolve_using_resolving_event (alc, aname, error);
206 if (!is_ok (error))
207 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Resolving(\"%s\") event: '%s'", aname->name, mono_error_get_message (error));
209 mono_error_cleanup (error);
211 return result;
214 static MonoAssembly*
215 mono_alc_invoke_resolve_using_resolve_satellite (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
217 static MonoMethod *resolve;
219 if (!resolve) {
220 ERROR_DECL (local_error);
221 MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
222 g_assert (alc_class);
223 MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolveSatelliteAssembly", -1, 0, local_error);
224 mono_error_assert_ok (local_error);
225 resolve = m;
227 g_assert (resolve);
229 return invoke_resolve_method (resolve, alc, aname, error);
232 MonoAssembly*
233 mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
235 MonoAssembly *result = NULL;
236 ERROR_DECL (error);
238 result = mono_alc_invoke_resolve_using_resolve_satellite (alc, aname, error);
239 if (!is_ok (error))
240 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC ResolveSatelliteAssembly(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
242 mono_error_cleanup (error);
244 return result;
247 #endif /* ENABLE_NETCORE */
249 MONO_EMPTY_SOURCE_FILE (assembly_load_context)