summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve MacLean <stmaclea@microsoft.com>2019-04-11 00:20:39 -0400
committerGitHub <noreply@github.com>2019-04-11 00:20:39 -0400
commit206f9680303134731862a35338618f2cbd225651 (patch)
tree19100fe89a23239d36c6ddd2669f110d58a88aaa
parentcb22707acb620e93a30254ded3048912a9ccb26f (diff)
downloadcoreclr-206f9680303134731862a35338618f2cbd225651.tar.gz
coreclr-206f9680303134731862a35338618f2cbd225651.tar.bz2
coreclr-206f9680303134731862a35338618f2cbd225651.zip
Contextual reflection (#23740)
* Add ContextualReflection APIs Add ContextualReflection APIs approved in dotnet/corefx#36236 Fix issue #22213 * SetParentAssembly even when IsCollectible() * ContextualReflection tests * PR Feedback * Add more usage tests Add using statement tests Add bad usage tests including Assert.Throws<> * Only initialize on set * Add XML API comments * Unify VerifyIsolation * Fix unused expectedAssembly * Remove ContextualReflectionScope throw * Clean up TestResolveMissingAssembly et. al * Remove unused QCall::AppDomainHandle * Remove AppDomainBaseObject * Pass AssemblyLoadContext as managed object to native * Fix AssemblyLoadContextBaseObject packing * AssemblyLoadContext backing stores Use explicit backing stores for events and properties * Remove StaticAsyncLocalCurrentContextualReflectionContext * Remove PermissionSetObject
-rw-r--r--src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs3
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs178
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs10
-rw-r--r--src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs34
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs4
-rw-r--r--src/System.Private.CoreLib/src/System/RuntimeHandles.cs10
-rw-r--r--src/System.Private.CoreLib/src/System/TypeNameParser.cs9
-rw-r--r--src/strongname/api/common.h2
-rw-r--r--src/vm/assemblynative.cpp44
-rw-r--r--src/vm/assemblynative.hpp4
-rw-r--r--src/vm/common.h2
-rw-r--r--src/vm/mscorlib.h10
-rw-r--r--src/vm/object.h52
-rw-r--r--src/vm/qcall.cpp22
-rw-r--r--src/vm/qcall.h29
-rw-r--r--src/vm/runtimehandles.cpp15
-rw-r--r--src/vm/runtimehandles.h2
-rw-r--r--src/vm/typeparse.cpp19
-rw-r--r--src/vm/vars.hpp3
-rw-r--r--tests/src/Loader/ContextualReflection/ContextualReflection.cs748
-rw-r--r--tests/src/Loader/ContextualReflection/ContextualReflection.csproj18
-rw-r--r--tests/src/Loader/ContextualReflection/ContextualReflectionDependency.cs123
-rw-r--r--tests/src/Loader/ContextualReflection/ContextualReflectionDependency.csproj17
23 files changed, 1236 insertions, 122 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs b/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs
index f328b9c251..270aa6ad65 100644
--- a/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs
+++ b/src/System.Private.CoreLib/shared/System/Activator.RuntimeType.cs
@@ -4,6 +4,7 @@
using System.Reflection;
using System.Globalization;
+using System.Runtime.Loader;
using System.Runtime.Remoting;
using System.Threading;
@@ -126,7 +127,7 @@ namespace System
{
// Classic managed type
assembly = RuntimeAssembly.InternalLoadAssemblyName(
- assemblyName, ref stackMark);
+ assemblyName, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext);
}
}
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs
index 8316e1093e..4efd5dec1d 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
@@ -31,18 +32,33 @@ namespace System.Runtime.Loader
private static readonly Dictionary<long, WeakReference<AssemblyLoadContext>> s_allContexts = new Dictionary<long, WeakReference<AssemblyLoadContext>>();
private static long s_nextId;
- // Indicates the state of this ALC (Alive or in Unloading state)
- private InternalState _state;
-
- // Id used by s_allContexts
- private readonly long _id;
+#region private data members
+ // If you modify any of these fields, you must also update the
+ // AssemblyLoadContextBaseObject structure in object.h
// synchronization primitive to protect against usage of this instance while unloading
private readonly object _unloadLock;
+ private event Func<Assembly, string, IntPtr> _resolvingUnmanagedDll;
+
+ private event Func<AssemblyLoadContext, AssemblyName, Assembly> _resolving;
+
+ private event Action<AssemblyLoadContext> _unloading;
+
+ private readonly string _name;
+
// Contains the reference to VM's representation of the AssemblyLoadContext
private readonly IntPtr _nativeAssemblyLoadContext;
+ // Id used by s_allContexts
+ private readonly long _id;
+
+ // Indicates the state of this ALC (Alive or in Unloading state)
+ private InternalState _state;
+
+ private readonly bool _isCollectible;
+#endregion
+
protected AssemblyLoadContext() : this(false, false, null)
{
}
@@ -58,9 +74,9 @@ namespace System.Runtime.Loader
private protected AssemblyLoadContext(bool representsTPALoadContext, bool isCollectible, string name)
{
// Initialize the VM side of AssemblyLoadContext if not already done.
- IsCollectible = isCollectible;
+ _isCollectible = isCollectible;
- Name = name;
+ _name = name;
// The _unloadLock needs to be assigned after the IsCollectible to ensure proper behavior of the finalizer
// even in case the following allocation fails or the thread is aborted between these two lines.
@@ -103,7 +119,7 @@ namespace System.Runtime.Loader
private void RaiseUnloadEvent()
{
// Ensure that we raise the Unload event only once
- Interlocked.Exchange(ref Unloading, null)?.Invoke(this);
+ Interlocked.Exchange(ref _unloading, null)?.Invoke(this);
}
private void InitiateUnload()
@@ -153,7 +169,17 @@ namespace System.Runtime.Loader
//
// Inputs: Invoking assembly, and library name to resolve
// Returns: A handle to the loaded native library
- public event Func<Assembly, string, IntPtr> ResolvingUnmanagedDll;
+ public event Func<Assembly, string, IntPtr> ResolvingUnmanagedDll
+ {
+ add
+ {
+ _resolvingUnmanagedDll += value;
+ }
+ remove
+ {
+ _resolvingUnmanagedDll -= value;
+ }
+ }
// Event handler for resolving managed assemblies.
// This event is raised if the managed assembly could not be resolved via
@@ -161,9 +187,29 @@ namespace System.Runtime.Loader
//
// Inputs: The AssemblyLoadContext and AssemblyName to be loaded
// Returns: The Loaded assembly object.
- public event Func<AssemblyLoadContext, AssemblyName, Assembly> Resolving;
+ public event Func<AssemblyLoadContext, AssemblyName, Assembly> Resolving
+ {
+ add
+ {
+ _resolving += value;
+ }
+ remove
+ {
+ _resolving -= value;
+ }
+ }
- public event Action<AssemblyLoadContext> Unloading;
+ public event Action<AssemblyLoadContext> Unloading
+ {
+ add
+ {
+ _unloading += value;
+ }
+ remove
+ {
+ _unloading -= value;
+ }
+ }
// Occurs when an Assembly is loaded
public static event AssemblyLoadEventHandler AssemblyLoad;
@@ -180,9 +226,9 @@ namespace System.Runtime.Loader
public static AssemblyLoadContext Default => DefaultAssemblyLoadContext.s_loadContext;
- public bool IsCollectible { get; }
+ public bool IsCollectible { get { return _isCollectible;} }
- public string Name { get; }
+ public string Name { get { return _name;} }
public override string ToString() => "\"" + Name + "\" " + GetType().ToString() + " #" + _id;
@@ -240,7 +286,7 @@ namespace System.Runtime.Loader
// Attempt to load the assembly, using the same ordering as static load, in the current load context.
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return Assembly.Load(assemblyName, ref stackMark, _nativeAssemblyLoadContext);
+ return Assembly.Load(assemblyName, ref stackMark, this);
}
// These methods load assemblies into the current AssemblyLoadContext
@@ -396,6 +442,110 @@ namespace System.Runtime.Loader
throw new InvalidOperationException(SR.AssemblyLoadContext_Verify_NotUnloading);
}
}
+
+ private static AsyncLocal<AssemblyLoadContext> s_asyncLocalCurrent;
+
+ /// <summary>Nullable current AssemblyLoadContext used for context sensitive reflection APIs</summary>
+ /// <remarks>
+ /// This is an advanced setting used in reflection assembly loading scenarios.
+ ///
+ /// There are a set of contextual reflection APIs which load managed assemblies through an inferred AssemblyLoadContext.
+ /// * <see cref="System.Activator.CreateInstance" />
+ /// * <see cref="System.Reflection.Assembly.Load" />
+ /// * <see cref="System.Reflection.Assembly.GetType" />
+ /// * <see cref="System.Type.GetType" />
+ ///
+ /// When CurrentContextualReflectionContext is null, the AssemblyLoadContext is inferred.
+ /// The inference logic is simple.
+ /// * For static methods, it is the AssemblyLoadContext which loaded the method caller's assembly.
+ /// * For instance methods, it is the AssemblyLoadContext which loaded the instance's assembly.
+ ///
+ /// When this property is set, the CurrentContextualReflectionContext value is used by these contextual reflection APIs for loading.
+ ///
+ /// This property is typically set in a using block by
+ /// <see cref="System.Runtime.Loader.AssemblyLoadContext.EnterContextualReflection"/>.
+ ///
+ /// The property is stored in an AsyncLocal&lt;AssemblyLoadContext&gt;. This means the setting can be unique for every async or thread in the process.
+ ///
+ /// For more details see https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/AssemblyLoadContext.ContextualReflection.md
+ /// </remarks>
+ public static AssemblyLoadContext CurrentContextualReflectionContext
+ {
+ get { return s_asyncLocalCurrent?.Value; }
+ }
+
+ private static void SetCurrentContextualReflectionContext(AssemblyLoadContext value)
+ {
+ if (s_asyncLocalCurrent == null)
+ {
+ Interlocked.CompareExchange(ref s_asyncLocalCurrent, new AsyncLocal<AssemblyLoadContext>(), null);
+ }
+ s_asyncLocalCurrent.Value = value;
+ }
+
+ /// <summary>Enter scope using this AssemblyLoadContext for ContextualReflection</summary>
+ /// <returns>A disposable ContextualReflectionScope for use in a using block</returns>
+ /// <remarks>
+ /// Sets CurrentContextualReflectionContext to this instance.
+ /// <see cref="System.Runtime.Loader.AssemblyLoadContext.CurrentContextualReflectionContext"/>
+ ///
+ /// Returns a disposable ContextualReflectionScope for use in a using block. When the using calls the
+ /// Dispose() method, it restores the ContextualReflectionScope to its previous value.
+ /// </remarks>
+ public ContextualReflectionScope EnterContextualReflection()
+ {
+ return new ContextualReflectionScope(this);
+ }
+
+ /// <summary>Enter scope using this AssemblyLoadContext for ContextualReflection</summary>
+ /// <param name="activating">Set CurrentContextualReflectionContext to the AssemblyLoadContext which loaded activating.</param>
+ /// <returns>A disposable ContextualReflectionScope for use in a using block</returns>
+ /// <remarks>
+ /// Sets CurrentContextualReflectionContext to to the AssemblyLoadContext which loaded activating.
+ /// <see cref="System.Runtime.Loader.AssemblyLoadContext.CurrentContextualReflectionContext"/>
+ ///
+ /// Returns a disposable ContextualReflectionScope for use in a using block. When the using calls the
+ /// Dispose() method, it restores the ContextualReflectionScope to its previous value.
+ /// </remarks>
+ public static ContextualReflectionScope EnterContextualReflection(Assembly activating)
+ {
+ return activating != null ?
+ GetLoadContext(activating).EnterContextualReflection() :
+ new ContextualReflectionScope(null);
+ }
+
+ /// <summary>Opaque disposable struct used to restore CurrentContextualReflectionContext</summary>
+ /// <remarks>
+ /// This is an implmentation detail of the AssemblyLoadContext.EnterContextualReflection APIs.
+ /// It is a struct, to avoid heap allocation.
+ /// It is required to be public to avoid boxing.
+ /// <see cref="System.Runtime.Loader.AssemblyLoadContext.EnterContextualReflection"/>
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public struct ContextualReflectionScope : IDisposable
+ {
+ private readonly AssemblyLoadContext _activated;
+ private readonly AssemblyLoadContext _predecessor;
+ private readonly bool _initialized;
+
+ internal ContextualReflectionScope(AssemblyLoadContext activating)
+ {
+ _predecessor = AssemblyLoadContext.CurrentContextualReflectionContext;
+ AssemblyLoadContext.SetCurrentContextualReflectionContext(activating);
+ _activated = activating;
+ _initialized = true;
+ }
+
+ public void Dispose()
+ {
+ if (_initialized)
+ {
+ // Do not clear initialized. Always restore the _predecessor in Dispose()
+ // _initialized = false;
+ AssemblyLoadContext.SetCurrentContextualReflectionContext(_predecessor);
+ }
+ }
+ }
}
internal sealed class DefaultAssemblyLoadContext : AssemblyLoadContext
diff --git a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs
index 4683b88632..42736a91b8 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs
+++ b/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs
@@ -15,13 +15,13 @@ namespace System.Reflection
{
public abstract partial class Assembly : ICustomAttributeProvider, ISerializable
{
- // Locate an assembly by the long form of the assembly name.
+ // Locate an assembly by the long form of the assembly name.
// eg. "Toolbox.dll, version=1.1.10.1220, locale=en, publickey=1234567890123456789012345678901234567890"
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
public static Assembly Load(string assemblyString)
{
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return RuntimeAssembly.InternalLoad(assemblyString, ref stackMark);
+ return RuntimeAssembly.InternalLoad(assemblyString, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext);
}
// Locate an assembly by its name. The name can be strong or
@@ -33,12 +33,12 @@ namespace System.Reflection
throw new ArgumentNullException(nameof(assemblyRef));
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return Load(assemblyRef, ref stackMark, IntPtr.Zero);
+ return Load(assemblyRef, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext);
}
// Locate an assembly by its name. The name can be strong or
// weak. The assembly is loaded into the domain of the caller.
- internal static Assembly Load(AssemblyName assemblyRef, ref StackCrawlMark stackMark, IntPtr ptrLoadContextBinder)
+ internal static Assembly Load(AssemblyName assemblyRef, ref StackCrawlMark stackMark, AssemblyLoadContext assemblyLoadContext)
{
AssemblyName modifiedAssemblyRef = null;
if (assemblyRef.CodeBase != null)
@@ -51,7 +51,7 @@ namespace System.Reflection
modifiedAssemblyRef = assemblyRef;
}
- return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, ref stackMark, ptrLoadContextBinder);
+ return RuntimeAssembly.InternalLoadAssemblyName(modifiedAssemblyRef, ref stackMark, assemblyLoadContext);
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
diff --git a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
index bb889787c1..64622f58a8 100644
--- a/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
+++ b/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
@@ -10,6 +10,7 @@ using System.IO;
using StringBuilder = System.Text.StringBuilder;
using System.Configuration.Assemblies;
using StackCrawlMark = System.Threading.StackCrawlMark;
+using System.Runtime.Loader;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
@@ -149,11 +150,12 @@ namespace System.Reflection
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void GetType(RuntimeAssembly assembly,
- string name,
- bool throwOnError,
- bool ignoreCase,
- ObjectHandleOnStack type,
- ObjectHandleOnStack keepAlive);
+ string name,
+ bool throwOnError,
+ bool ignoreCase,
+ ObjectHandleOnStack type,
+ ObjectHandleOnStack keepAlive,
+ ObjectHandleOnStack assemblyLoadContext);
public override Type GetType(string name, bool throwOnError, bool ignoreCase)
{
@@ -163,7 +165,15 @@ namespace System.Reflection
RuntimeType type = null;
object keepAlive = null;
- GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
+ AssemblyLoadContext assemblyLoadContextStack = AssemblyLoadContext.CurrentContextualReflectionContext;
+
+ GetType(GetNativeHandle(),
+ name,
+ throwOnError,
+ ignoreCase,
+ JitHelpers.GetObjectHandleOnStack(ref type),
+ JitHelpers.GetObjectHandleOnStack(ref keepAlive),
+ JitHelpers.GetObjectHandleOnStack(ref assemblyLoadContextStack));
GC.KeepAlive(keepAlive);
return type;
@@ -293,7 +303,7 @@ namespace System.Reflection
return CustomAttributeData.GetCustomAttributesInternal(this);
}
- internal static RuntimeAssembly InternalLoad(string assemblyString, ref StackCrawlMark stackMark)
+ internal static RuntimeAssembly InternalLoad(string assemblyString, ref StackCrawlMark stackMark, AssemblyLoadContext assemblyLoadContext = null)
{
RuntimeAssembly assembly;
AssemblyName an = CreateAssemblyName(assemblyString, out assembly);
@@ -304,7 +314,7 @@ namespace System.Reflection
return assembly;
}
- return InternalLoadAssemblyName(an, ref stackMark);
+ return InternalLoadAssemblyName(an, ref stackMark, assemblyLoadContext);
}
// Creates AssemblyName. Fills assembly if AssemblyResolve event has been raised.
@@ -327,7 +337,7 @@ namespace System.Reflection
return an;
}
- internal static RuntimeAssembly InternalLoadAssemblyName(AssemblyName assemblyRef, ref StackCrawlMark stackMark, IntPtr ptrLoadContextBinder = default)
+ internal static RuntimeAssembly InternalLoadAssemblyName(AssemblyName assemblyRef, ref StackCrawlMark stackMark, AssemblyLoadContext assemblyLoadContext = null)
{
#if FEATURE_APPX
if (ApplicationModel.IsUap)
@@ -348,7 +358,7 @@ namespace System.Reflection
string codeBase = VerifyCodeBase(assemblyRef.CodeBase);
- return nLoad(assemblyRef, codeBase, null, ref stackMark, true, ptrLoadContextBinder);
+ return nLoad(assemblyRef, codeBase, null, ref stackMark, true, assemblyLoadContext);
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -357,7 +367,7 @@ namespace System.Reflection
RuntimeAssembly assemblyContext,
ref StackCrawlMark stackMark,
bool throwOnFileNotFound,
- IntPtr ptrLoadContextBinder);
+ AssemblyLoadContext assemblyLoadContext = null);
public override bool ReflectionOnly
{
@@ -647,7 +657,7 @@ namespace System.Reflection
// This stack crawl mark is never used because the requesting assembly is explicitly specified,
// so the value could be anything.
StackCrawlMark unused = default;
- RuntimeAssembly retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound, IntPtr.Zero);
+ RuntimeAssembly retAssembly = nLoad(an, null, this, ref unused, throwOnFileNotFound);
if (retAssembly == this)
{
diff --git a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
index 5cabe5158e..c95043b09a 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
@@ -104,7 +104,7 @@ namespace System.Runtime.Loader
{
Assembly resolvedAssembly = null;
- Func<AssemblyLoadContext, AssemblyName, Assembly> assemblyResolveHandler = Resolving;
+ Func<AssemblyLoadContext, AssemblyName, Assembly> assemblyResolveHandler = _resolving;
if (assemblyResolveHandler != null)
{
@@ -200,7 +200,7 @@ namespace System.Runtime.Loader
{
IntPtr resolvedDll = IntPtr.Zero;
- Func<Assembly, string, IntPtr> dllResolveHandler = ResolvingUnmanagedDll;
+ Func<Assembly, string, IntPtr> dllResolveHandler = _resolvingUnmanagedDll;
if (dllResolveHandler != null)
{
diff --git a/src/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 56694c63b8..a2da2be1df 100644
--- a/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.Loader;
using System.Runtime.Serialization;
using System.Threading;
@@ -414,17 +415,17 @@ namespace System
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void GetTypeByName(string name, bool throwOnError, bool ignoreCase, StackCrawlMarkHandle stackMark,
- IntPtr pPrivHostBinder,
+ ObjectHandleOnStack assemblyLoadContext,
bool loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive);
// Wrapper function to reduce the need for ifdefs.
internal static RuntimeType GetTypeByName(string name, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark, bool loadTypeFromPartialName)
{
- return GetTypeByName(name, throwOnError, ignoreCase, ref stackMark, IntPtr.Zero, loadTypeFromPartialName);
+ return GetTypeByName(name, throwOnError, ignoreCase, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext, loadTypeFromPartialName);
}
internal static RuntimeType GetTypeByName(string name, bool throwOnError, bool ignoreCase, ref StackCrawlMark stackMark,
- IntPtr pPrivHostBinder,
+ AssemblyLoadContext assemblyLoadContext,
bool loadTypeFromPartialName)
{
if (name == null || name.Length == 0)
@@ -438,9 +439,10 @@ namespace System
RuntimeType type = null;
object keepAlive = null;
+ AssemblyLoadContext assemblyLoadContextStack = assemblyLoadContext;
GetTypeByName(name, throwOnError, ignoreCase,
JitHelpers.GetStackCrawlMarkHandle(ref stackMark),
- pPrivHostBinder,
+ JitHelpers.GetObjectHandleOnStack(ref assemblyLoadContextStack),
loadTypeFromPartialName, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
GC.KeepAlive(keepAlive);
diff --git a/src/System.Private.CoreLib/src/System/TypeNameParser.cs b/src/System.Private.CoreLib/src/System/TypeNameParser.cs
index 3cd904e8a2..4c96d786fb 100644
--- a/src/System.Private.CoreLib/src/System/TypeNameParser.cs
+++ b/src/System.Private.CoreLib/src/System/TypeNameParser.cs
@@ -6,12 +6,13 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
-using System.Security;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using System.Runtime.Versioning;
+using System.Security;
using System.Text;
using System.Threading;
-using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
namespace System
@@ -192,7 +193,7 @@ namespace System
{
if (throwOnError)
{
- assembly = RuntimeAssembly.InternalLoad(asmName, ref stackMark);
+ assembly = RuntimeAssembly.InternalLoad(asmName, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext);
}
else
{
@@ -200,7 +201,7 @@ namespace System
// Other exceptions like BadImangeFormatException should still fly.
try
{
- assembly = RuntimeAssembly.InternalLoad(asmName, ref stackMark);
+ assembly = RuntimeAssembly.InternalLoad(asmName, ref stackMark, AssemblyLoadContext.CurrentContextualReflectionContext);
}
catch (FileNotFoundException)
{
diff --git a/src/strongname/api/common.h b/src/strongname/api/common.h
index 626d9bb720..4347ebae51 100644
--- a/src/strongname/api/common.h
+++ b/src/strongname/api/common.h
@@ -94,11 +94,11 @@
typedef VPTR(class LoaderAllocator) PTR_LoaderAllocator;
typedef VPTR(class AppDomain) PTR_AppDomain;
-typedef VPTR(class AppDomainBaseObject) PTR_AppDomainBaseObject;
typedef DPTR(class ArrayBase) PTR_ArrayBase;
typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
typedef DPTR(class Assembly) PTR_Assembly;
typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject;
+typedef DPTR(class AssemblyLoadContextBaseObject) PTR_AssemblyLoadContextBaseObject;
typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject;
typedef VPTR(class BaseDomain) PTR_BaseDomain;
typedef DPTR(class MscorlibBinder) PTR_MscorlibBinder;
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
index 9c1e467f2f..66214a17a3 100644
--- a/src/vm/assemblynative.cpp
+++ b/src/vm/assemblynative.cpp
@@ -38,22 +38,24 @@ FCIMPL6(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF
AssemblyBaseObject* requestingAssemblyUNSAFE,
StackCrawlMark* stackMark,
CLR_BOOL fThrowOnFileNotFound,
- INT_PTR ptrLoadContextBinder)
+ AssemblyLoadContextBaseObject *assemblyLoadContextUNSAFE)
{
FCALL_CONTRACT;
struct _gc
{
- ASSEMBLYNAMEREF assemblyName;
- STRINGREF codeBase;
- ASSEMBLYREF requestingAssembly;
- ASSEMBLYREF rv;
+ ASSEMBLYNAMEREF assemblyName;
+ STRINGREF codeBase;
+ ASSEMBLYREF requestingAssembly;
+ ASSEMBLYREF rv;
+ ASSEMBLYLOADCONTEXTREF assemblyLoadContext;
} gc;
- gc.assemblyName = (ASSEMBLYNAMEREF) assemblyNameUNSAFE;
- gc.codeBase = (STRINGREF) codeBaseUNSAFE;
- gc.requestingAssembly = (ASSEMBLYREF) requestingAssemblyUNSAFE;
- gc.rv = NULL;
+ gc.assemblyName = (ASSEMBLYNAMEREF) assemblyNameUNSAFE;
+ gc.codeBase = (STRINGREF) codeBaseUNSAFE;
+ gc.requestingAssembly = (ASSEMBLYREF) requestingAssemblyUNSAFE;
+ gc.rv = NULL;
+ gc.assemblyLoadContext = (ASSEMBLYLOADCONTEXTREF) assemblyLoadContextUNSAFE;
HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
@@ -66,6 +68,8 @@ FCIMPL6(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF
DomainAssembly * pParentAssembly = NULL;
Assembly * pRefAssembly = NULL;
+ INT_PTR ptrLoadContextBinder = (gc.assemblyLoadContext != NULL) ? gc.assemblyLoadContext->GetNativeAssemblyLoadContext() : NULL;
+
if(gc.assemblyName->GetSimpleName() == NULL)
{
if (gc.codeBase == NULL)
@@ -446,7 +450,13 @@ void QCALLTYPE AssemblyNative::LoadTypeForWinRTTypeNameInContext(INT_PTR ptrAsse
}
#endif
-void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
+void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly,
+ LPCWSTR wszName,
+ BOOL bThrowOnError,
+ BOOL bIgnoreCase,
+ QCall::ObjectHandleOnStack retType,
+ QCall::ObjectHandleOnStack keepAlive,
+ QCall::ObjectHandleOnStack pAssemblyLoadContext)
{
CONTRACTL
{
@@ -464,8 +474,20 @@ void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR
BOOL prohibitAsmQualifiedName = TRUE;
+ ICLRPrivBinder * pPrivHostBinder = NULL;
+
+ if (*pAssemblyLoadContext.m_ppObject != NULL)
+ {
+ GCX_COOP();
+ ASSEMBLYLOADCONTEXTREF * pAssemblyLoadContextRef = reinterpret_cast<ASSEMBLYLOADCONTEXTREF *>(pAssemblyLoadContext.m_ppObject);
+
+ INT_PTR nativeAssemblyLoadContext = (*pAssemblyLoadContextRef)->GetNativeAssemblyLoadContext();
+
+ pPrivHostBinder = reinterpret_cast<ICLRPrivBinder *>(nativeAssemblyLoadContext);
+ }
+
// Load the class from this assembly (fail if it is in a different one).
- retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
+ retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, prohibitAsmQualifiedName, pAssembly->GetAssembly(), FALSE, (OBJECTREF*)keepAlive.m_ppObject, pPrivHostBinder);
if (!retTypeHandle.IsNull())
{
diff --git a/src/vm/assemblynative.hpp b/src/vm/assemblynative.hpp
index 0ce2fb2327..12d4ff8658 100644
--- a/src/vm/assemblynative.hpp
+++ b/src/vm/assemblynative.hpp
@@ -37,7 +37,7 @@ public:
AssemblyBaseObject* requestingAssemblyUNSAFE,
StackCrawlMark* stackMark,
CLR_BOOL fThrowOnFileNotFound,
- INT_PTR ptrLoadContextBinder);
+ AssemblyLoadContextBaseObject *assemblyLoadContextUNSAFE);
//
// instance FCALLs
@@ -78,7 +78,7 @@ public:
void QCALLTYPE GetVersion(QCall::AssemblyHandle pAssembly, INT32* pMajorVersion, INT32* pMinorVersion, INT32*pBuildNumber, INT32* pRevisionNumber);
static
- void QCALLTYPE GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive);
+ void QCALLTYPE GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive, QCall::ObjectHandleOnStack pAssemblyLoadContext);
static
void QCALLTYPE GetForwardedType(QCall::AssemblyHandle pAssembly, mdToken mdtExternalType, QCall::ObjectHandleOnStack retType);
diff --git a/src/vm/common.h b/src/vm/common.h
index 61ba2a7514..6fd5a37ad5 100644
--- a/src/vm/common.h
+++ b/src/vm/common.h
@@ -114,11 +114,11 @@
typedef VPTR(class LoaderAllocator) PTR_LoaderAllocator;
typedef VPTR(class AppDomain) PTR_AppDomain;
-typedef VPTR(class AppDomainBaseObject) PTR_AppDomainBaseObject;
typedef DPTR(class ArrayBase) PTR_ArrayBase;
typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
typedef DPTR(class Assembly) PTR_Assembly;
typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject;
+typedef DPTR(class AssemblyLoadContextBaseObject) PTR_AssemblyLoadContextBaseObject;
typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject;
typedef VPTR(class BaseDomain) PTR_BaseDomain;
typedef DPTR(class ClassLoader) PTR_ClassLoader;
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index 32d19cbfa6..ccdec0f110 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -889,6 +889,16 @@ DEFINE_METHOD(UNHANDLED_EVENTARGS, CTOR, .ctor,
DEFINE_CLASS(FIRSTCHANCE_EVENTARGS, ExceptionServices, FirstChanceExceptionEventArgs)
DEFINE_METHOD(FIRSTCHANCE_EVENTARGS, CTOR, .ctor, IM_Exception_RetVoid)
+DEFINE_CLASS_U(Loader, AssemblyLoadContext, AssemblyLoadContextBaseObject)
+DEFINE_FIELD_U(_unloadLock, AssemblyLoadContextBaseObject, _unloadLock)
+DEFINE_FIELD_U(_resolvingUnmanagedDll, AssemblyLoadContextBaseObject, _resovlingUnmanagedDll)
+DEFINE_FIELD_U(_resolving, AssemblyLoadContextBaseObject, _resolving)
+DEFINE_FIELD_U(_unloading, AssemblyLoadContextBaseObject, _unloading)
+DEFINE_FIELD_U(_name, AssemblyLoadContextBaseObject, _name)
+DEFINE_FIELD_U(_nativeAssemblyLoadContext, AssemblyLoadContextBaseObject, _nativeAssemblyLoadContext)
+DEFINE_FIELD_U(_id, AssemblyLoadContextBaseObject, _id)
+DEFINE_FIELD_U(_state, AssemblyLoadContextBaseObject, _state)
+DEFINE_FIELD_U(_isCollectible, AssemblyLoadContextBaseObject, _isCollectible)
DEFINE_CLASS(ASSEMBLYLOADCONTEXT, Loader, AssemblyLoadContext)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVE, Resolve, SM_IntPtr_AssemblyName_RetAssemblyBase)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLL, ResolveUnmanagedDll, SM_Str_IntPtr_RetIntPtr)
diff --git a/src/vm/object.h b/src/vm/object.h
index 590f1e0618..cc0810fc98 100644
--- a/src/vm/object.h
+++ b/src/vm/object.h
@@ -1610,6 +1610,53 @@ class AssemblyBaseObject : public Object
NOINLINE AssemblyBaseObject* GetRuntimeAssemblyHelper(LPVOID __me, DomainAssembly *pAssembly, OBJECTREF keepAlive);
#define FC_RETURN_ASSEMBLY_OBJECT(pAssembly, refKeepAlive) FC_INNER_RETURN(AssemblyBaseObject*, GetRuntimeAssemblyHelper(__me, pAssembly, refKeepAlive))
+// AssemblyLoadContextBaseObject
+// This class is the base class for AssemblyLoadContext
+//
+#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
+#include "pshpack4.h"
+#endif // (defined(_TARGET_X86_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
+class AssemblyLoadContextBaseObject : public Object
+{
+ friend class MscorlibBinder;
+
+ protected:
+ // READ ME:
+ // Modifying the order or fields of this object may require other changes to the
+ // classlib class definition of this object.
+#ifdef _TARGET_64BIT_
+ OBJECTREF _unloadLock;
+ OBJECTREF _resovlingUnmanagedDll;
+ OBJECTREF _resolving;
+ OBJECTREF _unloading;
+ OBJECTREF _name;
+ INT_PTR _nativeAssemblyLoadContext;
+ int64_t _id; // On 64-bit platforms this is a value type so it is placed after references and pointers
+ DWORD _state;
+ CLR_BOOL _isCollectible;
+#else // _TARGET_64BIT_
+ int64_t _id; // On 32-bit platforms this 64-bit value type is larger than a pointer so JIT places it first
+ OBJECTREF _unloadLock;
+ OBJECTREF _resovlingUnmanagedDll;
+ OBJECTREF _resolving;
+ OBJECTREF _unloading;
+ OBJECTREF _name;
+ INT_PTR _nativeAssemblyLoadContext;
+ DWORD _state;
+ CLR_BOOL _isCollectible;
+#endif // _TARGET_64BIT_
+
+ protected:
+ AssemblyLoadContextBaseObject() { LIMITED_METHOD_CONTRACT; }
+ ~AssemblyLoadContextBaseObject() { LIMITED_METHOD_CONTRACT; }
+
+ public:
+ INT_PTR GetNativeAssemblyLoadContext() { LIMITED_METHOD_CONTRACT; return _nativeAssemblyLoadContext; }
+};
+#if (defined(_TARGET_X86_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
+#include "poppack.h"
+#endif // (defined(_TARGET_X86_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
+
// AssemblyNameBaseObject
// This class is the base class for assembly names
//
@@ -1700,12 +1747,12 @@ typedef REF<ReflectFieldObject> REFLECTFIELDREF;
typedef REF<ThreadBaseObject> THREADBASEREF;
-typedef REF<AppDomainBaseObject> APPDOMAINREF;
-
typedef REF<MarshalByRefObjectBaseObject> MARSHALBYREFOBJECTBASEREF;
typedef REF<AssemblyBaseObject> ASSEMBLYREF;
+typedef REF<AssemblyLoadContextBaseObject> ASSEMBLYLOADCONTEXTREF;
+
typedef REF<AssemblyNameBaseObject> ASSEMBLYNAMEREF;
typedef REF<VersionBaseObject> VERSIONREF;
@@ -1753,6 +1800,7 @@ typedef PTR_ReflectMethodObject REFLECTMETHODREF;
typedef PTR_ReflectFieldObject REFLECTFIELDREF;
typedef PTR_ThreadBaseObject THREADBASEREF;
typedef PTR_AssemblyBaseObject ASSEMBLYREF;
+typedef PTR_AssemblyLoadContextBaseObject ASSEMBLYLOADCONTEXTREF;
typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF;
#ifndef DACCESS_COMPILE
diff --git a/src/vm/qcall.cpp b/src/vm/qcall.cpp
index 3b35f9089f..1b7bbda3b7 100644
--- a/src/vm/qcall.cpp
+++ b/src/vm/qcall.cpp
@@ -76,25 +76,3 @@ void QCall::ObjectHandleOnStack::SetGuidArray(const GUID * p, COUNT_T length)
memcpyNoGCRefs(arr->GetDataPtr(), p, length * sizeof(GUID));
Set(arr);
}
-
-//
-// Helpers for passing an AppDomain to a QCall
-//
-
-#ifdef _DEBUG
-
-//---------------------------------------------------------------------------------------
-//
-// Verify that the AppDomain being passed from the BCL is valid for use in a QCall. Note: some additional
-// checks are in System.AppDomain.GetNativeHandle()
-//
-
-void QCall::AppDomainHandle::VerifyDomainHandle() const
-{
- LIMITED_METHOD_CONTRACT;
-
- // System.AppDomain.GetNativeHandle() should ensure that we're not calling through with a null AppDomain pointer.
- _ASSERTE(m_pAppDomain);
-}
-
-#endif // _DEBUG
diff --git a/src/vm/qcall.h b/src/vm/qcall.h
index 3ad328a2e1..dd60bbb158 100644
--- a/src/vm/qcall.h
+++ b/src/vm/qcall.h
@@ -237,35 +237,6 @@ public:
}
};
- // AppDomainHandle is used for passing AppDomains into QCalls via System.AppDomainHandle
- struct AppDomainHandle
- {
- AppDomain *m_pAppDomain;
-
- operator AppDomain *()
- {
- LIMITED_METHOD_CONTRACT;
-#ifdef _DEBUG
- VerifyDomainHandle();
-#endif // _DEBUG
- return m_pAppDomain;
- }
-
- AppDomain *operator->() const
- {
- LIMITED_METHOD_CONTRACT;
-#ifdef _DEBUG
- VerifyDomainHandle();
-#endif // _DEBUG
- return m_pAppDomain;
- }
-
- private:
-#ifdef _DEBUG
- void VerifyDomainHandle() const;
-#endif // _DEBUG
- };
-
struct AssemblyHandle
{
DomainAssembly * m_pAssembly;
diff --git a/src/vm/runtimehandles.cpp b/src/vm/runtimehandles.cpp
index c25bcbf3fe..d0a2b043d9 100644
--- a/src/vm/runtimehandles.cpp
+++ b/src/vm/runtimehandles.cpp
@@ -1415,7 +1415,7 @@ void QCALLTYPE RuntimeTypeHandle::GetTypeByNameUsingCARules(LPCWSTR pwzClassName
void QCALLTYPE RuntimeTypeHandle::GetTypeByName(LPCWSTR pwzClassName, BOOL bThrowOnError, BOOL bIgnoreCase,
QCall::StackCrawlMarkHandle pStackMark,
- ICLRPrivBinder * pPrivHostBinder,
+ QCall::ObjectHandleOnStack pAssemblyLoadContext,
BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType,
QCall::ObjectHandleOnStack keepAlive)
{
@@ -1429,6 +1429,19 @@ void QCALLTYPE RuntimeTypeHandle::GetTypeByName(LPCWSTR pwzClassName, BOOL bThro
COMPlusThrowArgumentNull(W("className"),W("ArgumentNull_String"));
{
+ ICLRPrivBinder * pPrivHostBinder = NULL;
+
+ if (*pAssemblyLoadContext.m_ppObject != NULL)
+ {
+ GCX_COOP();
+ ASSEMBLYLOADCONTEXTREF * pAssemblyLoadContextRef = reinterpret_cast<ASSEMBLYLOADCONTEXTREF *>(pAssemblyLoadContext.m_ppObject);
+
+ INT_PTR nativeAssemblyLoadContext = (*pAssemblyLoadContextRef)->GetNativeAssemblyLoadContext();
+
+ pPrivHostBinder = reinterpret_cast<ICLRPrivBinder *>(nativeAssemblyLoadContext);
+ }
+
+
typeHandle = TypeName::GetTypeManaged(pwzClassName, NULL, bThrowOnError, bIgnoreCase, /*bProhibitAsmQualifiedName =*/ FALSE,
SystemDomain::GetCallersAssembly(pStackMark),
bLoadTypeFromPartialNameHack, (OBJECTREF*)keepAlive.m_ppObject,
diff --git a/src/vm/runtimehandles.h b/src/vm/runtimehandles.h
index 4c2ebdf52d..c83461a8a5 100644
--- a/src/vm/runtimehandles.h
+++ b/src/vm/runtimehandles.h
@@ -177,7 +177,7 @@ public:
static
void QCALLTYPE GetTypeByName(LPCWSTR pwzClassName, BOOL bThrowOnError, BOOL bIgnoreCase,
QCall::StackCrawlMarkHandle pStackMark,
- ICLRPrivBinder * pPrivHostBinder,
+ QCall::ObjectHandleOnStack pAssemblyLoadContext,
BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType,
QCall::ObjectHandleOnStack keepAlive);
diff --git a/src/vm/typeparse.cpp b/src/vm/typeparse.cpp
index 858d9a32d3..0794454be2 100644
--- a/src/vm/typeparse.cpp
+++ b/src/vm/typeparse.cpp
@@ -1507,20 +1507,23 @@ DomainAssembly * LoadDomainAssembly(
spec.SetWindowsRuntimeType(*pssOuterTypeName);
}
- if (pPrivHostBinder)
- {
- spec.SetHostBinder(pPrivHostBinder);
- }
- else if (pRequestingAssembly && (!pRequestingAssembly->IsCollectible()))
+ if (pRequestingAssembly)
{
GCX_PREEMP();
spec.SetParentAssembly(pRequestingAssembly->GetDomainAssembly());
}
- // If the requesting assembly has Fallback LoadContext binder available,
- // then set it up in the AssemblySpec.
- if (pRequestingAssembly != NULL)
+ // Have we been passed the reference to the binder against which this load should be triggered?
+ // If so, then use it to set the fallback load context binder.
+ if (pPrivHostBinder != NULL)
+ {
+ spec.SetFallbackLoadContextBinderForRequestingAssembly(pPrivHostBinder);
+ spec.SetPreferFallbackLoadContextBinder();
+ }
+ else if (pRequestingAssembly != NULL)
{
+ // If the requesting assembly has Fallback LoadContext binder available,
+ // then set it up in the AssemblySpec.
PEFile *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile();
spec.SetFallbackLoadContextBinderForRequestingAssembly(pRequestingAssemblyManifestFile->GetFallbackLoadContextBinder());
}
diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp
index 2c3d978d02..68473b6c1a 100644
--- a/src/vm/vars.hpp
+++ b/src/vm/vars.hpp
@@ -162,8 +162,7 @@ class OBJECTREF {
class ReflectClassBaseObject* m_asReflectClass;
class ExecutionContextObject* m_asExecutionContext;
- class AppDomainBaseObject* m_asAppDomainBase;
- class PermissionSetObject* m_asPermissionSetObject;
+ class AssemblyLoadContextBaseObject* m_asAssemblyLoadContextBase;
};
public:
diff --git a/tests/src/Loader/ContextualReflection/ContextualReflection.cs b/tests/src/Loader/ContextualReflection/ContextualReflection.cs
new file mode 100644
index 0000000000..3356e3df4b
--- /dev/null
+++ b/tests/src/Loader/ContextualReflection/ContextualReflection.cs
@@ -0,0 +1,748 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.Loader;
+using System.Runtime.Remoting;
+using System.Threading.Tasks;
+using TestLibrary;
+
+namespace ContextualReflectionTest
+{
+ class AGenericClass<T>
+ {
+ }
+
+ class Program : IProgram
+ {
+ public AssemblyLoadContext alc { get; set; }
+ public Assembly alcAssembly { get; set; }
+ public Type alcProgramType { get; set; }
+ public IProgram alcProgramInstance { get; set; }
+ public Assembly defaultAssembly { get; set; }
+
+ public static int Main()
+ {
+ Program program = new Program(isolated:false);
+
+ program.RunTests();
+
+ Console.WriteLine("Success");
+
+ return 100;
+ }
+
+ public Program()
+ {
+ InitializeIsolation(true);
+ }
+
+ public Program(bool isolated)
+ {
+ InitializeIsolation(isolated);
+ }
+
+ public void InitializeIsolation(bool isolated)
+ {
+ if (isolated == false)
+ {
+ alc = new AssemblyLoadContext("Isolated", isCollectible: true);
+ defaultAssembly = Assembly.GetExecutingAssembly();
+ alcAssembly = alc.LoadFromAssemblyPath(defaultAssembly.Location);
+
+ Assert.AreEqual(alcAssembly, alc.LoadFromAssemblyName(alcAssembly.GetName()));
+
+ alcProgramType = alcAssembly.GetType("ContextualReflectionTest.Program");
+
+ AssemblyLoadContext.Default.Resolving += TestResolve.ResolvingTestDefault;
+ alc.Resolving += TestResolve.ResolvingTestIsolated;
+
+ alcProgramInstance = (IProgram) Activator.CreateInstance(alcProgramType);
+ }
+ else
+ {
+ alcAssembly = Assembly.GetExecutingAssembly();
+ alc = AssemblyLoadContext.GetLoadContext(alcAssembly);
+ alcProgramType = typeof(Program);
+ alcProgramInstance = this;
+ defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(alcAssembly.GetName());
+ }
+ }
+
+ void VerifyIsolationDefault()
+ {
+ VerifyIsolation();
+ Assert.AreEqual(defaultAssembly, Assembly.GetExecutingAssembly());
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()));
+ Assert.AreNotEqual(alcProgramType, typeof(Program));
+ Assert.AreNotEqual((object)alcProgramInstance, (object)this);
+ }
+
+ void VerifyIsolationAlc()
+ {
+ VerifyIsolation();
+ Assert.AreEqual(alcAssembly, Assembly.GetExecutingAssembly());
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()));
+ Assert.AreEqual(alcProgramType, typeof(Program));
+ Assert.AreEqual((object)alcProgramInstance, (object)this);
+ }
+
+ void VerifyIsolation()
+ {
+ Assert.AreEqual("Default", AssemblyLoadContext.Default.Name);
+
+ Assert.IsNotNull(alc);
+ Assert.IsNotNull(alcAssembly);
+ Assert.IsNotNull(alcProgramType);
+ Assert.IsNotNull(alcProgramInstance);
+
+ Assert.AreEqual("Isolated", alc.Name);
+
+ Assert.AreNotEqual(defaultAssembly, alcAssembly);
+ Assert.AreNotEqual(alc, AssemblyLoadContext.Default);
+
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(alcProgramInstance.alcAssembly));
+ Assert.AreEqual(alcAssembly, alcProgramInstance.alcAssembly);
+ Assert.AreEqual(alcProgramType, alcProgramInstance.alcProgramType);
+ Assert.AreEqual(alcProgramInstance, alcProgramInstance.alcProgramInstance);
+ }
+
+ void VerifyTestResolve()
+ {
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("TestDefaultLoad")));
+ TestResolve.Assert(ResolveEvents.NoEvent, () => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("TestIsolatedLoad")));
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => alc.LoadFromAssemblyName(new AssemblyName("TestIsolatedLoad")));
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => alc.LoadFromAssemblyName(new AssemblyName("TestDefaultLoad")));
+
+ // Make sure failure is not cached
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("TestDefaultLoad")));
+ TestResolve.Assert(ResolveEvents.NoEvent, () => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("TestIsolatedLoad")));
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => alc.LoadFromAssemblyName(new AssemblyName("TestIsolatedLoad")));
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => alc.LoadFromAssemblyName(new AssemblyName("TestDefaultLoad")));
+ }
+
+ void VerifyContextualReflectionProxy()
+ {
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ using (ConntextualReflectionProxy.EnterContextualReflection(alcAssembly))
+ {
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ void VerifyUsingStatementContextualReflectionUsage()
+ {
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ {
+ using IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default);
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ }
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ try
+ {
+ using IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default);
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ throw new InvalidOperationException();
+ }
+ catch
+ {
+ }
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ using IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ using IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default);
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ defaultScope.Dispose();
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ void VerifyBadContextualReflectionUsage()
+ {
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default);
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ defaultScope.Dispose();
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default);
+ Assert.AreEqual(AssemblyLoadContext.Default, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ alcScope.Dispose();
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ defaultScope.Dispose();
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ alcScope.Dispose();
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ {
+ IDisposable alcScope = ConntextualReflectionProxy.EnterContextualReflection(alc);
+ Assert.AreEqual(alc, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ try
+ {
+ IDisposable defaultScope = ConntextualReflectionProxy.EnterContextualReflection((Assembly)null);
+ Assert.AreEqual(null, ConntextualReflectionProxy.CurrentContextualReflectionContext);
+
+ throw new InvalidOperationException();
+ }
+ catch
+ {
+ }
+ }
+
+ Assert.IsNull(ConntextualReflectionProxy.CurrentContextualReflectionContext);
+ }
+
+ void TestResolveMissingAssembly(bool isolated, Action<string> action, bool skipNullIsolated = false)
+ {
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => action("TestDefaultLoad"));
+ if (!skipNullIsolated)
+ TestResolve.Assert(isolated ? ResolveEvents.ExpectedEvent : ResolveEvents.NoEvent, () => action("TestIsolatedLoad"));
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => action("TestDefaultLoad"));
+ TestResolve.Assert(ResolveEvents.NoEvent, () => action("TestIsolatedLoad"));
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => action("TestDefaultLoad"));
+ TestResolve.Assert(ResolveEvents.ExpectedEvent, () => action("TestIsolatedLoad"));
+ }
+ }
+
+ void TestAssemblyLoad(bool isolated)
+ {
+ TestAssemblyLoad(isolated, (string assemblyName) => Assembly.Load(assemblyName));
+ TestAssemblyLoad(isolated, (string assemblyName) => Assembly.Load(new AssemblyName(assemblyName)));
+ }
+
+ void TestAssemblyLoad(bool isolated, Func<string, Assembly> assemblyLoad)
+ {
+ TestResolveMissingAssembly(isolated, (string assemblyName) => assemblyLoad(assemblyName));
+
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ Assembly assembly = assemblyLoad("ContextualReflection");
+
+ Assert.AreEqual(isolated ? alc : AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(assembly));
+
+ Assembly depends = assemblyLoad("ContextualReflectionDependency");
+
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(depends));
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ Assembly assembly = assemblyLoad("ContextualReflection");
+
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(assembly));
+
+ Assembly depends = assemblyLoad("ContextualReflectionDependency");
+
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(depends));
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ Assembly assembly = assemblyLoad("ContextualReflection");
+
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(assembly));
+
+ Assembly depends = assemblyLoad("ContextualReflectionDependency");
+
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(depends));
+ }
+ }
+
+ void TestTypeGetType(bool isolated)
+ {
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName));
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName, throwOnError : false));
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName, throwOnError : false, ignoreCase : false));
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName, assemblyResolver : null, typeResolver : null));
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName, assemblyResolver : null, typeResolver : null, throwOnError : false));
+ TestTypeGetType(isolated, (string typeName) => Type.GetType(typeName, assemblyResolver : null, typeResolver : null, throwOnError : false, ignoreCase : false));
+ }
+
+ void TestTypeGetType(bool isolated, Func<string, System.Type> typeGetType)
+ {
+ TestResolveMissingAssembly(isolated, (string assemblyName) => typeGetType(string.Format("MyType, {0}", assemblyName)));
+
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program");
+
+ Assembly expectedAssembly = Assembly.GetExecutingAssembly();
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(typeof (Program), p);
+ }
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program, ContextualReflection");
+
+ Assembly expectedAssembly = Assembly.GetExecutingAssembly();
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(typeof (Program), p);
+ }
+ {
+ Type g = typeGetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]], ContextualReflection");
+
+ Assembly expectedAssembly = Assembly.GetExecutingAssembly();
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ Assert.AreEqual(isolated ? alc : AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(g.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program");
+
+ Assembly expectedAssembly = Assembly.GetExecutingAssembly();
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(typeof (Program), p);
+ }
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program, ContextualReflection");
+
+ Assembly expectedAssembly = defaultAssembly;
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(p.Assembly));
+ }
+ {
+ Type g = typeGetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]], ContextualReflection");
+
+ Assembly expectedAssembly = defaultAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(g.Assembly));
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(g.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program");
+
+ Assembly expectedAssembly = Assembly.GetExecutingAssembly();
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(typeof (Program), p);
+ }
+ {
+ Type p = typeGetType("ContextualReflectionTest.Program, ContextualReflection");
+
+ Assembly expectedAssembly = alcAssembly;
+
+ Assert.IsNotNull(p);
+ Assert.AreEqual(expectedAssembly, p.Assembly);
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(p.Assembly));
+ }
+ {
+ Type g = typeGetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]], ContextualReflection");
+
+ Assembly expectedAssembly = alcAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(g.Assembly));
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(g.GenericTypeArguments[0].Assembly));
+ }
+ }
+ }
+
+ void TestAssemblyGetType(bool isolated)
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ TestResolveMissingAssembly(isolated,
+ (string assemblyName) => assembly.GetType(string.Format("ContextualReflectionTest.AGenericClass`1[[MyType, {0}]]", assemblyName)));
+
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]", throwOnError : false);
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ Type m = mscorlib.GetType("System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assembly expectedAssembly = mscorlib;
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(expectedAssembly, m.Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]", throwOnError : false);
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assembly expectedAssembly = defaultAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ Type m = mscorlib.GetType("System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assembly expectedAssembly = mscorlib;
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(expectedAssembly, m.Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]", throwOnError : false);
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ Type g = assembly.GetType("ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assembly expectedAssembly = alcAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ Type m = mscorlib.GetType("System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]", throwOnError : false);
+
+ Assembly expectedAssembly = mscorlib;
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(expectedAssembly, m.Assembly);
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ }
+
+ void TestActivatorCreateInstance(bool isolated)
+ {
+ TestResolveMissingAssembly(isolated, (string assemblyName) => Activator.CreateInstance(assemblyName, "MyType"));
+ TestResolveMissingAssembly(isolated,
+ (string assemblyName) => Activator.CreateInstance("System.Private.CoreLib", string.Format("System.Collections.Generic.List`1[[MyType, {0}]]", assemblyName)),
+ skipNullIsolated : true);
+
+ TestResolveMissingAssembly(isolated,
+ (string assemblyName) => Activator.CreateInstance("ContextualReflection", string.Format("ContextualReflectionTest.AGenericClass`1[[MyType, {0}]]", assemblyName)));
+
+ Assembly assembly = Assembly.GetExecutingAssembly();
+
+ using (ConntextualReflectionProxy.EnterContextualReflection((Assembly)null))
+ {
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance("ContextualReflection" , "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = assembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ Assembly expectedAssembly = alcAssembly;
+
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ ObjectHandle objectHandle = Activator.CreateInstance(mscorlib.GetName().Name, "System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type m = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(mscorlib, m.Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(AssemblyLoadContext.Default))
+ {
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = defaultAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance("ContextualReflection" , "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = defaultAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ ObjectHandle objectHandle = Activator.CreateInstance(mscorlib.GetName().Name, "System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type m = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = mscorlib;
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(expectedAssembly, m.Assembly);
+ Assert.AreEqual(AssemblyLoadContext.Default, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ using (ConntextualReflectionProxy.EnterContextualReflection(alc))
+ {
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(assembly, g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(Assembly.GetExecutingAssembly(), g.GenericTypeArguments[0].Assembly);
+ Assert.AreEqual(typeof (Program), g.GenericTypeArguments[0]);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance(null, "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = alcAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(assembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ ObjectHandle objectHandle = Activator.CreateInstance("ContextualReflection" , "ContextualReflectionTest.AGenericClass`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type g = objectHandle.Unwrap().GetType();
+
+ Assembly expectedAssembly = alcAssembly;
+
+ Assert.IsNotNull(g);
+ Assert.AreEqual(expectedAssembly, g.Assembly);
+ Assert.AreEqual(expectedAssembly, g.GenericTypeArguments[0].Assembly);
+ }
+ {
+ Assembly mscorlib = typeof (System.Collections.Generic.List<string>).Assembly;
+
+ ObjectHandle objectHandle = Activator.CreateInstance(mscorlib.GetName().Name, "System.Collections.Generic.List`1[[ContextualReflectionTest.Program, ContextualReflection]]");
+ Type m = objectHandle.Unwrap().GetType();
+
+ Assert.IsNotNull(m);
+ Assert.AreEqual(mscorlib, m.Assembly);
+ Assert.AreEqual(alc, AssemblyLoadContext.GetLoadContext(m.GenericTypeArguments[0].Assembly));
+ }
+ }
+ }
+
+ public void RunTests()
+ {
+ VerifyIsolationDefault();
+ VerifyTestResolve();
+ VerifyContextualReflectionProxy();
+ VerifyUsingStatementContextualReflectionUsage();
+ VerifyBadContextualReflectionUsage();
+
+ RunTests(isolated : false);
+ alcProgramInstance.RunTestsIsolated();
+ }
+
+ public void RunTests(bool isolated)
+ {
+ TestAssemblyLoad(isolated);
+ TestTypeGetType(isolated);
+ TestAssemblyGetType(isolated);
+ TestActivatorCreateInstance(isolated);
+ }
+
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ public void RunTestsIsolated()
+ {
+ VerifyIsolationAlc();
+ RunTests(isolated : true);
+ }
+ }
+}
+
diff --git a/tests/src/Loader/ContextualReflection/ContextualReflection.csproj b/tests/src/Loader/ContextualReflection/ContextualReflection.csproj
new file mode 100644
index 0000000000..6f88de3877
--- /dev/null
+++ b/tests/src/Loader/ContextualReflection/ContextualReflection.csproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <ProjectGuid>{78030DC5-F1A6-4B98-A130-A66F5047FF29}</ProjectGuid>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="ContextualReflection.cs" />
+ <ProjectReference Include="ContextualReflectionDependency.csproj" />
+ <ProjectReference Include="../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.cs b/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.cs
new file mode 100644
index 0000000000..d8fc8ef014
--- /dev/null
+++ b/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.cs
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.Loader;
+
+namespace ContextualReflectionTest
+{
+ public interface IProgram
+ {
+ AssemblyLoadContext alc { get; }
+ Assembly alcAssembly { get; }
+ Type alcProgramType { get; }
+ IProgram alcProgramInstance { get; }
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ void RunTestsIsolated();
+ }
+
+ public class ConntextualReflectionProxy
+ {
+ public static AssemblyLoadContext CurrentContextualReflectionContext
+ {
+ get
+ {
+#if AssemblyLoadContextContextualReflectionFacade
+ return AssemblyLoadContext.CurrentContextualReflectionContext;
+#else
+ Type t = typeof (AssemblyLoadContext);
+
+ object result = t.InvokeMember("CurrentContextualReflectionContext",
+ BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty,
+ null,
+ null,
+ new object [] {});
+
+ return (AssemblyLoadContext) result;
+#endif
+ }
+ }
+
+ static public IDisposable EnterContextualReflection(AssemblyLoadContext alc)
+ {
+#if AssemblyLoadContextContextualReflectionFacade
+ return alc.EnterContextualReflection();
+#else
+ Type t = typeof (AssemblyLoadContext);
+
+ object result = t.InvokeMember("EnterContextualReflection",
+ BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
+ null,
+ alc,
+ new object [] {});
+
+ return (IDisposable) result;
+#endif
+ }
+
+ static public IDisposable EnterContextualReflection(Assembly activating)
+ {
+#if AssemblyLoadContextContextualReflectionFacade
+ return AssemblyLoadContext.EnterContextualReflection(activating);
+#else
+ Type t = typeof (AssemblyLoadContext);
+
+ object result = t.InvokeMember("EnterContextualReflection",
+ BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static,
+ null,
+ null,
+ new object [] {activating});
+
+ return (IDisposable) result;
+#endif
+ }
+ }
+
+ public enum ResolveEvents
+ {
+ NoEvent,
+ ExpectedEvent,
+ };
+
+ public class TestResolve
+ {
+ static public ResolveEvents ResolveEvent { get; set;}
+
+ static public Assembly ResolvingTestDefault(AssemblyLoadContext alc, AssemblyName assemblyName)
+ {
+ if (assemblyName.Name.Contains("TestDefaultLoad") && (ResolveEvent == ResolveEvents.NoEvent))
+ {
+ ResolveEvent = ResolveEvents.ExpectedEvent;
+ }
+ return null;
+ }
+
+ static public Assembly ResolvingTestIsolated(AssemblyLoadContext alc, AssemblyName assemblyName)
+ {
+ if (assemblyName.Name.Contains("TestIsolatedLoad") && (ResolveEvent == ResolveEvents.NoEvent))
+ {
+ ResolveEvent = ResolveEvents.ExpectedEvent;
+ }
+ return null;
+ }
+
+ static public void Assert(ResolveEvents expected, Action action)
+ {
+ ResolveEvent = ResolveEvents.NoEvent;
+ try
+ {
+ action();
+ }
+ catch
+ {
+ }
+ finally
+ {
+ TestLibrary.Assert.AreEqual(expected, ResolveEvent);
+ }
+ }
+ }
+}
diff --git a/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.csproj b/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.csproj
new file mode 100644
index 0000000000..1d8fb64087
--- /dev/null
+++ b/tests/src/Loader/ContextualReflection/ContextualReflectionDependency.csproj
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <CLRTestKind>BuildOnly</CLRTestKind>
+ <ProjectGuid>{95DBE3B0-AA86-4366-BB8A-E04B534365F3}</ProjectGuid>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="ContextualReflectionDependency.cs" />
+ <ProjectReference Include="../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>