mono_assembly_name_free_internal (MonoAssemblyName *aname);
gboolean
+mono_assembly_name_culture_is_neutral (const MonoAssemblyName *aname);
+
+gboolean
mono_assembly_names_equal_flags (MonoAssemblyName *l, MonoAssemblyName *r, MonoAssemblyNameEqFlags flags);
gboolean
#include "config.h"
+#include "mono/metadata/assembly.h"
#include "mono/metadata/domain-internals.h"
#include "mono/metadata/icall-decl.h"
#include "mono/metadata/loader-internals.h"
#include "mono/metadata/loaded-images-internals.h"
#include "mono/utils/mono-error-internals.h"
+#include "mono/utils/mono-logger-internals.h"
#ifdef ENABLE_NETCORE
/* MonoAssemblyLoadContext support only in netcore Mono */
+static
+GENERATE_GET_CLASS_WITH_CACHE_DECL (assembly_load_context);
+
+GENERATE_GET_CLASS_WITH_CACHE (assembly_load_context, "System.Runtime.Loader", "AssemblyLoadContext");
+
void
mono_alc_init (MonoAssemblyLoadContext *alc, MonoDomain *domain)
{
if (is_default_alc) {
alc = mono_domain_default_alc (domain);
g_assert (alc);
+ if (!alc->gchandle)
+ alc->gchandle = this_gchandle;
} else {
/* create it */
alc = mono_domain_create_individual_alc (domain, this_gchandle, collectible, error);
return alc;
}
+gpointer
+ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly (MonoReflectionAssemblyHandle assm_obj, MonoError *error)
+{
+ MonoAssembly *assm = MONO_HANDLE_GETVAL (assm_obj, assembly);
+ MonoAssemblyLoadContext *alc = mono_assembly_get_alc (assm);
+
+ return GUINT_TO_POINTER (alc->gchandle);
+}
+
+gboolean
+mono_alc_is_default (MonoAssemblyLoadContext *alc)
+{
+ return alc == mono_alc_domain (alc)->default_alc;
+}
+
+static MonoAssembly*
+invoke_resolve_method (MonoMethod *resolve_method, MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
+{
+ MonoAssembly *result = NULL;
+ char* aname_str = NULL;
+ HANDLE_FUNCTION_ENTER ();
+
+ aname_str = mono_stringify_assembly_name (aname);
+
+ MonoStringHandle aname_obj = mono_string_new_handle (mono_domain_get (), aname_str, error);
+ goto_if_nok (error, leave);
+
+ MonoReflectionAssemblyHandle assm;
+ gpointer args[2];
+ args [0] = GUINT_TO_POINTER (alc->gchandle);
+ args [1] = MONO_HANDLE_RAW (aname_obj);
+ assm = MONO_HANDLE_CAST (MonoReflectionAssembly, mono_runtime_try_invoke_handle (resolve_method, NULL_HANDLE, args, error));
+ goto_if_nok (error, leave);
+
+ if (MONO_HANDLE_BOOL (assm))
+ result = MONO_HANDLE_GETVAL (assm, assembly);
+
+leave:
+ g_free (aname_str);
+ HANDLE_FUNCTION_RETURN_VAL (result);
+}
+
+static MonoAssembly*
+mono_alc_invoke_resolve_using_load (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
+{
+ static MonoMethod *resolve;
+
+ if (!resolve) {
+ ERROR_DECL (local_error);
+ MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
+ g_assert (alc_class);
+ MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingLoad", -1, 0, local_error);
+ mono_error_assert_ok (local_error);
+ resolve = m;
+ }
+ g_assert (resolve);
+
+ return invoke_resolve_method (resolve, alc, aname, error);
+}
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
+{
+ MonoAssembly *result = NULL;
+ ERROR_DECL (error);
+
+ result = mono_alc_invoke_resolve_using_load (alc, aname, error);
+ if (!is_ok (error))
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Load(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
+
+ mono_error_cleanup (error);
+
+ return result;
+}
+
+static MonoAssembly*
+mono_alc_invoke_resolve_using_resolving_event (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
+{
+ static MonoMethod *resolve;
+
+ if (!resolve) {
+ ERROR_DECL (local_error);
+ MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
+ g_assert (alc_class);
+ MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolvingEvent", -1, 0, local_error);
+ mono_error_assert_ok (local_error);
+ resolve = m;
+ }
+ g_assert (resolve);
+
+ return invoke_resolve_method (resolve, alc, aname, error);
+}
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
+{
+ MonoAssembly *result = NULL;
+ ERROR_DECL (error);
+
+ result = mono_alc_invoke_resolve_using_resolving_event (alc, aname, error);
+ if (!is_ok (error))
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC Resolving(\"%s\") event: '%s'", aname->name, mono_error_get_message (error));
+
+ mono_error_cleanup (error);
+
+ return result;
+}
+
+static MonoAssembly*
+mono_alc_invoke_resolve_using_resolve_satellite (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error)
+{
+ static MonoMethod *resolve;
+
+ if (!resolve) {
+ ERROR_DECL (local_error);
+ MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
+ g_assert (alc_class);
+ MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUsingResolveSatelliteAssembly", -1, 0, local_error);
+ mono_error_assert_ok (local_error);
+ resolve = m;
+ }
+ g_assert (resolve);
+
+ return invoke_resolve_method (resolve, alc, aname, error);
+}
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname)
+{
+ MonoAssembly *result = NULL;
+ ERROR_DECL (error);
+
+ result = mono_alc_invoke_resolve_using_resolve_satellite (alc, aname, error);
+ if (!is_ok (error))
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC ResolveSatelliteAssembly(\"%s\") method: '%s'", aname->name, mono_error_get_message (error));
+
+ mono_error_cleanup (error);
+
+ return result;
+}
+
+
+
#endif /* ENABLE_NETCORE */
}
}
+#ifndef ENABLE_NETCORE
static MonoAssembly*
load_reference_by_aname_refonly_asmctx (MonoAssemblyName *aname, MonoAssembly *assm, MonoImageOpenStatus *status)
{
reference = (MonoAssembly*)REFERENCE_MISSING;
return reference;
}
+#else
+static MonoAssembly*
+netcore_load_reference (MonoAssemblyName *aname, MonoAssemblyLoadContext *alc, MonoAssembly *requesting, MonoImageOpenStatus *status)
+{
+ g_assert (status != NULL);
+ g_assert (requesting != NULL);
+ g_assert (alc != NULL);
+
+ MonoAssemblyName mapped_aname;
+ MonoAssemblyName mapped_name_pp;
+
+ aname = mono_assembly_remap_version (aname, &mapped_aname);
+ /* FIXME: netcore doesn't have binding redirects */
+ aname = mono_assembly_apply_binding (aname, &mapped_name_pp);
+
+ MonoAssembly *reference = NULL;
+
+ gboolean is_satellite = !mono_assembly_name_culture_is_neutral (aname);
+ gboolean is_default = mono_alc_is_default (alc);
+
+ /*
+ * Try these until one of them succeeds (by returning a non-NULL reference):
+ * 1. Check if it's already loaded by the ALC.
+ * 2. If it's a non-default ALC, call the Load() method.
+ *
+ * 3. Try to load using the default ALC.
+ *
+ * 4. Call ALC Resolving event.
+ *
+ * 5. Return REFERNCE_MISSING
+ */
+
+ reference = mono_assembly_loaded_internal (alc, aname, FALSE);
+ if (reference)
+ goto leave;
+
+ if (!is_default)
+ reference = mono_alc_invoke_resolve_using_load_nofail (alc, aname);
+ if (reference)
+ goto leave;
+
+ if (is_default || !is_satellite) {
+ MonoAssemblyByNameRequest req;
+ mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_DEFAULT);
+ req.request.alc = mono_domain_default_alc (mono_alc_domain (alc));
+ req.requesting_assembly = requesting;
+ reference = mono_assembly_request_byname (aname, &req, status);
+ if (reference)
+ goto leave;
+ }
+
+ if (is_satellite) {
+ reference = mono_alc_invoke_resolve_using_resolve_satellite_nofail (alc, aname);
+ if (reference)
+ goto leave;
+ }
+
+ reference = mono_alc_invoke_resolve_using_resolving_event_nofail (alc, aname);
+ if (reference)
+ goto leave;
+
+ reference = (MonoAssembly*)REFERENCE_MISSING;
+
+leave:
+ return reference;
+}
+
+#endif /* ENABLE_NETCORE */
/**
* mono_assembly_get_assemblyref:
aname_str);
g_free (aname_str);
}
+#ifndef ENABLE_NETCORE
switch (mono_asmctx_get_kind (&image->assembly->context)) {
case MONO_ASMCTX_DEFAULT:
reference = load_reference_by_aname_default_asmctx (&aname, mono_image_get_alc (image), image->assembly, &status);
g_error ("Unexpected assembly load context kind %d for image %s.", mono_asmctx_get_kind (&image->assembly->context), image->name);
break;
}
+#else
+ reference = netcore_load_reference (&aname, mono_image_get_alc (image), image->assembly, &status);
+#endif
} else {
+#ifndef ENABLE_NETCORE
/* FIXME: can we establish that image->assembly is never NULL and this code is dead? */
reference = load_reference_by_aname_default_asmctx (&aname, mono_image_get_alc (image), image->assembly, &status);
+#else
+ g_assertf (image->assembly, "While loading reference %d MonoImage %s doesn't have a MonoAssembly", index, image->name);
+#endif
}
if (reference == NULL){
return aname->major;
}
+gboolean
+mono_assembly_name_culture_is_neutral (const MonoAssemblyName *aname)
+{
+ return (!aname->culture || aname->culture [0] == 0);
+}
+
static MonoAssembly*
probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
{
{
g_assert (!collectible); /* TODO: implement collectible ALCs */
MonoAssemblyLoadContext *alc = create_alc (domain, FALSE);
+ alc->gchandle = this_gchandle;
return alc;
}
#endif
HANDLES(MARSHAL_41, "copy_from_unmanaged_fixed", ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged, void, 5, (gconstpointer, gint32, MonoArray, gint32, gpointer))
HANDLES(MARSHAL_42, "copy_to_unmanaged_fixed", ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged, void, 5, (MonoArray, gint32, gpointer, gint32, gconstpointer))
-ICALL_TYPE(ALC, "System.Runtime.Loader.AssemblyLoadContext", ALC_4)
+ICALL_TYPE(ALC, "System.Runtime.Loader.AssemblyLoadContext", ALC_5)
+HANDLES(ALC_5, "GetLoadContextForAssembly", ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly, gpointer, 1, (MonoReflectionAssembly))
HANDLES(ALC_4, "InternalGetLoadedAssemblies", ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies, MonoArray, 0, ())
HANDLES(ALC_2, "InternalInitializeNativeALC", ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC, gpointer, 3, (gpointer, MonoBoolean, MonoBoolean))
HANDLES(ALC_1, "InternalLoadFile", ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalLoadFile, MonoReflectionAssembly, 3, (gpointer, MonoString, MonoStackCrawlMark_ptr))
#define _MONO_METADATA_LOADER_INTERNALS_H_
#include <glib.h>
+#include <mono/metadata/image.h>
#include <mono/metadata/object-forward.h>
#include <mono/utils/mono-forward.h>
#include <mono/utils/mono-error.h>
GSList *loaded_assemblies;
MonoCoopMutex assemblies_lock;
#endif
+ /* Handle of the corresponding managed object. If the ALC is
+ * collectible, the handle is weak, otherwise it's strong.
+ */
+ uint32_t gchandle;
};
#endif /* ENABLE_NETCORE */
{
return alc->domain;
}
+
+gboolean
+mono_alc_is_default (MonoAssemblyLoadContext *alc);
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_load_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname);
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname);
+
+MonoAssembly*
+mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname);
+
#endif /* ENABLE_NETCORE */
MonoLoadedImages *
# relies on AssemblyLoadContext
-nomethod System.Runtime.Loader.Tests.SatelliteAssembliesTests.SatelliteLoadsCorrectly
--nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.*
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetLoadContextTest_ValidUserAssembly
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.LoadAssemblyByPath_ValidUserAssembly
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.Unsupported_FixedAddressValueType
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.LoadAssemblyByStream_ValidUserAssembly
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.LoadFromAssemblyName_ValidTrustedPlatformAssembly
-nomethod System.Runtime.Loader.Tests.ContextualReflectionTest.*
-nomethod System.Runtime.Loader.Tests.SatelliteAssembliesTests.describeLib
+# relies on collectible AssemblyLoadContext
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.Unload_*
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.Finalizer_CollectibleWithNoAssemblyLoaded
+-nomethod System.Runtime.Loader.Tests.AssemblyLoadContextTest.PublicConstructor_Theory
+
####################################################################
## System.Reflection.MetadataLoadContext.Tests
####################################################################
<!-- appdomain.c mono_object_new_checked in mono_domain_create_appdomain_checked -->
<method signature="System.Void .ctor()" />
</type>
+
+ <!-- assembly-load-context.c: -->
+ <type fullname="System.Runtime.Loader.AssemblyLoadContext">
+ <!-- assembly-load-context.c: mono_alc_invoke_resolve_using_load -->
+ <method name="MonoResolveUsingLoad" />
+ <!-- assembly-load-context.c: mono_alc_invoke_resolve_using_resolving_event -->
+ <method name="MonoResolveUsingResolvingEvent" />
+ <!-- assembly-load-context.c: mono_alc_invoke_resolve_using_resolve_satellite -->
+ <method name="MonoResolveUsingResolveSatelliteAssembly" />
+ </type>
<!-- marshal.c: emit_marshal_custom (should not be used on devices)
<type fullname="System.ApplicationException" />
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern object GetFilesInternal (String name, bool getResourceModules);
+
+ internal string? GetSimpleName ()
+ {
+ // TODO: Make this cheaper and faster
+ return GetName ().Name;
+ }
}
}
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
namespace System.Runtime.Loader
return InternalGetLoadedAssemblies ();
}
- public static AssemblyLoadContext GetLoadContext (Assembly assembly)
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ extern static IntPtr GetLoadContextForAssembly (RuntimeAssembly rtAsm);
+
+ // Returns the load context in which the specified assembly has been loaded
+ public static AssemblyLoadContext? GetLoadContext (Assembly assembly)
{
- throw new NotImplementedException ();
+ if (assembly == null)
+ throw new ArgumentNullException (nameof (assembly));
+
+ AssemblyLoadContext? loadContextForAssembly = null;
+
+ RuntimeAssembly? rtAsm = assembly as RuntimeAssembly;
+
+ // We only support looking up load context for runtime assemblies.
+ if (rtAsm != null) {
+ RuntimeAssembly runtimeAssembly = rtAsm;
+ IntPtr ptrAssemblyLoadContext = GetLoadContextForAssembly (runtimeAssembly);
+ if (ptrAssemblyLoadContext == IntPtr.Zero)
+ {
+ // If the load context is returned null, then the assembly was bound using the TPA binder
+ // and we shall return reference to the active "Default" binder - which could be the TPA binder
+ // or an overridden CLRPrivBinderAssemblyLoadContext instance.
+ loadContextForAssembly = AssemblyLoadContext.Default;
+ } else {
+ loadContextForAssembly = (AssemblyLoadContext) (GCHandle.FromIntPtr (ptrAssemblyLoadContext).Target)!;
+ }
+ }
+
+ return loadContextForAssembly;
}
public void SetProfileOptimizationRoot (string directoryPath)
{
return AssemblyResolve (null, new ResolveEventArgs (name));
}
+
+ // Invoked by Mono to resolve using the load method.
+ private static Assembly? MonoResolveUsingLoad (IntPtr gchALC, string assemblyName)
+ {
+ return Resolve (gchALC, new AssemblyName (assemblyName));
+ }
+
+ // Invoked by Mono to resolve using the Resolving event after
+ // trying the Load overried and TPA load context without
+ // success.
+ private static Assembly? MonoResolveUsingResolvingEvent (IntPtr gchALC, string assemblyName)
+ {
+ return ResolveUsingResolvingEvent (gchALC, new AssemblyName (assemblyName));
+ }
+
+ // Invoked by Mono to resolve using the Resolving event after
+ // trying the Load overried and TPA load context without
+ // success.
+ private static Assembly? MonoResolveUsingResolveSatelliteAssembly (IntPtr gchALC, string assemblyName)
+ {
+ return ResolveSatelliteAssembly (gchALC, new AssemblyName (assemblyName));
+ }
+
+
+#region Copied from AssemblyLoadContext.CoreCLR.cs
+ // WISH: let's share this code
+
+ // This method is invoked by the VM when using the host-provided assembly load context
+ // implementation.
+ private static Assembly? Resolve(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
+ {
+ AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!;
+
+ return context.ResolveUsingLoad(assemblyName);
+ }
+
+ // This method is invoked by the VM to resolve an assembly reference using the Resolving event
+ // after trying assembly resolution via Load override and TPA load context without success.
+ private static Assembly? ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
+ {
+ AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!;
+
+ // Invoke the AssemblyResolve event callbacks if wired up
+ return context.ResolveUsingEvent(assemblyName);
+ }
+
+ // This method is invoked by the VM to resolve a satellite assembly reference
+ // after trying assembly resolution via Load override without success.
+ private static Assembly? ResolveSatelliteAssembly(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
+ {
+ AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!;
+
+ // Invoke the ResolveSatelliteAssembly method
+ return context.ResolveSatelliteAssembly(assemblyName);
+ }
+
+ private Assembly? GetFirstResolvedAssembly(AssemblyName assemblyName)
+ {
+ Assembly? resolvedAssembly = null;
+
+ Func<AssemblyLoadContext, AssemblyName, Assembly>? assemblyResolveHandler = _resolving;
+
+ if (assemblyResolveHandler != null)
+ {
+ // Loop through the event subscribers and return the first non-null Assembly instance
+ foreach (Func<AssemblyLoadContext, AssemblyName, Assembly> handler in assemblyResolveHandler.GetInvocationList())
+ {
+ resolvedAssembly = handler(this, assemblyName);
+ if (resolvedAssembly != null)
+ {
+ return resolvedAssembly;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Assembly ValidateAssemblyNameWithSimpleName(Assembly assembly, string? requestedSimpleName)
+ {
+ // Get the name of the loaded assembly
+ string? loadedSimpleName = null;
+
+ // Derived type's Load implementation is expected to use one of the LoadFrom* methods to get the assembly
+ // which is a RuntimeAssembly instance. However, since Assembly type can be used build any other artifact (e.g. AssemblyBuilder),
+ // we need to check for RuntimeAssembly.
+ RuntimeAssembly? rtLoadedAssembly = assembly as RuntimeAssembly;
+ if (rtLoadedAssembly != null)
+ {
+ loadedSimpleName = rtLoadedAssembly.GetSimpleName();
+ }
+
+ // The simple names should match at the very least
+ if (string.IsNullOrEmpty(requestedSimpleName))
+ {
+ throw new ArgumentException(SR.ArgumentNull_AssemblyNameName);
+ }
+ if (string.IsNullOrEmpty(loadedSimpleName) || !requestedSimpleName.Equals(loadedSimpleName, StringComparison.InvariantCultureIgnoreCase))
+ {
+ throw new InvalidOperationException(SR.Argument_CustomAssemblyLoadContextRequestedNameMismatch);
+ }
+
+ return assembly;
+ }
+
+ private Assembly? ResolveUsingLoad(AssemblyName assemblyName)
+ {
+ string? simpleName = assemblyName.Name;
+ Assembly? assembly = Load(assemblyName);
+
+ if (assembly != null)
+ {
+ assembly = ValidateAssemblyNameWithSimpleName(assembly, simpleName);
+ }
+
+ return assembly;
+ }
+
+ private Assembly? ResolveUsingEvent(AssemblyName assemblyName)
+ {
+ string? simpleName = assemblyName.Name;
+
+ // Invoke the AssemblyResolve event callbacks if wired up
+ Assembly? assembly = GetFirstResolvedAssembly(assemblyName);
+ if (assembly != null)
+ {
+ assembly = ValidateAssemblyNameWithSimpleName(assembly, simpleName);
+ }
+
+ return assembly;
+ }
+#endregion
}
}