|
2 | 2 | #include "mono/utils/mono-compiler.h"
|
3 | 3 |
|
4 | 4 | #include "mono/metadata/assembly.h"
|
| 5 | +#include "mono/metadata/assembly-internals.h" |
5 | 6 | #include "mono/metadata/domain-internals.h"
|
6 | 7 | #include "mono/metadata/exception-internals.h"
|
7 | 8 | #include "mono/metadata/icall-decl.h"
|
8 | 9 | #include "mono/metadata/loader-internals.h"
|
9 | 10 | #include "mono/metadata/loaded-images-internals.h"
|
10 | 11 | #include "mono/metadata/mono-private-unstable.h"
|
| 12 | +#include "mono/metadata/mono-debug.h" |
11 | 13 | #include "mono/utils/mono-error-internals.h"
|
12 | 14 | #include "mono/utils/mono-logger-internals.h"
|
13 | 15 |
|
14 | 16 | GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
|
| 17 | +static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly"); |
15 | 18 |
|
16 | 19 | static GSList *alcs;
|
17 | 20 | static MonoAssemblyLoadContext *default_alc;
|
18 | 21 | static MonoCoopMutex alc_list_lock; /* Used when accessing 'alcs' */
|
| 22 | +/* Protected by alc_list_lock */ |
| 23 | +static GSList *loaded_assemblies; |
19 | 24 |
|
20 | 25 | static inline void
|
21 | 26 | alcs_lock (void)
|
@@ -92,17 +97,18 @@ mono_alc_cleanup_assemblies (MonoAssemblyLoadContext *alc)
|
92 | 97 | // The minimum refcount on assemblies is 2: one for the domain and one for the ALC.
|
93 | 98 | // The domain refcount might be less than optimal on netcore, but its removal is too likely to cause issues for now.
|
94 | 99 | GSList *tmp;
|
95 |
| - MonoDomain *domain = mono_get_root_domain (); |
96 | 100 |
|
97 |
| - // Remove the assemblies from domain_assemblies |
98 |
| - mono_domain_assemblies_lock (domain); |
| 101 | + // Remove the assemblies from loaded_assemblies |
99 | 102 | for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
|
100 | 103 | MonoAssembly *assembly = (MonoAssembly *)tmp->data;
|
101 |
| - domain->domain_assemblies = g_slist_remove (domain->domain_assemblies, assembly); |
| 104 | + |
| 105 | + alcs_lock (); |
| 106 | + loaded_assemblies = g_slist_remove (loaded_assemblies, assembly); |
| 107 | + alcs_unlock (); |
| 108 | + |
102 | 109 | mono_assembly_decref (assembly);
|
103 |
| - 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); |
| 110 | + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading ALC [%p], removing assembly %s[%p] from loaded_assemblies, ref_count=%d\n", alc, assembly->aname.name, assembly, assembly->ref_count); |
104 | 111 | }
|
105 |
| - mono_domain_assemblies_unlock (domain); |
106 | 112 |
|
107 | 113 | // Release the GC roots
|
108 | 114 | for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
|
@@ -262,6 +268,135 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (M
|
262 | 268 | return (gpointer)alc->gchandle;
|
263 | 269 | }
|
264 | 270 |
|
| 271 | +static gboolean |
| 272 | +add_assembly_to_array (MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error) |
| 273 | +{ |
| 274 | + HANDLE_FUNCTION_ENTER (); |
| 275 | + error_init (error); |
| 276 | + MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (assm, error); |
| 277 | + goto_if_nok (error, leave); |
| 278 | + MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj); |
| 279 | +leave: |
| 280 | + HANDLE_FUNCTION_RETURN_VAL (is_ok (error)); |
| 281 | +} |
| 282 | + |
| 283 | +MonoArrayHandle |
| 284 | +ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies (MonoError *error) |
| 285 | +{ |
| 286 | + GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); |
| 287 | + |
| 288 | + MonoArrayHandle res = mono_array_new_handle (mono_class_get_assembly_class (), assemblies->len, error); |
| 289 | + goto_if_nok (error, leave); |
| 290 | + for (int i = 0; i < assemblies->len; ++i) { |
| 291 | + if (!add_assembly_to_array (res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error)) |
| 292 | + goto leave; |
| 293 | + } |
| 294 | + |
| 295 | +leave: |
| 296 | + g_ptr_array_free (assemblies, TRUE); |
| 297 | + return res; |
| 298 | +} |
| 299 | + |
| 300 | +static |
| 301 | +MonoAssembly * |
| 302 | +mono_alc_load_file (MonoAssemblyLoadContext *alc, MonoStringHandle fname, MonoAssembly *executing_assembly, MonoAssemblyContextKind asmctx, MonoError *error) |
| 303 | +{ |
| 304 | + MonoAssembly *ass = NULL; |
| 305 | + HANDLE_FUNCTION_ENTER (); |
| 306 | + char *filename = NULL; |
| 307 | + if (MONO_HANDLE_IS_NULL (fname)) { |
| 308 | + mono_error_set_argument_null (error, "assemblyFile", ""); |
| 309 | + goto leave; |
| 310 | + } |
| 311 | + |
| 312 | + filename = mono_string_handle_to_utf8 (fname, error); |
| 313 | + goto_if_nok (error, leave); |
| 314 | + |
| 315 | + if (!g_path_is_absolute (filename)) { |
| 316 | + mono_error_set_argument (error, "assemblyFile", "Absolute path information is required."); |
| 317 | + goto leave; |
| 318 | + } |
| 319 | + |
| 320 | + MonoImageOpenStatus status; |
| 321 | + MonoAssemblyOpenRequest req; |
| 322 | + mono_assembly_request_prepare_open (&req, asmctx, alc); |
| 323 | + req.requesting_assembly = executing_assembly; |
| 324 | + ass = mono_assembly_request_open (filename, &req, &status); |
| 325 | + if (!ass) { |
| 326 | + if (status == MONO_IMAGE_IMAGE_INVALID) |
| 327 | + mono_error_set_bad_image_by_name (error, filename, "Invalid Image: %s", filename); |
| 328 | + else |
| 329 | + mono_error_set_simple_file_not_found (error, filename); |
| 330 | + } |
| 331 | + |
| 332 | +leave: |
| 333 | + g_free (filename); |
| 334 | + HANDLE_FUNCTION_RETURN_VAL (ass); |
| 335 | +} |
| 336 | + |
| 337 | +MonoReflectionAssemblyHandle |
| 338 | +ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile (gpointer alc_ptr, MonoStringHandle fname, MonoStackCrawlMark *stack_mark, MonoError *error) |
| 339 | +{ |
| 340 | + MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE); |
| 341 | + MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)alc_ptr; |
| 342 | + |
| 343 | + MonoAssembly *executing_assembly; |
| 344 | + executing_assembly = mono_runtime_get_caller_from_stack_mark (stack_mark); |
| 345 | + MonoAssembly *ass = mono_alc_load_file (alc, fname, executing_assembly, mono_alc_is_default (alc) ? MONO_ASMCTX_LOADFROM : MONO_ASMCTX_INDIVIDUAL, error); |
| 346 | + goto_if_nok (error, leave); |
| 347 | + |
| 348 | + result = mono_assembly_get_object_handle (ass, error); |
| 349 | + |
| 350 | +leave: |
| 351 | + return result; |
| 352 | +} |
| 353 | + |
| 354 | +static MonoAssembly* |
| 355 | +mono_alc_load_raw_bytes (MonoAssemblyLoadContext *alc, guint8 *assembly_data, guint32 raw_assembly_len, guint8 *raw_symbol_data, guint32 raw_symbol_len, MonoError *error) |
| 356 | +{ |
| 357 | + MonoAssembly *ass = NULL; |
| 358 | + MonoImageOpenStatus status; |
| 359 | + MonoImage *image = mono_image_open_from_data_internal (alc, (char*)assembly_data, raw_assembly_len, TRUE, NULL, FALSE, NULL, NULL); |
| 360 | + |
| 361 | + if (!image) { |
| 362 | + mono_error_set_bad_image_by_name (error, "In memory assembly", "0x%p", assembly_data); |
| 363 | + return ass; |
| 364 | + } |
| 365 | + |
| 366 | + if (raw_symbol_data) |
| 367 | + mono_debug_open_image_from_memory (image, raw_symbol_data, raw_symbol_len); |
| 368 | + |
| 369 | + MonoAssemblyLoadRequest req; |
| 370 | + mono_assembly_request_prepare_load (&req, MONO_ASMCTX_INDIVIDUAL, alc); |
| 371 | + ass = mono_assembly_request_load_from (image, "", &req, &status); |
| 372 | + |
| 373 | + if (!ass) { |
| 374 | + mono_image_close (image); |
| 375 | + mono_error_set_bad_image_by_name (error, "In Memory assembly", "0x%p", assembly_data); |
| 376 | + return ass; |
| 377 | + } |
| 378 | + |
| 379 | + /* Clear the reference added by mono_image_open_from_data_internal above */ |
| 380 | + mono_image_close (image); |
| 381 | + |
| 382 | + return ass; |
| 383 | +} |
| 384 | + |
| 385 | +MonoReflectionAssemblyHandle |
| 386 | +ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFromStream (gpointer native_alc, gpointer raw_assembly_ptr, gint32 raw_assembly_len, gpointer raw_symbols_ptr, gint32 raw_symbols_len, MonoError *error) |
| 387 | +{ |
| 388 | + MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)native_alc; |
| 389 | + MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE); |
| 390 | + MonoAssembly *assm = NULL; |
| 391 | + assm = mono_alc_load_raw_bytes (alc, (guint8 *)raw_assembly_ptr, raw_assembly_len, (guint8 *)raw_symbols_ptr, raw_symbols_len, error); |
| 392 | + goto_if_nok (error, leave); |
| 393 | + |
| 394 | + result = mono_assembly_get_object_handle (assm, error); |
| 395 | + |
| 396 | +leave: |
| 397 | + return result; |
| 398 | +} |
| 399 | + |
265 | 400 | gboolean
|
266 | 401 | mono_alc_is_default (MonoAssemblyLoadContext *alc)
|
267 | 402 | {
|
@@ -420,3 +555,77 @@ mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext
|
420 | 555 |
|
421 | 556 | return result;
|
422 | 557 | }
|
| 558 | + |
| 559 | +void |
| 560 | +mono_alc_add_assembly (MonoAssemblyLoadContext *alc, MonoAssembly *ass) |
| 561 | +{ |
| 562 | + GSList *tmp; |
| 563 | + |
| 564 | + g_assert (ass); |
| 565 | + |
| 566 | + if (!ass->aname.name) |
| 567 | + return; |
| 568 | + |
| 569 | + mono_alc_assemblies_lock (alc); |
| 570 | + for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) { |
| 571 | + if (tmp->data == ass) { |
| 572 | + mono_alc_assemblies_unlock (alc); |
| 573 | + return; |
| 574 | + } |
| 575 | + } |
| 576 | + |
| 577 | + mono_assembly_addref (ass); |
| 578 | + // Prepending here will break the test suite with frequent InvalidCastExceptions, so we have to append |
| 579 | + alc->loaded_assemblies = g_slist_append (alc->loaded_assemblies, ass); |
| 580 | + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to ALC (%p), ref_count=%d", ass->aname.name, ass, (gpointer)alc, ass->ref_count); |
| 581 | + mono_alc_assemblies_unlock (alc); |
| 582 | + |
| 583 | + alcs_lock (); |
| 584 | + loaded_assemblies = g_slist_append (loaded_assemblies, ass); |
| 585 | + alcs_unlock (); |
| 586 | +} |
| 587 | + |
| 588 | +MonoAssembly* |
| 589 | +mono_alc_find_assembly (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname) |
| 590 | +{ |
| 591 | + GSList *tmp; |
| 592 | + MonoAssembly *ass; |
| 593 | + |
| 594 | + const MonoAssemblyNameEqFlags eq_flags = MONO_ANAME_EQ_IGNORE_PUBKEY | MONO_ANAME_EQ_IGNORE_VERSION | MONO_ANAME_EQ_IGNORE_CASE; |
| 595 | + |
| 596 | + mono_alc_assemblies_lock (alc); |
| 597 | + for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) { |
| 598 | + ass = (MonoAssembly *)tmp->data; |
| 599 | + g_assert (ass != NULL); |
| 600 | + // FIXME: Can dynamic assemblies match here for netcore? |
| 601 | + if (assembly_is_dynamic (ass) || !mono_assembly_names_equal_flags (aname, &ass->aname, eq_flags)) |
| 602 | + continue; |
| 603 | + |
| 604 | + mono_alc_assemblies_unlock (alc); |
| 605 | + return ass; |
| 606 | + } |
| 607 | + mono_alc_assemblies_unlock (alc); |
| 608 | + return NULL; |
| 609 | +} |
| 610 | + |
| 611 | +/* |
| 612 | + * mono_alc_get_all_loaded_assemblies: |
| 613 | + * |
| 614 | + * Return a list of loaded assemblies in all appdomains. |
| 615 | + */ |
| 616 | +GPtrArray* |
| 617 | +mono_alc_get_all_loaded_assemblies (void) |
| 618 | +{ |
| 619 | + GSList *tmp; |
| 620 | + GPtrArray *assemblies; |
| 621 | + MonoAssembly *ass; |
| 622 | + |
| 623 | + assemblies = g_ptr_array_new (); |
| 624 | + alcs_lock (); |
| 625 | + for (tmp = loaded_assemblies; tmp; tmp = tmp->next) { |
| 626 | + ass = (MonoAssembly *)tmp->data; |
| 627 | + g_ptr_array_add (assemblies, ass); |
| 628 | + } |
| 629 | + alcs_unlock (); |
| 630 | + return assemblies; |
| 631 | +} |
0 commit comments