diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 23fca9c978202..eb93c4f97c5e5 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -35,8 +35,6 @@ The .NET Foundation licenses this file to you under the MIT license. - true - false false true false @@ -108,8 +106,7 @@ The .NET Foundation licenses this file to you under the MIT license. - - + @@ -258,15 +255,12 @@ The .NET Foundation licenses this file to you under the MIT license. - + - - - @@ -291,8 +285,6 @@ The .NET Foundation licenses this file to you under the MIT license. - - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml deleted file mode 100644 index d5c7c1cddc97c..0000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 8548fbc8caf8b..ead6f8350b277 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -8,7 +8,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/Comparer.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/Comparer.NativeAot.cs index 1b6f63912e5b6..1ced04ab5b910 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/Comparer.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/Comparer.NativeAot.cs @@ -13,9 +13,6 @@ namespace System.Collections.Generic { public abstract partial class Comparer : IComparer, IComparer { - [FeatureSwitchDefinition("System.Collections.Generic.DefaultComparers")] - private static bool SupportsGenericIComparableInterfaces => true; - [Intrinsic] private static Comparer Create() { @@ -24,11 +21,7 @@ private static Comparer Create() // This body serves as a fallback when instantiation-specific implementation is unavailable. // If that happens, the compiler ensures we generate data structures to make the fallback work // when this method is compiled. - if (SupportsGenericIComparableInterfaces) - { - return Unsafe.As>(ComparerHelpers.GetComparer(typeof(T).TypeHandle)); - } - return new ObjectComparer(); + return Unsafe.As>(ComparerHelpers.GetComparer(typeof(T).TypeHandle)); } public static Comparer Default { [Intrinsic] get; } = Create(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.NativeAot.cs index 0e06ab4da79e1..bc61bb13dcab5 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.NativeAot.cs @@ -13,9 +13,6 @@ namespace System.Collections.Generic { public abstract partial class EqualityComparer : IEqualityComparer, IEqualityComparer { - [FeatureSwitchDefinition("System.Collections.Generic.DefaultComparers")] - private static bool SupportsGenericIEquatableInterfaces => true; - [Intrinsic] private static EqualityComparer Create() { @@ -30,11 +27,7 @@ private static EqualityComparer Create() return Unsafe.As>(new StringEqualityComparer()); } - if (SupportsGenericIEquatableInterfaces) - { - return Unsafe.As>(EqualityComparerHelpers.GetComparer(typeof(T).TypeHandle)); - } - return new ObjectEqualityComparer(); + return Unsafe.As>(EqualityComparerHelpers.GetComparer(typeof(T).TypeHandle)); } public static EqualityComparer Default { [Intrinsic] get; } = Create(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs index 59423d258179c..139fe425b4e4b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeType.cs @@ -46,12 +46,6 @@ internal void Free() RuntimeImports.RhHandleFree(_runtimeTypeInfoHandle); } - private static bool IsReflectionDisabled => false; - - private static bool DoNotThrowForNames => AppContext.TryGetSwitch("Switch.System.Reflection.Disabled.DoNotThrowForNames", out bool doNotThrow) && doNotThrow; - private static bool DoNotThrowForAssembly => AppContext.TryGetSwitch("Switch.System.Reflection.Disabled.DoNotThrowForAssembly", out bool doNotThrow) && doNotThrow; - private static bool DoNotThrowForAttributes => AppContext.TryGetSwitch("Switch.System.Reflection.Disabled.DoNotThrowForAttributes", out bool doNotThrow) && doNotThrow; - internal MethodTable* ToMethodTableMayBeNull() => _pUnderlyingEEType; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -72,9 +66,6 @@ internal RuntimeTypeInfo GetRuntimeTypeInfo() [MethodImpl(MethodImplOptions.NoInlining)] private RuntimeTypeInfo InitializeRuntimeTypeInfoHandle() { - if (IsReflectionDisabled) - throw new NotSupportedException(SR.Reflection_Disabled); - RuntimeTypeInfo runtimeTypeInfo = ExecutionDomain.GetRuntimeTypeInfo(_pUnderlyingEEType); // We assume that the RuntimeTypeInfo unifiers pick a winner when multiple threads @@ -648,9 +639,6 @@ public override bool IsInstanceOfType([NotNullWhen(true)] object? o) public override string ToString() { - if (IsReflectionDisabled) - return "0x" + ((nuint)_pUnderlyingEEType).ToString("x"); - return GetRuntimeTypeInfo().ToString(); } @@ -799,17 +787,11 @@ public override bool IsDefined(Type attributeType, bool inherit) public override object[] GetCustomAttributes(bool inherit) { - if (IsReflectionDisabled && DoNotThrowForAttributes) - return Array.Empty(); - return GetRuntimeTypeInfo().GetCustomAttributes(inherit); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { - if (IsReflectionDisabled && DoNotThrowForAttributes) - return Array.Empty(); - return GetRuntimeTypeInfo().GetCustomAttributes(attributeType, inherit); } @@ -817,18 +799,12 @@ public override IEnumerable CustomAttributes { get { - if (IsReflectionDisabled && DoNotThrowForAttributes) - return Array.Empty(); - return GetRuntimeTypeInfo().CustomAttributes; } } public override IList GetCustomAttributesData() { - if (IsReflectionDisabled && DoNotThrowForAttributes) - return Array.Empty(); - return GetRuntimeTypeInfo().GetCustomAttributesData(); } @@ -836,9 +812,6 @@ public override string Name { get { - if (IsReflectionDisabled && DoNotThrowForNames) - return ToString(); - return GetRuntimeTypeInfo().Name; } } @@ -847,9 +820,6 @@ public override string? Namespace { get { - if (IsReflectionDisabled && DoNotThrowForNames) - return null; - return GetRuntimeTypeInfo().Namespace; } } @@ -862,9 +832,6 @@ public override Assembly Assembly { get { - if (IsReflectionDisabled && DoNotThrowForAssembly) - return Assembly.GetExecutingAssembly(); - return GetRuntimeTypeInfo().Assembly; } } diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/ReflectionCoreCallbacksImplementation.cs b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/ReflectionCoreCallbacksImplementation.cs deleted file mode 100644 index ea00cc4394dff..0000000000000 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/ReflectionCoreCallbacksImplementation.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; - -using Internal.Reflection.Augments; -using Internal.Runtime.Augments; - -namespace Internal.Reflection -{ - internal class ReflectionCoreCallbacksImplementation : ReflectionCoreCallbacks - { - public override EnumInfo GetEnumInfo(Type type, Func create) => - create( - RuntimeAugments.GetEnumUnderlyingType(type.TypeHandle), - Array.Empty(), - Array.Empty(), - false); - - public override DynamicInvokeInfo GetDelegateDynamicInvokeInfo(Type type) - => throw new NotSupportedException(SR.Reflection_Disabled); - public override MethodInfo GetDelegateMethod(Delegate del) - => throw new NotSupportedException(SR.Reflection_Disabled); - public override object ActivatorCreateInstance( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type type, bool nonPublic) => throw new NotSupportedException(SR.Reflection_Disabled); - public override object ActivatorCreateInstance( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] - Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture, object?[]? activationAttributes) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Delegate CreateDelegate(Type type, MethodInfo method, bool throwOnBindFailure) => throw new NotSupportedException(SR.Reflection_Disabled); - [RequiresUnreferencedCode("The target method might be removed")] - public override Delegate CreateDelegate(Type type, object target, string method, bool ignoreCase, bool throwOnBindFailure) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Delegate CreateDelegate(Type type, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllMethods)] Type target, string method, bool ignoreCase, bool throwOnBindFailure) => throw new NotSupportedException(SR.Reflection_Disabled); - public override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, RuntimeTypeHandle declaringTypeHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override IntPtr GetFunctionPointer(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override EventInfo GetImplicitlyOverriddenBaseClassEvent(EventInfo e) => throw new NotSupportedException(SR.Reflection_Disabled); - public override MethodInfo GetImplicitlyOverriddenBaseClassMethod(MethodInfo m) => throw new NotSupportedException(SR.Reflection_Disabled); - public override PropertyInfo GetImplicitlyOverriddenBaseClassProperty(PropertyInfo p) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Assembly[] GetLoadedAssemblies() => throw new NotSupportedException(SR.Reflection_Disabled); - public override MethodBase GetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override MethodBase GetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Assembly Load(AssemblyName refName, bool throwOnFileNotFound) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Assembly Load(ReadOnlySpan rawAssembly, ReadOnlySpan pdbSymbolStore) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Assembly Load(string assemblyPath) => throw new NotSupportedException(SR.Reflection_Disabled); - public override void MakeTypedReference(object target, FieldInfo[] flds, out Type type, out int offset) => throw new NotSupportedException(SR.Reflection_Disabled); - public override Assembly GetAssemblyForHandle(RuntimeTypeHandle typeHandle) => new RuntimeAssemblyInfo(typeHandle); - public override void RunClassConstructor(RuntimeTypeHandle typeHandle) => throw new NotSupportedException(SR.Reflection_Disabled); - public override MethodBase GetMethodBaseFromStartAddressIfAvailable(IntPtr methodStartAddress) => null; - } -} diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeAssemblyInfo.cs b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeAssemblyInfo.cs deleted file mode 100644 index 205a3c3b055dc..0000000000000 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Reflection/RuntimeAssemblyInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace Internal.Reflection -{ - internal sealed class RuntimeAssemblyInfo : RuntimeAssembly - { - private readonly RuntimeTypeHandle _moduleType; - - public RuntimeAssemblyInfo(RuntimeTypeHandle moduleType) - { - _moduleType = moduleType; - } - - public override bool Equals(object? o) - { - return o is RuntimeAssemblyInfo other && other._moduleType.Equals(_moduleType); - } - - public override int GetHashCode() - { - return _moduleType.GetHashCode(); - } - - public override IEnumerable CustomAttributes => new List(); - } -} diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs deleted file mode 100644 index e71eebacb6457..0000000000000 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Internal.Reflection; -using Internal.Reflection.Augments; -using Internal.Runtime.Augments; - -namespace Internal.Runtime.CompilerHelpers -{ - public class LibraryInitializer - { - public static void InitializeLibrary() - { - ReflectionAugments.Initialize(new ReflectionCoreCallbacksImplementation()); - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Resources/Strings.resx b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Resources/Strings.resx deleted file mode 100644 index ee0f58a933adf..0000000000000 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/Resources/Strings.resx +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table. - - - This operation is not available because the reflection support was disabled at compile time. - - diff --git a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/System.Private.DisabledReflection.csproj b/src/coreclr/nativeaot/System.Private.DisabledReflection/src/System.Private.DisabledReflection.csproj deleted file mode 100644 index 365bf3356186c..0000000000000 --- a/src/coreclr/nativeaot/System.Private.DisabledReflection/src/System.Private.DisabledReflection.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - false - - - - - - - - - - - diff --git a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/ILLink/ILLink.Substitutions.xml b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/ILLink/ILLink.Substitutions.xml deleted file mode 100644 index 3d124ed9adef5..0000000000000 --- a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/ILLink/ILLink.Substitutions.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/StackTraceMetadata.cs b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/StackTraceMetadata.cs index 15c65d5e9dd63..44ebfc5864c6e 100644 --- a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/StackTraceMetadata.cs +++ b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/Internal/StackTraceMetadata/StackTraceMetadata.cs @@ -70,7 +70,7 @@ public static unsafe string GetMethodNameFromStartAddressIfAvailable(IntPtr meth isStackTraceHidden = false; // We haven't found information in the stack trace metadata tables, but maybe reflection will have this - if (IsReflectionExecutionAvailable() && ReflectionExecution.TryGetMethodMetadataFromStartAddress(methodStartAddress, + if (ReflectionExecution.TryGetMethodMetadataFromStartAddress(methodStartAddress, out MetadataReader reader, out TypeDefinitionHandle typeHandle, out MethodHandle methodHandle)) @@ -125,7 +125,7 @@ public static unsafe string GetMethodNameFromStartAddressIfAvailable(IntPtr meth } // We haven't found information in the stack trace metadata tables, but maybe reflection will have this - if (IsReflectionExecutionAvailable() && ReflectionExecution.TryGetMethodMetadataFromStartAddress(methodStartAddress, + if (ReflectionExecution.TryGetMethodMetadataFromStartAddress(methodStartAddress, out MetadataReader reader, out TypeDefinitionHandle typeHandle, out MethodHandle methodHandle)) @@ -186,9 +186,6 @@ private static string FormatAssemblyName(MetadataReader reader, ScopeReferenceHa return $"{reader.GetString(scopeRef.Name)}, Version={scopeRef.MajorVersion}.{scopeRef.MinorVersion}.{scopeRef.BuildNumber}.{scopeRef.RevisionNumber}"; } - // Can be rewritten to false through a feature switch. - private static bool IsReflectionExecutionAvailable() => true; - /// /// This hashtable supports mapping from module start addresses to per-module method name resolvers. /// diff --git a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj index cc44031e9ac55..cd40e0ec8ba54 100644 --- a/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj +++ b/src/coreclr/nativeaot/System.Private.StackTraceMetadata/src/System.Private.StackTraceMetadata.csproj @@ -4,10 +4,6 @@ false - - - - diff --git a/src/coreclr/nativeaot/docs/reflection-free-mode.md b/src/coreclr/nativeaot/docs/reflection-free-mode.md deleted file mode 100644 index 6b49771fb1b55..0000000000000 --- a/src/coreclr/nativeaot/docs/reflection-free-mode.md +++ /dev/null @@ -1,88 +0,0 @@ -# Reflection-free mode - -Reflection-free mode is a highly experimental mode of the NativeAOT compiler and runtime that greatly reduces the functionality of the reflection APIs and brings a couple interesting benefits as a result. The benefits of this mode are: - -* Greatly reduced size of self contained deployments - a fully self-contained "Hello world" style app compiles to a 1 MB file (on x64) with _no dependencies_. -* Reduced working set and better code locality - parts of the program are more tightly packed together. -* Less metadata for people to reverse engineer - apps compiled in reflection-free mode are as hard to reverse engineer as apps written in e.g. C++. - -Of course the benefits come with a drawback: not all .NET code can work in such environment. In fact, most of the existing code probably won't. Use this mode with caution. https://github.com/dotnet/runtime/issues/67193 tracks potential improvements of this mode. - -To enable reflection-free mode in a project that is already using NativeAOT, add the following property to a `PropertyGroup` in your project file: - -```xml - - true - -``` - -## What's different at compile time with reflection disabled - -When reflection is disabled, the AOT compiler stops emitting data structures that are required to make reflection work at runtime and stops enforcing policies that makes the code more reflection friendly. - -Think of: -* Names of methods, types, parameters are no longer generated into the executable. -* Additional metadata, like list of method parameter types, is no longer generated. -* The compiler no longer generates standalone method bodies that would be suitable for reflection invoke. -* Mapping tables that map method names to native code are no longer generated. -* The implementation of reflection is no longer compiled. - -## Reflection APIs that work in reflection-free mode - -Reflection-free mode **supports a limited set of reflection APIs** that keep their expected semantics. - -* `typeof(SomeType)` will return a `System.Type` that can be compared with results of other `typeof` expressions or results of `Object.GetType()` calls. The patterns commonly used in perf optimizations of generic code (e.g. `typeof(T) == typeof(byte)`) will work fine, and so will `obj.GetType() == typeof(SomeType)`. -* Following APIs on `System.Type` work: `TypeHandle`, `UnderlyingSystemType`, `BaseType`, `IsByRefLike`, `IsValueType`, `GetTypeCode`, `GetHashCode`, `GetElementType`, `GetInterfaces`, `HasElementType`, `IsArray`, `IsByRef`, `IsPointer`, `IsPrimitive`, `IsAssignableFrom`, `IsAssignableTo`, `IsInstanceOfType`. -* `Activator.CreateInstance()` will work. The compiler statically analyzes and expands this to efficient code at compile time. No reflection is involved at runtime. -* `Assembly.GetExecutingAssembly()` will return a `System.Reflection.Assembly` that can be compared with other runtime `Assembly` instances. This is mostly to make it possible to use the `NativeLibrary.SetDllImportResolver` API. - -## Reflection APIs that are up for discussion - -We might be able to add support for the following APIs without sacrificing too much of the goals of the reflection-free mode: - -* `Enum.Parse` and `Enum.ToString`. These methods currently only work with integers (`ToString` returns an integer, and `Parse` can parse integers). Note that `Enum.GetValues` would still not work. -* Type names (`Type.Name`, `Type.Namespace`, `Type.FullName`): We could probably add this back if there's good use cases in an otherwise reflection-free mode. -* `Delegate.DynamicInvoke` can be made to work if there's a good use case too. - -## APIs that don't work and will not work - -* APIs that require dynamic code generation: `Reflection.Emit`, `Assembly.Load` and friends -* Obvious program introspection APIs: APIs on `Type` and `Assembly` not mentioned above, `MethodBase`, `MethodInfo`, `ConstructorInfo`, `FieldInfo`, `PropertyInfo`, `EventInfo`. These APIs will throw at runtime. -* APIs building on top of reflection APIs. Too many to enumerate. - -## Shimming - -Sometimes reflection is used in non-critical paths to retrieve type names. In reflection-free mode, accessing type names throws an exception. To help moving such code to reflection-free mode, we have an AppContext switch to generate fake names and namespaces for types. With this mode enabled, accessing the `Name` and `Namespace` property will not throw, but won't return the actual name either. - -To enable this mode, add following item to an `ItemGroup` in your project file: - -```xml - - - -``` - -To achieve similar result for when querying for ``Assembly`` (will instead give the ExecutingAssembly): - -```xml - - - -``` - -And here for CustomAttributes (will return an empty array): - -```xml - - - -``` - -## Internal implementation - -The reflection-free mode is implemented as a collection of features that can be controlled individually via the AOT compiler command line options for experiments and troubleshooting, including: -- `--scanreflection` (also exposed as `IlcScanReflection` build property): Infer reflection usage by code analysis. This feature is disabled for reflection-free mode. -- `--reflectiondata:none`: Disables generation of reflection data. -- `--feature:System.Collections.Generic.DefaultComparers=false`: Disables `EqualityComparer.Default` and `Comparer.Default` optimizations that are based on reflection. - -The complete set of individual features that the reflection-free mode is composed from currently can be found by looking for `IlcDisableReflection` in [Microsoft.NETCore.Native.targets](../BuildIntegration/Microsoft.NETCore.Native.targets). diff --git a/src/coreclr/nativeaot/docs/reflection-in-aot-mode.md b/src/coreclr/nativeaot/docs/reflection-in-aot-mode.md deleted file mode 100644 index ee3ac192ea371..0000000000000 --- a/src/coreclr/nativeaot/docs/reflection-in-aot-mode.md +++ /dev/null @@ -1,100 +0,0 @@ -# Reflection in AOT mode # - -When .NET code is compiled ahead of time, a typical problem the ahead of time compiler faces is deciding what code to compile and what data structures to generate. - -For static languages such as C or C++, the problem of deciding what to include in the final executable is quite simple: one starts with including `main()` and establishing what other methods and data structures `main()` references. One then includes those references, the references of the references and so on, until there's no reference left to include. This concept is easy to understand and works great for languages like C or C++. Nice side effect of this approach is that the generated program is small. If the code doesn't call into e.g. the `printf` function, the `printf` function is not generated in the final executable. - -Problems with such approach start to show up on platforms that allow unconstrained reflection. Reflection is a mechanism .NET provides that allows developers to inspect the structure of the program at runtime and access/invoke types and their members. With unconstrained reflection, the definition of "program" includes "everything that one would have access to at the time of compiling the program". - -As a motivating example, consider this program: - -```csharp -class Program -{ - public static void Main() - { - Console.Write("Name of type: "); - string typeName = Console.ReadLine(); - - // Allow to exit the program peacefully - if (String.IsNullOrEmpty(typeName)) - return; - - Console.Write("Name of method: "); - string methodName = Console.ReadLine(); - - Type.GetType(typeName).GetMethod(methodName).Invoke(null, null); - } - - public static void SayHello() - { - Console.WriteLine("Hello!"); - } -} -``` - -The above program lets the user invoke any parameterless public static method on any type. For the naive compilation algorithm above, this program would work great for input strings `Program` and `Main` because the algorithm included method `Main` in the final executable. The program wouldn't work so great for inputs `Program` and `SayHello`†, because method `SayHello` wasn't called from anywhere. For the naive algorithm, the only way to fix the program for inputs `Program` and `SayHello` is to add a call to `SayHello` in `Main`. - -> † The behavior for `Type.GetMethod` on type `Program` and method `SayHello` would be to return `null` if `SayHello` wasn't compiled. The reason for this is that `Type.GetMethod` is documented to return `null` if there's no method with a given name, and for the purposes of the program, `SayHello` doesn't exist. The compiler could remember there used to be such method and write the information in the executable, but that would raise additional questions about whether the uncompiled method should be included in the list of methods returned from a `Type.GetMethods` call. - -While the example program above is not practical in reality, similar patterns exist in e.g. reflection based serialization and deserialization libraries that access members based on their names that could be literally downloaded from the internet. - -The dynamic nature of reflection doesn't pose a problem just for fully AOT .NET Runtimes. It's also a problem when tools such as [IL linker](https://github.com/dotnet/core/blob/master/samples/linker-instructions.md) are used to remove unnecessary code. The desire to remove unused code is stronger in fully AOT mode, since native code comes with a greater multiplicative factor (IL instructions are more compact than native instructions). - -## Solving reflection in full AOT mode ## - -The solution to reflection is about establishing what parts of the program can be reached dynamically and making sure their metadata and code is available at runtime. - -### Assume everything is accessed dynamically ### - -The compiler can simply assume that everything can be accessed dynamically. This means that everything will be compiled and available at runtime. This is the safest possible option, but results in big executables and long compilation times. "Everything" includes all of .NET Core framework code, including things like support for FTP or WCF. An app is unlikely to be relying on all of that. - -### Assume non-framework code is accessed dynamically ### - -The compiler can make an assumption that everything that is not part of .NET framework can be accessed dynamically. Unused parts of the framework will not be available for reflection, but real world programs rarely reflect on them. This option still produces executables that are pretty big (especially with many NuGet packages referenced), but their size is more practical. - -### Assume statically reachable code is accessed dynamically ### - -This is the algorithm we discussed above - only things that are reachable through the static callgraph will be available for reflection. - -### Assume code computed by static analysis is accessed dynamically ### - -The compiler can build insights into how reflection is used by analyzing the use of reflection APIs within the compiled program and using data flow analysis to see what elements are reflected on. This is effective for a lot of patterns (such as `typeof(Foo).GetMethod("Bar")`), but can also miss a lot of reflection use in practice. - -### Assume nothing is accessed dynamically ### - -In NativeAOT, reflection metadata (names of types, list of their methods, fields, signatures, etc.) is _optional_. The NativeAOT runtime has its own minimal version of the metadata that represents the minimum required to execute managed code (think: base type and list of interfaces, offsets to GC pointers within an instance of the type, pointer to the finalizer, etc.). The metadata used by the reflection subsystem within the base class libraries is only used by the reflection stack and is not necessary to execute non-reflection code. For a .NET app that doesn't use reflection, the compiler can skip generating the reflection metadata completely. People who would like to totally minimize the size of their applications or obfuscate their code could be interested in this option, although not much existing real world code would be expected to work with this (including a lot of the framework code). - -## Providing hints to the compiler externally ## - -If compiler cannot detect types used by the aplication, an rd.xml file can be supplemented to help ILCompiler find types that should be analyzed. -For that, file `rd.xml` should be created and following lines added to project file -```xml - - - -``` - -Format of the file described [here](rd-xml-format.md) - -## Shimming - -Native AOT libraries have configuration settings (shims) that enable replacing some of frequently used reflection patterns that are incompatible with Native AOT with compatible equivalents that approximate their functionality, without changing the source code. The shim settings documented in this section are meant to be used as temporary unreliable workarounds until the permanent source code fix can be made. They are not guaranteed to make the application work correctly. - -### Simulated calling assembly - -`Assembly.GetCallingAssembly` is not supported in Native AOT and throws `PlatformNotSupportedException` by default. - -`Assembly.GetCallingAssembly` can be in certain situations simulated by `Assembly.GetEntryAssembly`. - -To enable simulated `Assembly.GetCallingAssembly`, you will need: - -```xml - - - -``` - -## Experimental Reflection Free Mode - -Reflection-free mode is a an experimental mode of the NativeAOT compiler and runtime that greatly reduces the functionality of the reflection APIs and demonstrates how far reflection trimming can get. See [Reflection Free Mode](reflection-free-mode.md) for mode details. diff --git a/src/coreclr/nativeaot/nativeaot.sln b/src/coreclr/nativeaot/nativeaot.sln index b2aaf792bd935..30c0b1ec2c84e 100644 --- a/src/coreclr/nativeaot/nativeaot.sln +++ b/src/coreclr/nativeaot/nativeaot.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.11.35017.193 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "System.Private.CoreLib\src\System.Private.CoreLib.csproj", "{E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.DisabledReflection", "System.Private.DisabledReflection\src\System.Private.DisabledReflection.csproj", "{ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Reflection.Execution", "System.Private.Reflection.Execution\src\System.Private.Reflection.Execution.csproj", "{7498DD7C-76C1-4912-AF72-DA84E05B568F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.StackTraceMetadata", "System.Private.StackTraceMetadata\src\System.Private.StackTraceMetadata.csproj", "{33CAE331-16EE-443C-A0CC-4337B94A02AD}" @@ -102,36 +100,6 @@ Global {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x64.Build.0 = Release|x64 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x86.ActiveCfg = Release|x86 {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6}.Release|x86.Build.0 = Release|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|Any CPU.ActiveCfg = Checked|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|Any CPU.Build.0 = Checked|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm.ActiveCfg = Checked|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm.Build.0 = Checked|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm64.ActiveCfg = Checked|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|arm64.Build.0 = Checked|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x64.ActiveCfg = Checked|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x64.Build.0 = Checked|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x86.ActiveCfg = Checked|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Checked|x86.Build.0 = Checked|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|Any CPU.ActiveCfg = Debug|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|Any CPU.Build.0 = Debug|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm.ActiveCfg = Debug|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm.Build.0 = Debug|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm64.ActiveCfg = Debug|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|arm64.Build.0 = Debug|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x64.ActiveCfg = Debug|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x64.Build.0 = Debug|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x86.ActiveCfg = Debug|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Debug|x86.Build.0 = Debug|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|Any CPU.ActiveCfg = Release|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|Any CPU.Build.0 = Release|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm.ActiveCfg = Release|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm.Build.0 = Release|arm - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm64.ActiveCfg = Release|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|arm64.Build.0 = Release|arm64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x64.ActiveCfg = Release|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x64.Build.0 = Release|x64 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x86.ActiveCfg = Release|x86 - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4}.Release|x86.Build.0 = Release|x86 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|Any CPU.ActiveCfg = Checked|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|Any CPU.Build.0 = Checked|x64 {7498DD7C-76C1-4912-AF72-DA84E05B568F}.Checked|arm.ActiveCfg = Checked|arm @@ -558,7 +526,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {E4BC768B-F97D-4A8F-9391-B65DF3EB47C6} = {EC8F472E-5375-4962-9963-8B11F2924C2B} - {ADA691AE-4E1F-4212-97E6-51A27EFCE7E4} = {EC8F472E-5375-4962-9963-8B11F2924C2B} {7498DD7C-76C1-4912-AF72-DA84E05B568F} = {EC8F472E-5375-4962-9963-8B11F2924C2B} {33CAE331-16EE-443C-A0CC-4337B94A02AD} = {EC8F472E-5375-4962-9963-8B11F2924C2B} {3E43ACA2-073E-4A66-BA9C-417C5F83D430} = {EC8F472E-5375-4962-9963-8B11F2924C2B} diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index f091e180d94fd..2cd3cf685d335 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -175,7 +175,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index b0437eb8c5c53..e6246a6f98107 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -4316,9 +4316,6 @@ Unsupported type - - This operation is not available because the reflection support was disabled at compile time. - Cannot set initonly static field '{0}' after type '{1}' is initialized.