[netcore] Implement referenced assembly resolving and ALC.GetLoadContext (mono/mono...
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Fri, 2 Aug 2019 18:06:44 +0000 (14:06 -0400)
committerGitHub <noreply@github.com>
Fri, 2 Aug 2019 18:06:44 +0000 (14:06 -0400)
* [netcore] Implement GetLoadContext

* [netcore] Implement ALC-aware referenced assembly resolution.

The process is described in
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=netcore-3.0#usage-in-the-runtime

We try four things until one of them returns a non-null assembly.

1. Check if the assembly is already loaded in the ALC of the requesting
assembly.
2. If the ALC is not the default ALC, invoke the Load override.
3. Try the default ALC (TPA - trusted platform assemblies) loading.
4. Invoke the Resolving event of the original ALC.

The implementation borrows some managed code from
https://github.com/dotnet/coreclr/blob/mono/mono@8ba2e15201361402acd0ae9710bd37d50785cdfa/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs#L84-L187

It would be nice if that code was shared between the runtimes.

* [runtime] Implement mono_assembly_name_culture_is_neutral

* [netcore] Add mono_alc_invoke_resolve_using_resolve_satellite

* [netcore] Use ResolveSatelliteAssembly for satellite assembly refs

* [netcore] Some AssemblyLoadContextTest tests now pass

System.Runtime.Loader.Tests.AssemblyLoadContextTest.PublicConstructor_Default
System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetAssemblyNameTest_NullParameter
System.Runtime.Loader.Tests.AssemblyLoadContextTest.LoadFromAssemblyName_AssemblyNotFound
System.Runtime.Loader.Tests.AssemblyLoadContextTest.PublicConstructor_Theory (with isCollectible: False)
System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetAssemblyNameTest_ValidAssembly
System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetLoadContextTest_SystemPrivateCorelibAssembly
System.Runtime.Loader.Tests.AssemblyLoadContextTest.DefaultAssemblyLoadContext_Properties
System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetAssemblyNameTest_AssemblyNotFound
System.Runtime.Loader.Tests.AssemblyLoadContextTest.GetLoadContextTest_ValidTrustedPlatformAssembly

Commit migrated from https://github.com/mono/mono/commit/2f2f6c104b2a0115a7fb1ab24673b587c27e4365

src/mono/mono/metadata/assembly-internals.h
src/mono/mono/metadata/assembly-load-context.c
src/mono/mono/metadata/assembly.c
src/mono/mono/metadata/domain.c
src/mono/mono/metadata/icall-def-netcore.h
src/mono/mono/metadata/loader-internals.h
src/mono/netcore/CoreFX.issues.rsp
src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml
src/mono/netcore/System.Private.CoreLib/src/System.Reflection/RuntimeAssembly.cs
src/mono/netcore/System.Private.CoreLib/src/System.Runtime.Loader/AssemblyLoadContext.cs

index 77659a1..75702c8 100644 (file)
@@ -37,6 +37,9 @@ void
 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
index 8f563df..820e4f2 100644 (file)
@@ -1,13 +1,20 @@
 #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)
 {
@@ -40,6 +47,8 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC
        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);
@@ -47,4 +56,147 @@ ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalInitializeNativeALC
        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 */
index 16c7815..c09dde6 100644 (file)
@@ -1464,6 +1464,7 @@ mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *an
        }
 }
 
+#ifndef ENABLE_NETCORE
 static MonoAssembly*
 load_reference_by_aname_refonly_asmctx (MonoAssemblyName *aname, MonoAssembly *assm, MonoImageOpenStatus *status)
 {
@@ -1578,6 +1579,74 @@ load_reference_by_aname_individual_asmctx (MonoAssemblyName *aname, MonoAssembly
                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:
@@ -1662,6 +1731,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                                    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);
@@ -1679,9 +1749,16 @@ mono_assembly_load_reference (MonoImage *image, int index)
                        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){
@@ -3569,6 +3646,12 @@ mono_assembly_name_get_version (MonoAssemblyName *aname, uint16_t *minor, uint16
        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)
 {
index 612db9e..27447d4 100644 (file)
@@ -2098,6 +2098,7 @@ mono_domain_create_individual_alc (MonoDomain *domain, uint32_t this_gchandle, g
 {
        g_assert (!collectible); /* TODO: implement collectible ALCs */
        MonoAssemblyLoadContext *alc = create_alc (domain, FALSE);
+       alc->gchandle = this_gchandle;
        return alc;
 }
 #endif
index cbb1222..15007ec 100644 (file)
@@ -369,7 +369,8 @@ HANDLES(MARSHAL_34, "StructureToPtr", ves_icall_System_Runtime_InteropServices_M
 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))
index de7f2aa..5d4533f 100644 (file)
@@ -6,6 +6,7 @@
 #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>
@@ -22,6 +23,10 @@ struct _MonoAssemblyLoadContext {
        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 */
 
@@ -43,6 +48,19 @@ mono_alc_domain (MonoAssemblyLoadContext *alc)
 {
        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 *
index 2dd4292..9d2ce86 100644 (file)
 
 # 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
 ####################################################################
index 5772c67..8ab7011 100644 (file)
                        <!-- 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" />
index 7c7c205..9a26473 100644 (file)
@@ -441,5 +441,11 @@ namespace System.Reflection
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern object GetFilesInternal (String name, bool getResourceModules);
+
+               internal string? GetSimpleName ()
+               {
+                       // TODO: Make this cheaper and faster
+                       return GetName ().Name;
+               }
        }
 }
index 539e4e4..7c1d7a4 100644 (file)
@@ -5,6 +5,7 @@
 using System.IO;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Threading;
 
 namespace System.Runtime.Loader
@@ -58,9 +59,35 @@ 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)
@@ -87,5 +114,137 @@ namespace System.Runtime.Loader
                {
                        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
        }
 }