diff options
author | Alex Ghiondea <ghiondea.alexandru@microsoft.com> | 2015-12-23 23:17:35 +0300 |
---|---|---|
committer | Alex Ghiondea <ghiondea.alexandru@microsoft.com> | 2015-12-23 23:17:35 +0300 |
commit | 54a7e4b76dd58797a26fcdc727f0ba296f6c367d (patch) | |
tree | e386d328900e2fecd62d5562cb2546f35db927a2 /src/System.Private.Reflection.Core | |
parent | a4e8d45a352f5952912add6ee0391a4d8f201741 (diff) |
While porting the library I ended up updating quite a few projects to make sure they continue to work.
There were a couple of changes to the build system that are included in this change:
- The location of the tool to restore the packages is set to use dnu for now.
- When restoring packages for the internal build we need to actually pass the right parameters to the build of the depproj
There were a couple of places where we had some issues that I fixed while I was doing the port:
- The compiler gave error messages about some method out parameters not being assigned.
- There was one missing 'unsafe' modifier on an interop file
- I had to pull in a 'debug' method temporarily in the ret build. This was needed because the debug build of CoreLib currently does not build with the 'DEBUG' define.
[tfs-changeset: 1559864]
Diffstat (limited to 'src/System.Private.Reflection.Core')
92 files changed, 14848 insertions, 0 deletions
diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/AssemblyBinder.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/AssemblyBinder.cs new file mode 100644 index 000000000..d4601dbd5 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/AssemblyBinder.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Collections.Generic; +using global::System.Reflection; +using global::Internal.Metadata.NativeFormat; +using global::System.Reflection.Runtime.General; + +namespace Internal.Reflection.Core +{ + // + // Implements the custom assembly binding policy for a Reflection domain. This gets called any time the domain needs + // to resolve an assembly name. + // + // If the binder cannot locate an assembly, it must return null and set "exception" to an exception object. + // + public abstract class AssemblyBinder + { + public abstract bool Bind(AssemblyName refName, out MetadataReader reader, out ScopeDefinitionHandle scopeDefinitionHandle, out IEnumerable<QScopeDefinition> overflowScopes, out Exception exception); + + // This helper is a concession to the fact that third-party binders running on top of the Win8P surface area have no sensible way + // to perform this task due to the lack of a SetCulture() api on the AssemblyName class. Reflection.Core *is* able to do this + // thanks to the Internal.Reflection.Augment contract so we will expose this helper for the convenience of binders. + protected AssemblyName CreateAssemblyNameFromMetadata(MetadataReader reader, ScopeDefinitionHandle scopeDefinitionHandle) + { + return scopeDefinitionHandle.ToRuntimeAssemblyName(reader).ToAssemblyName(); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs new file mode 100644 index 000000000..69e169449 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionDomain.cs @@ -0,0 +1,166 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.TypeParsing; +using global::System.Reflection.Runtime.CustomAttributes; +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +namespace Internal.Reflection.Core.Execution +{ + // + // This singleton class implements the domain used for "execution" reflection objects, e.g. Types obtained from RuntimeTypeHandles. + // This class is only instantiated on Project N, as the desktop uses IRC only for LMR. + // + public sealed class ExecutionDomain : ReflectionDomain + { + internal ExecutionDomain(ReflectionDomainSetup executionDomainSetup, ExecutionEnvironment executionEnvironment) + : base(executionDomainSetup, 0) + { + this.ExecutionEnvironment = executionEnvironment; + } + + // + // Retrieves a type by name. Helper to implement Type.GetType(); + // + public Type GetType(String typeName, bool throwOnError, bool ignoreCase, IEnumerable<String> defaultAssemblyNames) + { + if (typeName == null) + throw new ArgumentNullException(); + + if (typeName.Length == 0) + { + if (throwOnError) + throw new TypeLoadException(SR.Arg_TypeLoadNullStr); + else + return null; + } + + AssemblyQualifiedTypeName assemblyQualifiedTypeName; + try + { + assemblyQualifiedTypeName = TypeParser.ParseAssemblyQualifiedTypeName(typeName); + } + catch (ArgumentException) + { + // Input string was a syntactically invalid type name. + if (throwOnError) + throw; + return null; + } + + if (assemblyQualifiedTypeName.AssemblyName != null) + { + defaultAssemblyNames = new String[] { null }; + } + + Exception lastTypeLoadException = null; + foreach (String assemblyName in defaultAssemblyNames) + { + RuntimeAssembly defaultAssembly; + if (assemblyName == null) + { + defaultAssembly = null; + } + else + { + RuntimeAssemblyName runtimeAssemblyName = AssemblyNameParser.Parse(assemblyName); + Exception e = RuntimeAssembly.TryGetRuntimeAssembly(this, runtimeAssemblyName, out defaultAssembly); + if (e != null) + continue; // A default assembly such as "System.Runtime" might not "exist" in an app that opts heavily out of pay-for-play metadata. Just go on to the next one. + } + + RuntimeType result; + Exception typeLoadException = assemblyQualifiedTypeName.TryResolve(this, defaultAssembly, ignoreCase, out result); + if (typeLoadException == null) + return result; + lastTypeLoadException = typeLoadException; + } + + if (throwOnError) + { + if (lastTypeLoadException == null) + throw new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFoundByGetType, typeName)); + else + throw lastTypeLoadException; + } + else + { + return null; + } + } + + // + // Retrieves the MethodBase for a given method handle. Helper to implement Delegate.GetMethodInfo() + // + public MethodBase GetMethod(RuntimeTypeHandle declaringTypeHandle, MethodHandle methodHandle, RuntimeTypeHandle[] genericMethodTypeArgumentHandles) + { + RuntimeType declaringType = ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(declaringTypeHandle); + RuntimeTypeInfo contextTypeInfo = declaringType.GetRuntimeTypeInfo(); + RuntimeNamedTypeInfo definingTypeInfo = contextTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + MetadataReader reader = definingTypeInfo.Reader; + if (methodHandle.IsConstructor(reader)) + { + return RuntimePlainConstructorInfo.GetRuntimePlainConstructorInfo(methodHandle, definingTypeInfo, contextTypeInfo); + } + else + { + RuntimeNamedMethodInfo runtimeNamedMethodInfo = RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(methodHandle, definingTypeInfo, contextTypeInfo); + if (!runtimeNamedMethodInfo.IsGenericMethod) + { + return runtimeNamedMethodInfo; + } + else + { + RuntimeType[] genericTypeArguments = new RuntimeType[genericMethodTypeArgumentHandles.Length]; + for (int i = 0; i < genericMethodTypeArgumentHandles.Length; i++) + { + genericTypeArguments[i] = ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(genericMethodTypeArgumentHandles[i]); + } + return RuntimeConstructedGenericMethodInfo.GetRuntimeConstructedGenericMethodInfo(runtimeNamedMethodInfo, genericTypeArguments); + } + } + } + + // + // Get or create a CustomAttributeData object for a specific type and arguments. + // + public CustomAttributeData GetCustomAttributeData(Type attributeType, IList<CustomAttributeTypedArgument> constructorArguments, IList<CustomAttributeNamedArgument> namedArguments) + { + RuntimeType runtimeAttributeType = attributeType as RuntimeType; + if (runtimeAttributeType == null) + throw new InvalidOperationException(); + return new RuntimePseudoCustomAttributeData(runtimeAttributeType, constructorArguments, namedArguments); + } + + //======================================================================================= + // Flotsam and jetsam. + //======================================================================================= + // + // ShadowTypes are a trick to make Types based on RuntimeTypeHandles "light up" on Project N when metadata and reflection are present. + // This is exposed on the execution domain only as it makes no sense for LMR types. + // + public Type CreateShadowRuntimeInspectionOnlyNamedTypeIfAvailable(RuntimeTypeHandle runtimeTypeHandle) + { + MetadataReader metadataReader; + TypeDefinitionHandle typeDefinitionHandle; + + if (!ReflectionCoreExecution.ExecutionEnvironment.TryGetMetadataForNamedType(runtimeTypeHandle, out metadataReader, out typeDefinitionHandle)) + return null; + return new ShadowRuntimeInspectionOnlyNamedType(metadataReader, typeDefinitionHandle); + } + + internal ExecutionEnvironment ExecutionEnvironment { get; private set; } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs new file mode 100644 index 000000000..1b83aa1b7 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ExecutionEnvironment.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Reflection; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core.NonPortable; + +using OpenMethodInvoker = global::System.Reflection.Runtime.MethodInfos.OpenMethodInvoker; + +namespace Internal.Reflection.Core.Execution +{ + // + // This class abstracts the underlying Redhawk (or whatever execution engine) runtime and exposes the services + // that I.R.Core.Execution needs. + // + public abstract class ExecutionEnvironment + { + //============================================================================================== + // Access to the underlying execution engine's object allocation routines. + //============================================================================================== + public abstract Object NewObject(RuntimeTypeHandle typeHandle); + public abstract Array NewArray(RuntimeTypeHandle typeHandleForArrayType, int count); + public abstract Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArrayType, int[] lengths, int[] lowerBounds); + + //============================================================================================== + // Execution engine policies. + //============================================================================================== + + // + // This returns a generic type with one generic parameter (representing the array element type) + // whose base type and interface list determines what TypeInfo.BaseType and TypeInfo.ImplementedInterfaces + // return for types that return true for IsArray. + // + public abstract RuntimeTypeHandle ProjectionTypeForArrays { get; } + public abstract bool IsAssignableFrom(RuntimeTypeHandle dstType, RuntimeTypeHandle srcType); + public abstract bool TryGetBaseType(RuntimeTypeHandle typeHandle, out RuntimeTypeHandle baseTypeHandle); + public abstract IEnumerable<RuntimeTypeHandle> TryGetImplementedInterfaces(RuntimeTypeHandle typeHandle); + public abstract bool IsReflectionBlocked(RuntimeTypeHandle typeHandle); + + //============================================================================================== + // Default Value support. + //============================================================================================== + public abstract bool GetDefaultValueIfAny(MetadataReader reader, ParameterHandle parameterHandle, Type declaredType, IEnumerable<CustomAttributeData> customAttributes, out Object defaultValue); + public abstract bool GetDefaultValueIfAny(MetadataReader reader, FieldHandle fieldHandle, Type declaredType, IEnumerable<CustomAttributeData> customAttributes, out Object defaultValue); + public abstract bool GetDefaultValueIfAny(MetadataReader reader, PropertyHandle propertyHandle, Type declaredType, IEnumerable<CustomAttributeData> customAttributes, out Object defaultValue); + + //============================================================================================== + // Reflection Mapping Tables + //============================================================================================== + public abstract bool TryGetMetadataForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeDefinitionHandle typeDefHandle); + public abstract bool TryGetNamedTypeForMetadata(MetadataReader metadataReader, TypeDefinitionHandle typeDefHandle, out RuntimeTypeHandle runtimeTypeHandle); + + public abstract bool TryGetTypeReferenceForNamedType(RuntimeTypeHandle runtimeTypeHandle, out MetadataReader metadataReader, out TypeReferenceHandle typeRefHandle); + public abstract bool TryGetNamedTypeForTypeReference(MetadataReader metadataReader, TypeReferenceHandle typeRefHandle, out RuntimeTypeHandle runtimeTypeHandle); + + public abstract bool TryGetArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, out RuntimeTypeHandle arrayTypeHandle); + public abstract bool TryGetArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, out RuntimeTypeHandle elementTypeHandle); + + public abstract bool TryGetMultiDimArrayTypeForElementType(RuntimeTypeHandle elementTypeHandle, int rank, out RuntimeTypeHandle arrayTypeHandle); + public abstract bool TryGetMultiDimArrayTypeElementType(RuntimeTypeHandle arrayTypeHandle, int rank, out RuntimeTypeHandle elementTypeHandle); + + public abstract bool TryGetPointerTypeForTargetType(RuntimeTypeHandle targetTypeHandle, out RuntimeTypeHandle pointerTypeHandle); + public abstract bool TryGetPointerTypeTargetType(RuntimeTypeHandle pointerTypeHandle, out RuntimeTypeHandle targetTypeHandle); + + public abstract bool TryGetConstructedGenericTypeComponents(RuntimeTypeHandle runtimeTypeHandle, out RuntimeTypeHandle genericTypeDefinitionHandle, out RuntimeTypeHandle[] genericTypeArgumentHandles); + public abstract bool TryGetConstructedGenericTypeForComponents(RuntimeTypeHandle genericTypeDefinitionHandle, RuntimeTypeHandle[] genericTypeArgumentHandles, out RuntimeTypeHandle runtimeTypeHandle); + + public abstract bool TryGetMetadataNameForRuntimeTypeHandle(RuntimeTypeHandle rtth, out string name); + + //============================================================================================== + // Invoke and field access support. + //============================================================================================== + public abstract MethodInvoker TryGetMethodInvoker(MetadataReader reader, RuntimeTypeHandle declaringTypeHandle, MethodHandle methodHandle, RuntimeTypeHandle[] genericMethodTypeArgumentHandles); + public abstract FieldAccessor TryGetFieldAccessor(RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle fieldTypeHandle, FieldHandle fieldHandle); + + //============================================================================================== + // Pseudo Custom Attributes + //============================================================================================== + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, ScopeDefinitionHandle scopeDefinitionHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, MethodHandle methodHandle, TypeDefinitionHandle declaringTypeHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, ParameterHandle parameterHandle, MethodHandle declaringMethodHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, FieldHandle fieldHandle, TypeDefinitionHandle declaringTypeHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, PropertyHandle propertyHandle, TypeDefinitionHandle declaringTypeHandle); + public abstract IEnumerable<CustomAttributeData> GetPsuedoCustomAttributes(MetadataReader reader, EventHandle eventHandle, TypeDefinitionHandle declaringTypeHandle); + + //============================================================================================== + // RuntimeMethodHandle and RuntimeFieldHandle support. + //============================================================================================== + public abstract bool TryGetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, out RuntimeTypeHandle declaringTypeHandle, out MethodHandle methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles); + public abstract bool TryGetMethodFromHandleAndType(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle, out MethodHandle methodHandle, out RuntimeTypeHandle[] genericMethodTypeArgumentHandles); + public abstract bool TryGetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, out RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle); + public abstract bool TryGetFieldFromHandleAndType(RuntimeFieldHandle runtimeFieldHandle, RuntimeTypeHandle declaringTypeHandle, out FieldHandle fieldHandle); + + + //============================================================================================== + // Manifest resource stream support. + //============================================================================================== + public abstract ManifestResourceInfo GetManifestResourceInfo(Assembly assembly, String resourceName); + public abstract String[] GetManifestResourceNames(Assembly assembly); + public abstract Stream GetManifestResourceStream(Assembly assembly, String name); + + //============================================================================================== + // Other + //============================================================================================== + public abstract MethodInvoker GetSyntheticMethodInvoker(RuntimeTypeHandle thisType, RuntimeTypeHandle[] parameterTypes, InvokerOptions options, Func<Object, Object[], Object> invoker); + public abstract bool IsCOMObject(Type type); + + //============================================================================================== + // Generic Virtual Method Support + //============================================================================================== + public abstract bool TryGetGenericVirtualTargetForTypeAndSlot(RuntimeTypeHandle targetHandle, ref RuntimeTypeHandle declaringType, ref RuntimeTypeHandle[] genericArguments, ref string methodName, ref IntPtr methodSignature, out IntPtr methodPointer, out IntPtr dictionaryPointer, out bool slotUpdated); + + //============================================================================================== + // Non-public methods + //============================================================================================== + internal MethodInvoker GetMethodInvoker(MetadataReader reader, RuntimeType declaringType, MethodHandle methodHandle, RuntimeType[] genericMethodTypeArguments, MemberInfo exceptionPertainant) + { + if (declaringType.InternalIsOpen) + return new OpenMethodInvoker(); + for (int i = 0; i < genericMethodTypeArguments.Length; i++) + { + if (genericMethodTypeArguments[i].InternalIsOpen) + return new OpenMethodInvoker(); + } + + RuntimeTypeHandle typeDefinitionHandle = declaringType.TypeHandle; + RuntimeTypeHandle[] genericMethodTypeArgumentHandles = new RuntimeTypeHandle[genericMethodTypeArguments.Length]; + + for (int i = 0; i < genericMethodTypeArguments.Length; i++) + { + genericMethodTypeArgumentHandles[i] = genericMethodTypeArguments[i].TypeHandle; + } + MethodInvoker methodInvoker = TryGetMethodInvoker(reader, typeDefinitionHandle, methodHandle, genericMethodTypeArgumentHandles); + if (methodInvoker == null) + throw declaringType.GetReflectionDomain().CreateNonInvokabilityException(exceptionPertainant); + return methodInvoker; + } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/FieldAccessor.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/FieldAccessor.cs new file mode 100644 index 000000000..6faba1d4f --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/FieldAccessor.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Collections.Generic; +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core.NonPortable; + +namespace Internal.Reflection.Core.Execution +{ + // + // This class abstracts the underlying Redhawk (or whatever execution engine) runtime that sets and gets fields. + // + public abstract class FieldAccessor + { + protected FieldAccessor() { } + public abstract Object GetField(Object obj); + public abstract void SetField(Object obj, Object value); + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs new file mode 100644 index 000000000..d011b22fe --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/InvokerOptions.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; + +namespace Internal.Reflection.Core.Execution +{ + [Flags] + public enum InvokerOptions + { + None = 0x00000000, + AllowNullThis = 0x00000001, // Don't raise an exception if the "thisObject" parameter to Invoker is null. + DontWrapException = 0x00000002, // Don't wrap target exceptions in TargetInvocationException. + } +} + diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs new file mode 100644 index 000000000..67a3c6021 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/MethodInvoker.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; + +namespace Internal.Reflection.Core.Execution +{ + // + // This class polymorphically implements the MethodBase.Invoke() api and its close cousins. MethodInvokers are designed to be built once and cached + // for maximum Invoke() throughput. + // + public abstract class MethodInvoker + { + protected MethodInvoker() { } + + public abstract Object Invoke(Object thisObject, Object[] arguments); + public abstract Delegate CreateDelegate(RuntimeTypeHandle delegateType, Object target, bool isStatic, bool isVirtual, bool isOpen); + } +} + diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ReflectionCoreExecution.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ReflectionCoreExecution.cs new file mode 100644 index 000000000..4552d30bc --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/Execution/ReflectionCoreExecution.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// Internal.Reflection.Core.Execution +// ------------------------------------------------- +// Why does this exist?: +// This contract augments Internal.Reflection.Core and adds the ability +// to create a single "execution domain" which allows creation of +// a Win8P-style "invokable" Reflection object tree. Reflection objects +// in this domain unify with the underlying execution engine's +// native type artifacts (i.e. typeof() and Object.GetType() returns +// types in this domain.) +// +// Implemented by: +// Reflection.Core.dll on RH and desktop. +// +// Consumed by: +// RH for "classic reflection". +// Not used on desktop. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; + +using global::Internal.Metadata.NativeFormat; +using global::Internal.Reflection.Augments; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +namespace Internal.Reflection.Core.Execution +{ + public static class ReflectionCoreExecution + { + // + // One time initialization to supply the information needed to initialize the default domain and the + // the execution environment. + // + // Remarks: + // This design intentionally restricts you to one ExecutionEnvironment per side-by-side runtime in a process. + // Aside from the dubious value of allowing multiple executionEnvironments, there is no good way to + // for this scenario: + // + // typeof(Foo).GetTypeInfo() + // + // to "lookup" a domain in order to map the RuntimeTypeHandle to a specific ExecutionEnvironment. + // + public static void InitializeExecutionDomain(ReflectionDomainSetup executionDomainSetup, ExecutionEnvironment executionEnvironment) + { + ExecutionDomain executionDomain = new ExecutionDomain(executionDomainSetup, executionEnvironment); + //@todo: This check has a race window but since this is a private api targeted by the toolchain, perhaps this is not so critical. + if (_executionDomain != null) + throw new InvalidOperationException(); // Multiple Initializes not allowed. + _executionDomain = executionDomain; + + ReflectionCoreCallbacks reflectionCallbacks = new ReflectionCoreCallbacksImplementation(); + ReflectionAugments.Initialize(reflectionCallbacks); + return; + } + + // + // The ExecutionDomain is the domain that hosts reflection entities created by these constructs: + // + // Type.GetTypeFromHandle() ( i.e. typeof() ) + // Object.GetType() + // Type.GetType(String name, [bool throwOnError]) + // Assembly.Load(AssemblyName) + // + // There is only one ExecutionDomain and it is initialized by the Initialize() method. It is the only domain capable + // of supporting invocation. + // + public static ExecutionDomain ExecutionDomain + { + get + { + return _executionDomain; + } + } + + internal static ExecutionEnvironment ExecutionEnvironment + { + get + { + return ExecutionDomain.ExecutionEnvironment; + } + } + + private volatile static ExecutionDomain _executionDomain; + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/FoundationTypes.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/FoundationTypes.cs new file mode 100644 index 000000000..fe87cf128 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/FoundationTypes.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; + +namespace Internal.Reflection.Core +{ + // This class serves up a small set of foundation types that have special meaning to Reflection. + public abstract class FoundationTypes + { + public abstract Type SystemObject { get; } + public abstract Type SystemValueType { get; } + public abstract Type SystemEnum { get; } + public abstract Type SystemVoid { get; } + public abstract Type SystemArray { get; } + public abstract Type SystemString { get; } + public abstract Type SystemType { get; } + public abstract Type SystemBoolean { get; } + public abstract Type SystemChar { get; } + public abstract Type SystemSByte { get; } + public abstract Type SystemByte { get; } + public abstract Type SystemInt16 { get; } + public abstract Type SystemUInt16 { get; } + public abstract Type SystemInt32 { get; } + public abstract Type SystemUInt32 { get; } + public abstract Type SystemInt64 { get; } + public abstract Type SystemUInt64 { get; } + public abstract Type SystemIntPtr { get; } + public abstract Type SystemUIntPtr { get; } + public abstract Type SystemSingle { get; } + public abstract Type SystemDouble { get; } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomain.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomain.cs new file mode 100644 index 000000000..045c4fd77 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomain.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +//Internal.Reflection.Core +//------------------------------------------------- +// Why does this exist?: +// This contract exposes the service +// of consuming metadata (through the S.R.M api) and creating +// an Win8P-style "browse-only" Reflection object tree on top of it. +// +// The contract allows the creation of multiple "reflection domains" with +// custom assembly binding policies. +// +// +// Implemented by: +// Reflection.Core.dll on RH and desktop. +// +// Consumed by: +// LMR on RH and desktop. +// "Classic reflection" on RH. +// +// + +using global::System; +using global::System.Reflection; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +namespace Internal.Reflection.Core +{ + //===================================================================================================================================== + // A Reflection domain is an independent "universe" of loaded reflection types. Reflection entities cannot exist in multiple domains, + // nor at they allowed to intermix. + // + // Reflection domains are "browse-only" - attempts to invoke, instantiate or set or get fields and properties all fail. + // + // Each reflection domain determines its own rules for resolving assemblies and the identity of the "core" assembly (typically + // mscorlib.dll.) + //===================================================================================================================================== + public class ReflectionDomain + { + public ReflectionDomain(ReflectionDomainSetup setup) + { + throw new PlatformNotSupportedException(); + } + + public Assembly LoadAssembly(AssemblyName refName) + { + throw new PlatformNotSupportedException(); + } + + public Exception CreateMissingMetadataException(Type pertainant) + { + return this.ReflectionDomainSetup.CreateMissingMetadataException(pertainant); + } + + public Exception CreateMissingMetadataException(TypeInfo pertainant) + { + return this.ReflectionDomainSetup.CreateMissingMetadataException(pertainant); + } + + public Exception CreateMissingMetadataException(TypeInfo pertainant, string nestedTypeName) + { + return this.ReflectionDomainSetup.CreateMissingMetadataException(pertainant, nestedTypeName); + } + + public Exception CreateNonInvokabilityException(MemberInfo pertainant) + { + return this.ReflectionDomainSetup.CreateNonInvokabilityException(pertainant); + } + + + // This private constructor exists as a temporary measure so that we can create Execution domains without enabling the + // general ReflectionDomain case. + internal ReflectionDomain(ReflectionDomainSetup setup, int meaningless) + { + this.ReflectionDomainSetup = setup; + } + + internal ReflectionDomainSetup ReflectionDomainSetup { get; private set; } + + internal FoundationTypes FoundationTypes + { + get + { + return this.ReflectionDomainSetup.FoundationTypes; + } + } + + internal IEnumerable<Type> PrimitiveTypes + { + get + { + FoundationTypes foundationTypes = this.FoundationTypes; + return new Type[] + { + foundationTypes.SystemBoolean, + foundationTypes.SystemChar, + foundationTypes.SystemSByte, + foundationTypes.SystemByte, + foundationTypes.SystemInt16, + foundationTypes.SystemUInt16, + foundationTypes.SystemInt32, + foundationTypes.SystemUInt32, + foundationTypes.SystemInt64, + foundationTypes.SystemUInt64, + foundationTypes.SystemSingle, + foundationTypes.SystemDouble, + foundationTypes.SystemIntPtr, + foundationTypes.SystemUIntPtr, + }; + } + } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomainSetup.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomainSetup.cs new file mode 100644 index 000000000..d9b88686f --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Core/ReflectionDomainSetup.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +//Internal.Reflection.Core +//------------------------------------------------- +// Why does this exist?: +// This contract exposes the service +// of consuming metadata (through the S.R.M api) and creating +// an Win8P-style "browse-only" Reflection object tree on top of it. +// +// The contract allows the creation of multiple "reflection domains" with +// custom assembly binding policies. +// +// +// Implemented by: +// Reflection.Core.dll on RH and desktop. +// +// Consumed by: +// LMR on RH and desktop. +// "Classic reflection" on RH. +// +// + +using global::System; +using global::System.Reflection; +using global::System.Reflection.Runtime.General; + +namespace Internal.Reflection.Core +{ + //===================================================================================================================================== + // This object encapsulates the customization parameters for Reflection domains. + //===================================================================================================================================== + public abstract class ReflectionDomainSetup + { + protected ReflectionDomainSetup() { } + public abstract AssemblyBinder AssemblyBinder { get; } + public abstract FoundationTypes FoundationTypes { get; } + public abstract Exception CreateMissingMetadataException(TypeInfo pertainant); + public abstract Exception CreateMissingMetadataException(Type pertainant); + public abstract Exception CreateMissingMetadataException(TypeInfo pertainant, string nestedTypeName); + public abstract Exception CreateNonInvokabilityException(MemberInfo pertainant); + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs new file mode 100644 index 000000000..082ec20ca --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ITraceableTypeMember.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; + +namespace Internal.Reflection.Tracing +{ + internal interface ITraceableTypeMember + { + // Returns the Name value *without recursing into the public Name implementation.* + String MemberName { get; } + + // Returns the DeclaringType value *without recursing into the public DeclaringType implementation.* + Type ContainingType { get; } + } +} diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Internal.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Internal.cs new file mode 100644 index 000000000..fca49f7c7 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Internal.cs @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Text; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core.NonPortable; + +namespace Internal.Reflection.Tracing +{ + public static partial class ReflectionTrace + { + //============================================================================== + // Returns the type name to emit into the ETW record. + // + // - If it returns null, skip writing the ETW record. Null returns can happen + // for the following reasons: + // - Missing metadata + // - Open type (no need to trace these - open type creations always succeed) + // - Third-party-implemented Types. + // + // The implementation does a reasonable-effort to avoid MME's to avoid an annoying + // debugger experience. However, some MME's will still get caught by the try/catch. + // + // - The format happens to match what the AssemblyQualifiedName property returns + // but we cannot invoke that here due to the risk of infinite recursion. + // The implementation must be very careful what it calls. + //============================================================================== + private static String NameString(this Type type) + { + try + { + return type.AssemblyQualifiedTypeName(); + } + catch + { + return null; + } + } + + //============================================================================== + // Returns the assembly name to emit into the ETW record. + //============================================================================== + private static String NameString(this Assembly assembly) + { + try + { + RuntimeAssembly runtimeAssembly = assembly as RuntimeAssembly; + if (runtimeAssembly == null) + return null; + return runtimeAssembly.Scope.Handle.ToRuntimeAssemblyName(runtimeAssembly.Scope.Reader).FullName; + } + catch + { + return null; + } + } + + //============================================================================== + // Returns the custom attribute type name to emit into the ETW record. + //============================================================================== + private static String AttributeTypeNameString(this CustomAttributeData customAttributeData) + { + try + { + RuntimeCustomAttributeData runtimeCustomAttributeData = customAttributeData as RuntimeCustomAttributeData; + if (runtimeCustomAttributeData == null) + return null; + return runtimeCustomAttributeData.AttributeType.NameString(); + } + catch + { + return null; + } + } + + //============================================================================== + // Returns the declaring type name (without calling MemberInfo.DeclaringType) to emit into the ETW record. + //============================================================================== + private static String DeclaringTypeNameString(this MemberInfo memberInfo) + { + try + { + ITraceableTypeMember traceableTypeMember = memberInfo as ITraceableTypeMember; + if (traceableTypeMember == null) + return null; + return traceableTypeMember.ContainingType.NameString(); + } + catch + { + return null; + } + } + + //============================================================================== + // Returns the MemberInfo.Name value (without calling MemberInfo.Name) to emit into the ETW record. + //============================================================================== + private static String NameString(this MemberInfo memberInfo) + { + try + { + TypeInfo typeInfo = memberInfo as TypeInfo; + if (typeInfo != null) + return typeInfo.AsType().NameString(); + + ITraceableTypeMember traceableTypeMember = memberInfo as ITraceableTypeMember; + if (traceableTypeMember == null) + return null; + return traceableTypeMember.MemberName; + } + catch + { + return null; + } + } + + //============================================================================== + // Append type argument strings. + //============================================================================== + private static String GenericTypeArgumentStrings(this Type[] typeArguments) + { + if (typeArguments == null) + return null; + String s = ""; + foreach (Type typeArgument in typeArguments) + { + String typeArgumentString = typeArgument.NameString(); + if (typeArgumentString == null) + return null; + s += "@" + typeArgumentString; + } + return s; + } + + private static String NonQualifiedTypeName(this Type type) + { + RuntimeType runtimeType = type as RuntimeType; + if (runtimeType == null) + return null; + + if (runtimeType.HasElementType) + { + String elementTypeName = runtimeType.InternalRuntimeElementType.NonQualifiedTypeName(); + if (elementTypeName == null) + return null; + String suffix; + if (runtimeType.IsArray) + { + int rank = runtimeType.GetArrayRank(); + if (rank == 1) + suffix = "[" + (runtimeType.InternalIsMultiDimArray ? "*" : "") + "]"; + else + suffix = "[" + new String(',', rank - 1) + "]"; + } + else if (runtimeType.IsByRef) + suffix = "&"; + else if (runtimeType.IsPointer) + suffix = "*"; + else + return null; + + return elementTypeName + suffix; + } + else if (runtimeType.IsGenericParameter) + { + return null; + } + else if (runtimeType.IsConstructedGenericType) + { + StringBuilder sb = new StringBuilder(); + String genericTypeDefinitionTypeName = runtimeType.GetGenericTypeDefinition().NonQualifiedTypeName(); + if (genericTypeDefinitionTypeName == null) + return null; + sb.Append(genericTypeDefinitionTypeName); + sb.Append("["); + String sep = ""; + foreach (RuntimeType ga in runtimeType.InternalRuntimeGenericTypeArguments) + { + String gaTypeName = ga.AssemblyQualifiedTypeName(); + if (gaTypeName == null) + return null; + sb.Append(sep + "[" + gaTypeName + "]"); + sep = ","; + } + sb.Append("]"); + + return sb.ToString(); + } + else + { + RuntimeNamedTypeInfo runtimeNamedTypeInfo = type.GetTypeInfo() as RuntimeNamedTypeInfo; + if (runtimeNamedTypeInfo == null) + return null; + MetadataReader reader = runtimeNamedTypeInfo.Reader; + + String s = ""; + TypeDefinitionHandle typeDefinitionHandle = runtimeNamedTypeInfo.TypeDefinitionHandle; + NamespaceDefinitionHandle namespaceDefinitionHandle; + do + { + TypeDefinition typeDefinition = typeDefinitionHandle.GetTypeDefinition(reader); + String name = typeDefinition.Name.GetString(reader); + if (s == "") + s = name; + else + s = name + "+" + s; + namespaceDefinitionHandle = typeDefinition.NamespaceDefinition; + typeDefinitionHandle = typeDefinition.EnclosingType; + } + while (!typeDefinitionHandle.IsNull(reader)); + + NamespaceChain namespaceChain = new NamespaceChain(reader, namespaceDefinitionHandle); + String ns = namespaceChain.NameSpace; + if (ns != null) + s = ns + "." + s; + return s; + } + } + + private static String AssemblyQualifiedTypeName(this Type type) + { + RuntimeType runtimeType = type as RuntimeType; + if (runtimeType == null) + return null; + String nonqualifiedTypeName = runtimeType.NonQualifiedTypeName(); + if (nonqualifiedTypeName == null) + return null; + String assemblyName = runtimeType.ContainingAssemblyName(); + if (assemblyName == null) + return assemblyName; + return nonqualifiedTypeName + ", " + assemblyName; + } + + private static String ContainingAssemblyName(this Type type) + { + RuntimeType runtimeType = type as RuntimeType; + if (runtimeType == null) + return null; + RuntimeTypeInfo runtimeTypeInfo = runtimeType.GetRuntimeTypeInfo<RuntimeTypeInfo>(); + if (runtimeTypeInfo is RuntimeNoMetadataNamedTypeInfo) + return null; + return runtimeTypeInfo.Assembly.NameString(); + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.Events.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.Events.cs new file mode 100644 index 000000000..3ba3b1a2c --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.Events.cs @@ -0,0 +1,673 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using ReflectionEventSource = global::System.Reflection.Runtime.Tracing.ReflectionEventSource; + +namespace Internal.Reflection.Tracing +{ + // + // The individual event methods. These are in a separate file to allow them to be tool-generated. + // + public static partial class ReflectionTrace + { + public static void Type_MakeGenericType(Type type, Type[] typeArguments) + { + String typeName = type.NameString(); + if (typeName == null) + return; + String typeArgumentStrings = typeArguments.GenericTypeArgumentStrings(); + if (typeArgumentStrings == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeGenericType(typeName, typeArgumentStrings); + } + + public static void Type_MakeArrayType(Type type) + { + String typeName = type.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeArrayType(typeName); + } + + public static void Type_FullName(Type type) + { + String typeName = type.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_FullName(typeName); + } + + public static void Type_Namespace(Type type) + { + String typeName = type.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_Namespace(typeName); + } + + public static void Type_AssemblyQualifiedName(Type type) + { + String typeName = type.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_AssemblyQualifiedName(typeName); + } + + public static void Type_Name(Type type) + { + String typeName = type.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_Name(typeName); + } + + public static void TypeInfo_CustomAttributes(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_CustomAttributes(typeName); + } + + public static void TypeInfo_Name(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_Name(typeName); + } + + public static void TypeInfo_BaseType(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_BaseType(typeName); + } + + public static void TypeInfo_DeclaredConstructors(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredConstructors(typeName); + } + + public static void TypeInfo_DeclaredEvents(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredEvents(typeName); + } + + public static void TypeInfo_DeclaredFields(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredFields(typeName); + } + + public static void TypeInfo_DeclaredMembers(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredMembers(typeName); + } + + public static void TypeInfo_DeclaredMethods(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredMethods(typeName); + } + + public static void TypeInfo_DeclaredNestedTypes(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredNestedTypes(typeName); + } + + public static void TypeInfo_DeclaredProperties(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaredProperties(typeName); + } + + public static void TypeInfo_DeclaringMethod(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_DeclaringMethod(typeName); + } + + public static void TypeInfo_FullName(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_FullName(typeName); + } + + public static void TypeInfo_AssemblyQualifiedName(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_AssemblyQualifiedName(typeName); + } + + public static void TypeInfo_Namespace(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_Namespace(typeName); + } + + public static void TypeInfo_GetDeclaredEvent(TypeInfo typeInfo, String eventName) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + if (eventName == null) + return; + ReflectionEventSource.Log.TypeInfo_GetDeclaredEvent(typeName, eventName); + } + + public static void TypeInfo_GetDeclaredField(TypeInfo typeInfo, String fieldName) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + if (fieldName == null) + return; + ReflectionEventSource.Log.TypeInfo_GetDeclaredField(typeName, fieldName); + } + + public static void TypeInfo_GetDeclaredMethod(TypeInfo typeInfo, String methodName) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + if (methodName == null) + return; + ReflectionEventSource.Log.TypeInfo_GetDeclaredMethod(typeName, methodName); + } + + public static void TypeInfo_GetDeclaredProperty(TypeInfo typeInfo, String propertyName) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + if (propertyName == null) + return; + ReflectionEventSource.Log.TypeInfo_GetDeclaredProperty(typeName, propertyName); + } + + public static void TypeInfo_MakeArrayType(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeArrayType(typeName); + } + + public static void TypeInfo_MakeArrayType(TypeInfo typeInfo, int rank) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeArrayType(typeName); + } + + public static void TypeInfo_MakeByRefType(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeByRefType(typeName); + } + + public static void TypeInfo_MakeGenericType(TypeInfo typeInfo, Type[] typeArguments) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + String typeArgumentStrings = typeArguments.GenericTypeArgumentStrings(); + if (typeArgumentStrings == null) + return; + ReflectionEventSource.Log.TypeInfo_MakeGenericType(typeName, typeArgumentStrings); + } + + public static void TypeInfo_MakePointerType(TypeInfo typeInfo) + { + String typeName = typeInfo.NameString(); + if (typeName == null) + return; + ReflectionEventSource.Log.TypeInfo_MakePointerType(typeName); + } + + public static void Assembly_DefinedTypes(Assembly assembly) + { + String assemblyName = assembly.NameString(); + if (assemblyName == null) + return; + ReflectionEventSource.Log.Assembly_DefinedTypes(assemblyName); + } + + public static void Assembly_GetType(Assembly assembly, String typeName) + { + String assemblyName = assembly.NameString(); + if (assemblyName == null) + return; + if (typeName == null) + return; + ReflectionEventSource.Log.Assembly_GetType(assemblyName, typeName); + } + + public static void Assembly_CustomAttributes(Assembly assembly) + { + String assemblyName = assembly.NameString(); + if (assemblyName == null) + return; + ReflectionEventSource.Log.Assembly_CustomAttributes(assemblyName); + } + + public static void Assembly_FullName(Assembly assembly) + { + String assemblyName = assembly.NameString(); + if (assemblyName == null) + return; + ReflectionEventSource.Log.Assembly_FullName(assemblyName); + } + + public static void Assembly_GetName(Assembly assembly) + { + String assemblyName = assembly.NameString(); + if (assemblyName == null) + return; + ReflectionEventSource.Log.Assembly_GetName(assemblyName); + } + + public static void CustomAttributeData_ConstructorArguments(CustomAttributeData customAttributeData) + { + String attributeTypeName = customAttributeData.AttributeTypeNameString(); + if (attributeTypeName == null) + return; + ReflectionEventSource.Log.CustomAttributeData_ConstructorArguments(attributeTypeName); + } + + public static void CustomAttributeData_NamedArguments(CustomAttributeData customAttributeData) + { + String attributeTypeName = customAttributeData.AttributeTypeNameString(); + if (attributeTypeName == null) + return; + ReflectionEventSource.Log.CustomAttributeData_NamedArguments(attributeTypeName); + } + + public static void EventInfo_AddMethod(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_AddMethod(declaringTypeName, eventName); + } + + public static void EventInfo_RaiseMethod(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_RaiseMethod(declaringTypeName, eventName); + } + + public static void EventInfo_RemoveMethod(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_RemoveMethod(declaringTypeName, eventName); + } + + public static void EventInfo_CustomAttributes(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_CustomAttributes(declaringTypeName, eventName); + } + + public static void EventInfo_Name(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_Name(declaringTypeName, eventName); + } + + public static void EventInfo_DeclaringType(EventInfo eventInfo) + { + String declaringTypeName = eventInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String eventName = eventInfo.NameString(); + if (eventName == null) + return; + ReflectionEventSource.Log.EventInfo_DeclaringType(declaringTypeName, eventName); + } + + public static void FieldInfo_SetValue(FieldInfo fieldInfo, Object obj, Object value) + { + String declaringTypeName = fieldInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String fieldName = fieldInfo.NameString(); + if (fieldName == null) + return; + ReflectionEventSource.Log.FieldInfo_SetValue(declaringTypeName, fieldName); + } + + public static void FieldInfo_GetValue(FieldInfo fieldInfo, Object obj) + { + String declaringTypeName = fieldInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String fieldName = fieldInfo.NameString(); + if (fieldName == null) + return; + ReflectionEventSource.Log.FieldInfo_GetValue(declaringTypeName, fieldName); + } + + public static void FieldInfo_CustomAttributes(FieldInfo fieldInfo) + { + String declaringTypeName = fieldInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String fieldName = fieldInfo.NameString(); + if (fieldName == null) + return; + ReflectionEventSource.Log.FieldInfo_CustomAttributes(declaringTypeName, fieldName); + } + + public static void FieldInfo_Name(FieldInfo fieldInfo) + { + String declaringTypeName = fieldInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String fieldName = fieldInfo.NameString(); + if (fieldName == null) + return; + ReflectionEventSource.Log.FieldInfo_Name(declaringTypeName, fieldName); + } + + public static void FieldInfo_DeclaringType(FieldInfo fieldInfo) + { + String declaringTypeName = fieldInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String fieldName = fieldInfo.NameString(); + if (fieldName == null) + return; + ReflectionEventSource.Log.FieldInfo_DeclaringType(declaringTypeName, fieldName); + } + + public static void MethodBase_CustomAttributes(MethodBase methodBase) + { + String declaringTypeName = methodBase.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodBase.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_CustomAttributes(declaringTypeName, methodName); + } + + public static void MethodBase_Name(MethodBase methodBase) + { + String declaringTypeName = methodBase.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodBase.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_Name(declaringTypeName, methodName); + } + + public static void MethodBase_DeclaringType(MethodBase methodBase) + { + String declaringTypeName = methodBase.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodBase.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_DeclaringType(declaringTypeName, methodName); + } + + public static void MethodBase_GetParameters(MethodBase methodBase) + { + String declaringTypeName = methodBase.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodBase.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_GetParameters(declaringTypeName, methodName); + } + + public static void ConstructorInfo_Invoke(ConstructorInfo constructor, Object[] parameters) + { + String declaringTypeName = constructor.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = constructor.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_Invoke(declaringTypeName, methodName); + } + + public static void MethodBase_Invoke(MethodBase methodBase, Object obj, Object[] parameters) + { + String declaringTypeName = methodBase.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodBase.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodBase_Invoke(declaringTypeName, methodName); + } + + public static void MethodInfo_ReturnParameter(MethodInfo methodInfo) + { + String declaringTypeName = methodInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodInfo.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodInfo_ReturnParameter(declaringTypeName, methodName); + } + + public static void MethodInfo_ReturnType(MethodInfo methodInfo) + { + String declaringTypeName = methodInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodInfo.NameString(); + if (methodName == null) + return; + ReflectionEventSource.Log.MethodInfo_ReturnType(declaringTypeName, methodName); + } + + public static void MethodInfo_MakeGenericMethod(MethodInfo methodInfo, Type[] typeArguments) + { + String declaringTypeName = methodInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodInfo.NameString(); + if (methodName == null) + return; + String typeArgumentStrings = typeArguments.GenericTypeArgumentStrings(); + if (typeArgumentStrings == null) + return; + ReflectionEventSource.Log.MethodInfo_MakeGenericMethod(declaringTypeName, methodName, typeArgumentStrings); + } + + public static void MethodInfo_CreateDelegate(MethodInfo methodInfo, Type delegateType) + { + String declaringTypeName = methodInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodInfo.NameString(); + if (methodName == null) + return; + String delegateTypeName = delegateType.NameString(); + if (delegateType == null) + return; + ReflectionEventSource.Log.MethodInfo_CreateDelegate(declaringTypeName, methodName, delegateTypeName); + } + + public static void MethodInfo_CreateDelegate(MethodInfo methodInfo, Type delegateType, Object target) + { + String declaringTypeName = methodInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String methodName = methodInfo.NameString(); + if (methodName == null) + return; + String delegateTypeName = delegateType.NameString(); + if (delegateType == null) + return; + ReflectionEventSource.Log.MethodInfo_CreateDelegate(declaringTypeName, methodName, delegateTypeName); + } + + public static void PropertyInfo_GetValue(PropertyInfo propertyInfo, Object obj, Object[] index) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_GetValue(declaringTypeName, propertyName); + } + + public static void PropertyInfo_SetValue(PropertyInfo propertyInfo, Object obj, Object value, Object[] index) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_SetValue(declaringTypeName, propertyName); + } + + public static void PropertyInfo_GetMethod(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_GetMethod(declaringTypeName, propertyName); + } + + public static void PropertyInfo_SetMethod(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_SetMethod(declaringTypeName, propertyName); + } + + public static void PropertyInfo_GetConstantValue(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_GetConstantValue(declaringTypeName, propertyName); + } + + public static void PropertyInfo_PropertyType(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_PropertyType(declaringTypeName, propertyName); + } + + public static void PropertyInfo_CustomAttributes(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_CustomAttributes(declaringTypeName, propertyName); + } + + public static void PropertyInfo_Name(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_Name(declaringTypeName, propertyName); + } + + public static void PropertyInfo_DeclaringType(PropertyInfo propertyInfo) + { + String declaringTypeName = propertyInfo.DeclaringTypeNameString(); + if (declaringTypeName == null) + return; + String propertyName = propertyInfo.NameString(); + if (propertyName == null) + return; + ReflectionEventSource.Log.PropertyInfo_DeclaringType(declaringTypeName, propertyName); + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.cs b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.cs new file mode 100644 index 000000000..be029fe19 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Internal/Reflection/Tracing/ReflectionTrace.Public.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Runtime.CompilerServices; + +using ReflectionEventSource = global::System.Reflection.Runtime.Tracing.ReflectionEventSource; + +namespace Internal.Reflection.Tracing +{ + [DeveloperExperienceModeOnly] + public static partial class ReflectionTrace + { + public static bool Enabled + { + get + { + return ReflectionEventSource.IsInitialized && ReflectionEventSource.Log.IsEnabled(); + } + } + + public static String GetTraceString(this TypeInfo typeInfo) + { + return typeInfo.NameString(); + } + } +} + + diff --git a/src/System.Private.Reflection.Core/src/Resources/Resources.resx b/src/System.Private.Reflection.Core/src/Resources/Resources.resx new file mode 100644 index 000000000..f2bea8235 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Resources/Resources.resx @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="Bif_InvalidMetadata" xml:space="preserve"> + <value>A problem was found in this image's metadata.</value> + </data> + <data name="Acc_CreateAbstEx" xml:space="preserve"> + <value>Cannot create an instance of {0} because it is an abstract class.</value> + </data> + <data name="Acc_NotClassInit" xml:space="preserve"> + <value>Type initializer was not callable.</value> + </data> + <data name="Acc_ReadOnly" xml:space="preserve"> + <value>Cannot set a constant field.</value> + </data> + <data name="Arg_NotGenericMethodDefinition" xml:space="preserve"> + <value>{0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.</value> + </data> + <data name="Arg_NotGenericParameter" xml:space="preserve"> + <value>Method may only be called on a Type for which Type.IsGenericParameter is true.</value> + </data> + <data name="Arg_TypeLoadNullStr" xml:space="preserve"> + <value>A null or zero length string does not represent a valid Type.</value> + </data> + <data name="Argument_NotEnoughGenArguments" xml:space="preserve"> + <value>The type or method has {1} generic parameter(s), but {0} generic argument(s) were provided. A generic argument must be provided for each generic parameter.</value> + </data> + <data name="Reflection_CustomReflectionObjectsNotSupported" xml:space="preserve"> + <value>The object '{0}' was created by a custom ReflectionContext and cannot be used here.</value> + </data> + <data name="TypeLoad_TypeNotFoundByGetType" xml:space="preserve"> + <value>The type '{0}' cannot be found.</value> + </data> + <data name="TypeLoad_TypeNotFound" xml:space="preserve"> + <value>The type '{0}' cannot be found in the metadata for '{1}'.</value> + </data> + <data name="TypeLoad_BadEscape" xml:space="preserve"> + <value>An invalid escape sequence was found inside a type name.</value> + </data> + <data name="FileNotFound_AssemblyNotFound" xml:space="preserve"> + <value>Cannot load assembly '{0}'. No metadata found for this assembly.</value> + </data> + <data name="Format_StringZeroLength" xml:space="preserve"> + <value>String cannot have zero length.</value> + </data> + <data name="Arg_HTCapacityOverflow" xml:space="preserve"> + <value>Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table.</value> + </data> + <data name="NotSupported_ByRefReturn" xml:space="preserve"> + <value>ByRef return value not supported in reflection invocation.</value> + </data> + <data name="Security_InvalidAssemblyPublicKey" xml:space="preserve"> + <value>Invalid assembly public key.</value> + </data> + <data name="Arg_DlgtTargMeth" xml:space="preserve"> + <value>Cannot bind to the target method because its signature is not compatible with that of the delegate type.</value> + </data> + <data name="Arg_MustBeDelegate" xml:space="preserve"> + <value>Type must derive from Delegate.</value> + </data> + <data name="Arg_InvokeMethodMissingMetadata" xml:space="preserve"> + <value>Cannot create a delegate on type '{0}' as it is missing metadata for the Invoke method. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=616867</value> + </data> + <data name="Argument_AddingDuplicate" xml:space="preserve"> + <value>An item with the same key has already been added.</value> + </data> + <data name="Argument_InvalidHandle" xml:space="preserve"> + <value>The handle is invalid.</value> + </data> + <data name="Argument_ResolveMethodHandle" xml:space="preserve"> + <value>Type handle '{0}' and method handle with declaring type '{1}' are incompatible. Get RuntimeMethodHandle and declaring RuntimeTypeHandle off the same MethodBase.</value> + </data> + <data name="Argument_ResolveFieldHandle" xml:space="preserve"> + <value>Type handle '{0}' and field handle with declaring type '{1}' are incompatible. Get RuntimeFieldHandle and declaring RuntimeTypeHandle off the same FieldInfo.</value> + </data> + <data name="Argument_MethodDeclaringTypeGeneric" xml:space="preserve"> + <value>Cannot resolve method {0} because the declaring type of the method handle is generic. Explicitly provide the declaring type to GetMethodFromHandle.</value> + </data> + <data name="Argument_FieldDeclaringTypeGeneric" xml:space="preserve"> + <value>Cannot resolve field {0} because the declaring type of the field handle is generic. Explicitly provide the declaring type to GetFieldFromHandle.</value> + </data> + <data name="Arg_UnboundGenParam" xml:space="preserve"> + <value>Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.</value> + </data> + <data name="Argument_AssemblyGetTypeCannotSpecifyAssembly" xml:space="preserve"> + <value>Type names passed to Assembly.GetType() must not specify an assembly.</value> + </data> + <data name="InvalidOperation_NoPublicAddMethod" xml:space="preserve"> + <value>Cannot add the event handler since no public add method exists for the event.</value> + </data> + <data name="InvalidOperation_NoPublicRemoveMethod" xml:space="preserve"> + <value>Cannot remove the event handler since no public remove method exists for the event.</value> + </data> +</root> diff --git a/src/System.Private.Reflection.Core/src/Resources/Strings.resx b/src/System.Private.Reflection.Core/src/Resources/Strings.resx new file mode 100644 index 000000000..f2bea8235 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Resources/Strings.resx @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="Bif_InvalidMetadata" xml:space="preserve"> + <value>A problem was found in this image's metadata.</value> + </data> + <data name="Acc_CreateAbstEx" xml:space="preserve"> + <value>Cannot create an instance of {0} because it is an abstract class.</value> + </data> + <data name="Acc_NotClassInit" xml:space="preserve"> + <value>Type initializer was not callable.</value> + </data> + <data name="Acc_ReadOnly" xml:space="preserve"> + <value>Cannot set a constant field.</value> + </data> + <data name="Arg_NotGenericMethodDefinition" xml:space="preserve"> + <value>{0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.</value> + </data> + <data name="Arg_NotGenericParameter" xml:space="preserve"> + <value>Method may only be called on a Type for which Type.IsGenericParameter is true.</value> + </data> + <data name="Arg_TypeLoadNullStr" xml:space="preserve"> + <value>A null or zero length string does not represent a valid Type.</value> + </data> + <data name="Argument_NotEnoughGenArguments" xml:space="preserve"> + <value>The type or method has {1} generic parameter(s), but {0} generic argument(s) were provided. A generic argument must be provided for each generic parameter.</value> + </data> + <data name="Reflection_CustomReflectionObjectsNotSupported" xml:space="preserve"> + <value>The object '{0}' was created by a custom ReflectionContext and cannot be used here.</value> + </data> + <data name="TypeLoad_TypeNotFoundByGetType" xml:space="preserve"> + <value>The type '{0}' cannot be found.</value> + </data> + <data name="TypeLoad_TypeNotFound" xml:space="preserve"> + <value>The type '{0}' cannot be found in the metadata for '{1}'.</value> + </data> + <data name="TypeLoad_BadEscape" xml:space="preserve"> + <value>An invalid escape sequence was found inside a type name.</value> + </data> + <data name="FileNotFound_AssemblyNotFound" xml:space="preserve"> + <value>Cannot load assembly '{0}'. No metadata found for this assembly.</value> + </data> + <data name="Format_StringZeroLength" xml:space="preserve"> + <value>String cannot have zero length.</value> + </data> + <data name="Arg_HTCapacityOverflow" xml:space="preserve"> + <value>Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table.</value> + </data> + <data name="NotSupported_ByRefReturn" xml:space="preserve"> + <value>ByRef return value not supported in reflection invocation.</value> + </data> + <data name="Security_InvalidAssemblyPublicKey" xml:space="preserve"> + <value>Invalid assembly public key.</value> + </data> + <data name="Arg_DlgtTargMeth" xml:space="preserve"> + <value>Cannot bind to the target method because its signature is not compatible with that of the delegate type.</value> + </data> + <data name="Arg_MustBeDelegate" xml:space="preserve"> + <value>Type must derive from Delegate.</value> + </data> + <data name="Arg_InvokeMethodMissingMetadata" xml:space="preserve"> + <value>Cannot create a delegate on type '{0}' as it is missing metadata for the Invoke method. For more information, please visit http://go.microsoft.com/fwlink/?LinkID=616867</value> + </data> + <data name="Argument_AddingDuplicate" xml:space="preserve"> + <value>An item with the same key has already been added.</value> + </data> + <data name="Argument_InvalidHandle" xml:space="preserve"> + <value>The handle is invalid.</value> + </data> + <data name="Argument_ResolveMethodHandle" xml:space="preserve"> + <value>Type handle '{0}' and method handle with declaring type '{1}' are incompatible. Get RuntimeMethodHandle and declaring RuntimeTypeHandle off the same MethodBase.</value> + </data> + <data name="Argument_ResolveFieldHandle" xml:space="preserve"> + <value>Type handle '{0}' and field handle with declaring type '{1}' are incompatible. Get RuntimeFieldHandle and declaring RuntimeTypeHandle off the same FieldInfo.</value> + </data> + <data name="Argument_MethodDeclaringTypeGeneric" xml:space="preserve"> + <value>Cannot resolve method {0} because the declaring type of the method handle is generic. Explicitly provide the declaring type to GetMethodFromHandle.</value> + </data> + <data name="Argument_FieldDeclaringTypeGeneric" xml:space="preserve"> + <value>Cannot resolve field {0} because the declaring type of the field handle is generic. Explicitly provide the declaring type to GetFieldFromHandle.</value> + </data> + <data name="Arg_UnboundGenParam" xml:space="preserve"> + <value>Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.</value> + </data> + <data name="Argument_AssemblyGetTypeCannotSpecifyAssembly" xml:space="preserve"> + <value>Type names passed to Assembly.GetType() must not specify an assembly.</value> + </data> + <data name="InvalidOperation_NoPublicAddMethod" xml:space="preserve"> + <value>Cannot add the event handler since no public add method exists for the event.</value> + </data> + <data name="InvalidOperation_NoPublicRemoveMethod" xml:space="preserve"> + <value>Cannot remove the event handler since no public remove method exists for the event.</value> + </data> +</root> diff --git a/src/System.Private.Reflection.Core/src/Resources/System.Private.Reflection.Core.rd.xml b/src/System.Private.Reflection.Core/src/Resources/System.Private.Reflection.Core.rd.xml new file mode 100644 index 000000000..3498c6f52 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/Resources/System.Private.Reflection.Core.rd.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" ?> +<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata"> + <Library Name="*System.Private.Reflection.Core*"> + <Assembly Name="System.Private.Reflection.Core"> + <Namespace Name="System"> + <Type Name="DBNull" Browse="All"> + </Type> + </Namespace> + </Assembly> + </Library> +</Directives> diff --git a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj new file mode 100644 index 000000000..cbd265fb9 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>System.Private.Reflection.Core</AssemblyName> + <OutputType>Library</OutputType> + <ProjectGuid>{999BB20D-A032-4836-A587-627D243C1668}</ProjectGuid> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <EnableWinRT>true</EnableWinRT> + <CLSCompliant>false</CLSCompliant> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\..\AotPackageReference\AotPackageReference.depproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + </ProjectReference> + + <ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" /> + <ProjectReference Include="..\..\System.Private.Reflection\src\System.Private.Reflection.csproj" /> + <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" /> + + <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.IO.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Diagnostics.Tracing.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Resources.ResourceManager.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Reflection.Primitives.dll" /> + </ItemGroup> + + <ItemGroup> + <Compile Include="System\DBNull.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\AssemblyNameHelpers.StrongName.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\AssemblyNameHelpers.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\AssemblyNameLexer.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\AssemblyNameParser.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\RuntimeAssembly.cs" /> + <Compile Include="System\Reflection\Runtime\Assemblies\RuntimeAssemblyName.cs" /> + <Compile Include="System\Reflection\Runtime\CustomAttributes\RuntimeCustomAttributeData.cs" /> + <Compile Include="System\Reflection\Runtime\CustomAttributes\RuntimeNormalCustomAttributeData.cs" /> + <Compile Include="System\Reflection\Runtime\CustomAttributes\RuntimePseudoCustomAttributeData.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DefaultDispenserPolicy.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\Dispenser.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserAlgorithm.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserFactory.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserPolicy.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserScenario.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserThatAlwaysCreates.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserThatAlwaysReuses.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserThatReusesAsLongAsKeyIsAlive.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserThatReusesAsLongAsValueIsAlive.cs" /> + <Compile Include="System\Reflection\Runtime\Dispensers\DispenserThatLatchesTypeInfosInsideTypes.cs" /> + <Compile Include="System\Reflection\Runtime\EventInfos\RuntimeEventInfo.cs" /> + <Compile Include="System\Reflection\Runtime\FieldInfos\RuntimeFieldInfo.cs" /> + <Compile Include="System\Reflection\Runtime\FieldInfos\LiteralFieldAccessor.cs" /> + <Compile Include="System\Reflection\Runtime\General\Assignability.cs" /> + <Compile Include="System\Reflection\Runtime\General\ReflectionCoreCallbacksImplementation.cs" /> + <Compile Include="System\Reflection\Runtime\General\Dispensers.cs" /> + <Compile Include="System\Reflection\Runtime\General\MetadataReaderExtensions.cs" /> + <Compile Include="System\Reflection\Runtime\General\NamespaceChain.cs" /> + <Compile Include="System\Reflection\Runtime\General\QHandles.cs" /> + <Compile Include="System\Reflection\Runtime\General\RuntimeNamespaceInfo.cs" /> + <Compile Include="System\Reflection\Runtime\General\RuntimeTypeExtensions.cs" /> + <Compile Include="System\Reflection\Runtime\General\RuntimeTypeUnifierEx.cs" /> + <Compile Include="System\Reflection\Runtime\General\ToStringUtils.cs" /> + <Compile Include="System\Reflection\Runtime\General\TypeContext.cs" /> + <Compile Include="System\Reflection\Runtime\General\TypeResolver.cs" /> + <Compile Include="System\Reflection\Runtime\General\TypeExtensions.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\OpenMethodInvoker.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeConstructedGenericMethodInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeConstructorInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimePlainConstructorInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeSyntheticConstructorInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeMethodCommon.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeMethodInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeNamedMethodInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\RuntimeSyntheticMethodInfo.cs" /> + <Compile Include="System\Reflection\Runtime\MethodInfos\SyntheticMethodId.cs" /> + <Compile Include="System\Reflection\Runtime\Modules\RuntimeModule.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeFatMethodParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeMethodParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimePropertyIndexParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeThinMethodParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\ParameterInfos\RuntimeSyntheticParameterInfo.cs" /> + <Compile Include="System\Reflection\Runtime\PropertyInfos\RuntimePropertyInfo.cs" /> + <Compile Include="System\Reflection\Runtime\Tracing\ReflectionEventSource.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeArrayTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeConstructedGenericTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeGenericParameterTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeHasElementTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeNamedTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeNoMetadataNamedTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeBlockedTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\RuntimeTypeInfo.cs" /> + <Compile Include="System\Reflection\Runtime\TypeInfos\TypeInfoCachedData.cs" /> + <Compile Include="System\Reflection\Runtime\Types\RuntimeGenericParameterType.cs" /> + <Compile Include="System\Reflection\Runtime\Types\RuntimeGenericParameterTypeForTypes.cs" /> + <Compile Include="System\Reflection\Runtime\Types\RuntimeGenericParameterTypeForMethods.cs" /> + <Compile Include="System\Reflection\Runtime\Types\RuntimeInspectionOnlyNamedType.cs" /> + <Compile Include="System\Reflection\Runtime\Types\ShadowRuntimeInspectionOnlyNamedType.cs" /> + <Compile Include="System\Reflection\Runtime\TypeParsing\TypeName.cs" /> + <Compile Include="System\Reflection\Runtime\TypeParsing\TypeLexer.cs" /> + <Compile Include="System\Reflection\Runtime\TypeParsing\TypeParser.cs" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Internal\Reflection\Core\AssemblyBinder.cs" /> + <Compile Include="Internal\Reflection\Core\FoundationTypes.cs" /> + <Compile Include="Internal\Reflection\Core\ReflectionDomain.cs" /> + <Compile Include="Internal\Reflection\Core\ReflectionDomainSetup.cs" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Internal\Reflection\Core\Execution\ExecutionDomain.cs" /> + <Compile Include="Internal\Reflection\Core\Execution\ExecutionEnvironment.cs" /> + <Compile Include="Internal\Reflection\Core\Execution\FieldAccessor.cs" /> + <Compile Include="Internal\Reflection\Core\Execution\MethodInvoker.cs" /> + <Compile Include="Internal\Reflection\Core\Execution\ReflectionCoreExecution.cs" /> + <Compile Include="Internal\Reflection\Core\Execution\InvokerOptions.cs" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Internal\Reflection\Tracing\ReflectionTrace.Public.cs" /> + <Compile Include="Internal\Reflection\Tracing\ReflectionTrace.Public.Events.cs" /> + <Compile Include="Internal\Reflection\Tracing\ReflectionTrace.Internal.cs" /> + <Compile Include="Internal\Reflection\Tracing\ITraceableTypeMember.cs" /> + </ItemGroup> + <ItemGroup> + <Compile Include="...\..\common\src\System\CommonRuntimeTypes.cs" /> + <Compile Include="...\..\common\src\System\NotImplemented.cs" /> + <Compile Include="...\..\common\src\System\Collections\Generic\LowLevelList.cs" /> + <Compile Include="...\..\common\src\System\Collections\Generic\LowLevelDictionary.cs" /> + <Compile Include="...\..\common\src\System\Linq\LowLevelEnumerable.cs" /> + <Compile Include="...\..\common\src\System\Collections\HashHelpers.cs" /> + <Compile Include="...\..\common\src\System\Collections\Generic\EnumerableExtensions.cs" /> + <Compile Include="...\..\common\src\System\Collections\Generic\Empty.cs" /> + <Compile Include="...\..\common\src\System\Collections\Concurrent\ConcurrentUnifier.cs" /> + <Compile Include="...\..\common\src\System\Collections\Concurrent\ConcurrentUnifierW.cs" /> + <Compile Include="...\..\common\src\System\Collections\Concurrent\ConcurrentUnifierWKeyed.cs" /> + <Compile Include="...\..\common\src\System\Collections\Concurrent\IKeyedItem.cs" /> + <Compile Include="...\..\common\src\System\Runtime\CompilerServices\DeveloperExperienceModeOnlyAttribute.cs" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/src/System.Private.Reflection.Core/src/System/DBNull.cs b/src/System.Private.Reflection.Core/src/System/DBNull.cs new file mode 100644 index 000000000..df48d9933 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/DBNull.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System.Diagnostics; + +namespace System +{ + // + // This is not actually an instance of the System.DBNull type exposed out of System.Data.Common. + // But this is also true on CoreCLR, so it's still compatible! + // + // This will of course, confound anyone who actually tries to compare the real System.DBNull to what we return. + // This is, however, the least worst of many bad options. Current apps out in the wild do not have access to a + // contract exposing System.DBNull so this hack of checking the type name via reflection is what they actually do. + // + // Official guidance is: Call ParameterInfo.HasDefaultValue. + // + + // + // @todo: B#1190393 - this type should be "internal" but has to be made "public" in order for it to be reflectable under + // our reflection-block mechanism. The ReflectionBlock mechanism is on the block itself, so once that's done, we can make this type + // "internal" too. + // + public sealed class DBNull + { + private DBNull() + { + } + + internal static readonly Object Value = new DBNull(); + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.StrongName.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.StrongName.cs new file mode 100644 index 000000000..d1b6f3b53 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.StrongName.cs @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + + +/*============================================================ +** + Type: AssemblyNameHelpers +** +==============================================================*/ + +using global::System; +using global::System.IO; +using global::System.Text; +using global::System.Collections.Generic; +using global::Internal.Runtime.Augments; +using Buffer = System.Buffer; + +using SecurityException = global::System.Security.SecurityException; + +namespace System.Reflection.Runtime.Assemblies +{ + internal static partial class AssemblyNameHelpers + { + internal static byte[] ComputePublicKeyToken(byte[] publicKey) + { + if (publicKey == null) + return null; + + if (publicKey.Length == 0) + return Array.Empty<byte>(); + + if (!IsValidPublicKey(publicKey)) + throw new SecurityException(SR.Security_InvalidAssemblyPublicKey); + + byte[] hash = WinRTInterop.Callbacks.ComputeSHA1(publicKey); + byte[] pkt = new byte[PUBLIC_KEY_TOKEN_LEN]; + for (int i = 0; i < PUBLIC_KEY_TOKEN_LEN; i++) + { + pkt[i] = hash[hash.Length - i - 1]; + } + return pkt; + } + + // + // This validation logic is a manual port of StrongNameIsValidPublicKey() in the desktop CLR (see clr\src\StrongName\api\StrongNameInternal.cpp) + // + private static bool IsValidPublicKey(byte[] publicKey) + { + uint publicKeyLength = (uint)(publicKey.Length); + + // The buffer must be at least as large as the public key structure (for compat with desktop, we actually compare with the size of the header + 4). + if (publicKeyLength < SizeOfPublicKeyBlob + 4) + return false; + + + // Poor man's reinterpret_cast into the PublicKeyBlob structure. + uint[] publicKeyBlob = new uint[3]; + Buffer.BlockCopy(publicKey, 0, publicKeyBlob, 0, (int)SizeOfPublicKeyBlob); + uint sigAlgID = publicKeyBlob[0]; + uint hashAlgID = publicKeyBlob[1]; + uint cbPublicKey = publicKeyBlob[2]; + + // The buffer must be the same size as the structure header plus the trailing key data + if (cbPublicKey != publicKeyLength - SizeOfPublicKeyBlob) + return false; + + // The buffer itself looks reasonable, but the public key structure needs to be validated as well + + // The ECMA key doesn't look like a valid key so it will fail the below checks. If we were passed that + // key, then we can skip them. + if (ByteArrayEquals(publicKey, EcmaKey)) + return true; + + // If a hash algorithm is specified, it must be a sensible value + bool fHashAlgorithmValid = GetAlgClass(hashAlgID) == ALG_CLASS_HASH && GetAlgSid(hashAlgID) == ALG_SID_SHA1; + if (hashAlgID != 0 && !fHashAlgorithmValid) + return false; + + // If a signature algorithm is specified, it must be a sensible value + bool fSignatureAlgorithmValid = GetAlgClass(sigAlgID) == ALG_CLASS_SIGNATURE; + if (sigAlgID != 0 && !fSignatureAlgorithmValid) + return false; + + // The key blob must indicate that it is a PUBLICKEYBLOB + if (publicKey[SizeOfPublicKeyBlob] != PUBLICKEYBLOB) + return false; + + //@todo: Desktop also tries to import the public key blob using the Crypto api as further validation - not clear if there's any non-banned API to do this. + + return true; + } + + private static bool ByteArrayEquals(byte[] b1, byte[] b2) + { + if (b1.Length != b2.Length) + return false; + for (int i = 0; i < b1.Length; i++) + { + if (b1[i] != b2[i]) + return false; + } + return true; + } + + // Constants and macros copied from WinCrypt.h: + + private static uint GetAlgClass(uint x) + { + return (x & (7 << 13)); + } + + private static uint GetAlgSid(uint x) + { + return (x & (511)); + } + + private const uint ALG_CLASS_HASH = (4 << 13); + private const uint ALG_SID_SHA1 = 4; + private const uint ALG_CLASS_SIGNATURE = (1 << 13); + private const uint PUBLICKEYBLOB = 0x6; + + private const uint SizeOfPublicKeyBlob = 12; + + private const int PUBLIC_KEY_TOKEN_LEN = 8; + + private static byte[] EcmaKey = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.cs new file mode 100644 index 000000000..51778e061 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameHelpers.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +/*============================================================ +** + Type: AssemblyNameHelpers +** +==============================================================*/ + +using global::System; +using global::System.Globalization; +using global::System.IO; +using global::System.Text; +using global::System.Collections.Generic; + +namespace System.Reflection.Runtime.Assemblies +{ + internal static partial class AssemblyNameHelpers + { + internal static String ComputeDisplayName(RuntimeAssemblyName a) + { + if (a.Name == String.Empty) + throw new FileLoadException(); + + StringBuilder sb = new StringBuilder(); + if (a.Name != null) + { + sb.AppendQuoted(a.Name); + } + + if (a.Version != null) + { + sb.Append(", Version="); + sb.Append(a.Version.ToString()); + } + + String cultureName = a.CultureName; + if (cultureName != null) + { + if (cultureName == String.Empty) + cultureName = "neutral"; + sb.Append(", Culture="); + sb.AppendQuoted(cultureName); + } + + byte[] pkt = a.PublicKeyOrToken; + if (pkt != null) + { + if (0 != (a.Flags & AssemblyNameFlags.PublicKey)) + pkt = ComputePublicKeyToken(pkt); + + if (pkt.Length > PUBLIC_KEY_TOKEN_LEN) + throw new ArgumentException(); + + sb.Append(", PublicKeyToken="); + if (pkt.Length == 0) + sb.Append("null"); + else + { + foreach (byte b in pkt) + { + sb.Append(b.ToString("x2", CultureInfo.InvariantCulture)); + } + } + } + + if (0 != (a.Flags & AssemblyNameFlags.Retargetable)) + sb.Append(", Retargetable=Yes"); + + AssemblyContentType contentType = ExtractAssemblyContentType(a.Flags); + if (contentType == AssemblyContentType.WindowsRuntime) + sb.Append(", ContentType=WindowsRuntime"); + + // NOTE: By design (desktop compat) AssemblyName.FullName and ToString() do not include ProcessorArchitecture. + + return sb.ToString(); + } + + private static void AppendQuoted(this StringBuilder sb, String s) + { + bool needsQuoting = false; + const char quoteChar = '\"'; + + //@todo: App-compat: You can use double or single quotes to quote a name, and Fusion (or rather the IdentityAuthority) picks one + // by some algorithm. Rather than guess at it, I'll just use double-quote consistently. + if (s != s.Trim() || s.Contains("\"") || s.Contains("\'")) + needsQuoting = true; + + if (needsQuoting) + sb.Append(quoteChar); + + for (int i = 0; i < s.Length; i++) + { + bool addedEscape = false; + foreach (KeyValuePair<char, String> kv in AssemblyNameLexer.EscapeSequences) + { + String escapeReplacement = kv.Value; + if (!(s[i] == escapeReplacement[0])) + continue; + if ((s.Length - i) < escapeReplacement.Length) + continue; + String prefix = s.Substring(i, escapeReplacement.Length); + if (prefix == escapeReplacement) + { + sb.Append('\\'); + sb.Append(kv.Key); + addedEscape = true; + } + } + + if (!addedEscape) + sb.Append(s[i]); + } + + if (needsQuoting) + sb.Append(quoteChar); + } + + + // + // Converts an AssemblyName to a RuntimeAssemblyName that is free from any future mutations on the AssemblyName. + // + internal static RuntimeAssemblyName ToRuntimeAssemblyName(this AssemblyName assemblyName) + { + if (assemblyName.Name == null) + throw new ArgumentException(); + + AssemblyNameFlags flags = assemblyName.Flags; + AssemblyContentType contentType = assemblyName.ContentType; + ProcessorArchitecture processorArchitecture = assemblyName.ProcessorArchitecture; + AssemblyNameFlags combinedFlags = CombineAssemblyNameFlags(flags, contentType, processorArchitecture); + byte[] pkOriginal; + if (0 != (flags & AssemblyNameFlags.PublicKey)) + pkOriginal = assemblyName.GetPublicKey(); + else + pkOriginal = assemblyName.GetPublicKeyToken(); + + // AssemblyName's PKT property getters do NOT copy the array before giving it out. Make our own copy + // as the original is wide open to tampering by anyone. + byte[] pkCopy = null; + if (pkOriginal != null) + { + pkCopy = new byte[pkOriginal.Length]; + ((ICollection<byte>)pkOriginal).CopyTo(pkCopy, 0); + } + + return new RuntimeAssemblyName(assemblyName.Name, assemblyName.Version, assemblyName.CultureName, combinedFlags, pkCopy); + } + + // + // These helpers convert between the combined flags+contentType+processorArchitecture value and the separated parts. + // + // Since these are only for trusted callers, they do NOT check for out of bound bits. + // + + internal static AssemblyContentType ExtractAssemblyContentType(AssemblyNameFlags flags) + { + return (AssemblyContentType)((((int)flags) >> 9) & 0x7); + } + + internal static ProcessorArchitecture ExtractProcessorArchitecture(AssemblyNameFlags flags) + { + return (ProcessorArchitecture)((((int)flags) >> 4) & 0x7); + } + + internal static AssemblyNameFlags ExtractAssemblyNameFlags(AssemblyNameFlags combinedFlags) + { + return combinedFlags & unchecked((AssemblyNameFlags)0xFFFFF10F); + } + + internal static AssemblyNameFlags CombineAssemblyNameFlags(AssemblyNameFlags flags, AssemblyContentType contentType, ProcessorArchitecture processorArchitecture) + { + return (AssemblyNameFlags)(((int)flags) | (((int)contentType) << 9) | ((int)processorArchitecture << 4)); + } + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameLexer.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameLexer.cs new file mode 100644 index 000000000..543ec5478 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameLexer.cs @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Text; +using global::System.Globalization; +using global::System.Collections.Generic; +using global::System.Runtime.InteropServices; + +namespace System.Reflection.Runtime.Assemblies +{ + // + // A simple lexer for assembly display names. + // + internal struct AssemblyNameLexer + { + internal AssemblyNameLexer(String s) + { + // Convert string to char[] with NUL terminator. (An actual NUL terminator in the input string will be treated + // as an actual end of string: this is compatible with desktop behavior.) + char[] chars = new char[s.Length + 1]; + s.CopyTo(0, chars, 0, s.Length); + _chars = chars; + _index = 0; + } + + // + // Return the next token in assembly name. If you expect the result to be DisplayNameToken.String, + // use GetNext(out String) instead. + // + internal Token GetNext() + { + String ignore; + return GetNext(out ignore); + } + + // + // Return the next token in assembly name. If the result is DisplayNameToken.String, + // sets "tokenString" to the tokenized string. + // + internal Token GetNext(out String tokenString) + { + tokenString = null; + while (Char.IsWhiteSpace(_chars[_index])) + _index++; + + char c = _chars[_index++]; + if (c == 0) + return Token.End; + if (c == ',') + return Token.Comma; + if (c == '=') + return Token.Equals; + + StringBuilder sb = new StringBuilder(); + + char quoteChar = (char)0; + if (c == '\'' || c == '\"') + { + quoteChar = c; + c = _chars[_index++]; + } + + for (; ;) + { + if (c == 0) + { + _index--; + break; // Terminate: End of string (desktop compat: if string was quoted, permitted to terminate without end-quote.) + } + + if (quoteChar != 0 && c == quoteChar) + break; // Terminate: Found closing quote of quoted string. + + if (quoteChar == 0 && (c == ',' || c == '=')) + { + _index--; + break; // Terminate: Found start of a new ',' or '=' token. + } + + if (quoteChar == 0 && (c == '\'' || c == '\"')) + throw new FileLoadException(); // Desktop compat: Unescaped quote illegal unless entire string is quoted. + + if (c == '\\') + { + c = _chars[_index++]; + bool matched = false; + foreach (KeyValuePair<char, String> kv in EscapeSequences) + { + if (c == kv.Key) + { + matched = true; + sb.Append(kv.Value); + break; + } + } + if (!matched) + throw new FileLoadException(); // Unrecognized escape + } + else + { + sb.Append(c); + } + + c = _chars[_index++]; + } + + tokenString = sb.ToString(); + if (quoteChar == 0) + tokenString = tokenString.Trim(); // Unless quoted, whitespace at beginning or end doesn't count. + return Token.String; + } + + internal static KeyValuePair<char, String>[] EscapeSequences = + { + new KeyValuePair<char, String>('\\', "\\"), + new KeyValuePair<char, String>(',', ","), + new KeyValuePair<char, String>('=', "="), + new KeyValuePair<char, String>('\'', "'"), + new KeyValuePair<char, String>('\"', "\""), + new KeyValuePair<char, String>('n', Environment.NewLine), + new KeyValuePair<char, String>('t', "\t"), + }; + + // Token categories for display name lexer. + internal enum Token + { + Equals = 1, + Comma = 2, + String = 3, + End = 4, + } + + private char[] _chars; + private int _index; + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameParser.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameParser.cs new file mode 100644 index 000000000..5b6c23fb6 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/AssemblyNameParser.cs @@ -0,0 +1,230 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Text; +using global::System.Diagnostics; +using global::System.Globalization; +using global::System.Collections.Generic; +using global::System.Runtime.InteropServices; + +namespace System.Reflection.Runtime.Assemblies +{ + // + // Parses an assembly name. + // + internal static class AssemblyNameParser + { + internal static void Parse(AssemblyName blank, String s) + { + if (s == null) + throw new ArgumentNullException(); + RuntimeAssemblyName runtimeAssemblyName = Parse(s); + runtimeAssemblyName.CopyToAssemblyName(blank); + } + + internal static RuntimeAssemblyName Parse(String s) + { + Debug.Assert(s != null); + AssemblyNameLexer lexer = new AssemblyNameLexer(s); + + // Name must come first. + String name; + AssemblyNameLexer.Token token = lexer.GetNext(out name); + if (token != AssemblyNameLexer.Token.String) + { + if (token == AssemblyNameLexer.Token.End) + throw new ArgumentException(SR.Format_StringZeroLength); + else + throw new FileLoadException(); + } + + if (name == String.Empty) + throw new FileLoadException(); + + Version version = null; + String cultureName = null; + byte[] pkt = null; + AssemblyNameFlags flags = 0; + + LowLevelList<String> alreadySeen = new LowLevelList<String>(); + token = lexer.GetNext(); + while (token != AssemblyNameLexer.Token.End) + { + if (token != AssemblyNameLexer.Token.Comma) + throw new FileLoadException(); + String attributeName; + + token = lexer.GetNext(out attributeName); + if (token != AssemblyNameLexer.Token.String) + throw new FileLoadException(); + token = lexer.GetNext(); + + // Compat note: Inside AppX apps, the desktop CLR's AssemblyName parser skips past any elements that don't follow the "<Something>=<Something>" pattern. + // (when running classic Windows apps, such an illegal construction throws an exception as expected.) + // Naturally, at least one app unwittingly takes advantage of this. + if (token == AssemblyNameLexer.Token.Comma || token == AssemblyNameLexer.Token.End) + continue; + + if (token != AssemblyNameLexer.Token.Equals) + throw new FileLoadException(); + String attributeValue; + token = lexer.GetNext(out attributeValue); + if (token != AssemblyNameLexer.Token.String) + throw new FileLoadException(); + + if (attributeName == String.Empty) + throw new FileLoadException(); + + for (int i = 0; i < alreadySeen.Count; i++) + { + if (alreadySeen[i].Equals(attributeName, StringComparison.OrdinalIgnoreCase)) + throw new FileLoadException(); // Cannot specify the same attribute twice. + } + alreadySeen.Add(attributeName); + + if (attributeName.Equals("Version", StringComparison.OrdinalIgnoreCase)) + { + version = ParseVersion(attributeValue); + } + + if (attributeName.Equals("Culture", StringComparison.OrdinalIgnoreCase)) + { + cultureName = ParseCulture(attributeValue); + } + + if (attributeName.Equals("PublicKeyToken", StringComparison.OrdinalIgnoreCase)) + { + pkt = ParsePKT(attributeValue); + } + + if (attributeName.Equals("ProcessorArchitecture", StringComparison.OrdinalIgnoreCase)) + { + flags |= (AssemblyNameFlags)(((int)ParseProcessorArchitecture(attributeValue)) << 4); + } + + if (attributeName.Equals("Retargetable", StringComparison.OrdinalIgnoreCase)) + { + if (attributeValue.Equals("Yes", StringComparison.OrdinalIgnoreCase)) + flags |= AssemblyNameFlags.Retargetable; + else if (attributeValue.Equals("No", StringComparison.OrdinalIgnoreCase)) + { + // nothing to do + } + else + throw new FileLoadException(); + } + + if (attributeName.Equals("ContentType", StringComparison.OrdinalIgnoreCase)) + { + if (attributeValue.Equals("WindowsRuntime", StringComparison.OrdinalIgnoreCase)) + flags |= (AssemblyNameFlags)(((int)AssemblyContentType.WindowsRuntime) << 9); + else + throw new FileLoadException(); + } + + // Desktop compat: If we got here, the attribute name is unknown to us. Ignore it (as long it's not duplicated.) + token = lexer.GetNext(); + } + return new RuntimeAssemblyName(name, version, cultureName, flags, pkt); + } + + private static Version ParseVersion(String attributeValue) + { + String[] parts = attributeValue.Split('.'); + if (parts.Length > 4) + throw new FileLoadException(); + ushort[] versionNumbers = new ushort[4]; + for (int i = 0; i < versionNumbers.Length; i++) + { + if (i >= parts.Length) + versionNumbers[i] = ushort.MaxValue; + else + { + // Desktop compat: TryParse is a little more forgiving than Fusion. + for (int j = 0; j < parts[i].Length; j++) + { + if (!Char.IsDigit(parts[i][j])) + throw new FileLoadException(); + } + if (!(ushort.TryParse(parts[i], out versionNumbers[i]))) + { + if (parts[i] == string.Empty) + { + // Desktop compat: Empty strings are a synonym for 0 + versionNumbers[i] = 0; + } + else + { + throw new FileLoadException(); + } + } + } + } + + if (parts.Length == 1) + return null; // Desktop compat: if only major version present, treat as no version. + + return new Version(versionNumbers[0], versionNumbers[1], versionNumbers[2], versionNumbers[3]); + } + + private static String ParseCulture(String attributeValue) + { + if (attributeValue.Equals("Neutral", StringComparison.OrdinalIgnoreCase)) + { + return ""; + } + else + { + CultureInfo culture = new CultureInfo(attributeValue); // Force a CultureNotFoundException if not a valid culture. + return culture.Name; + } + } + + private static byte[] ParsePKT(String attributeValue) + { + if (attributeValue.Equals("null", StringComparison.OrdinalIgnoreCase) || attributeValue == String.Empty) + return Array.Empty<byte>(); + + if (attributeValue.Length != 8 * 2) + throw new FileLoadException(); + + byte[] pkt = new byte[8]; + int srcIndex = 0; + for (int i = 0; i < 8; i++) + { + char hi = attributeValue[srcIndex++]; + char lo = attributeValue[srcIndex++]; + pkt[i] = (byte)((ParseHexNybble(hi) << 4) | ParseHexNybble(lo)); + } + return pkt; + } + + private static ProcessorArchitecture ParseProcessorArchitecture(String attributeValue) + { + if (attributeValue.Equals("msil", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.MSIL; + if (attributeValue.Equals("x86", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.X86; + if (attributeValue.Equals("ia64", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.IA64; + if (attributeValue.Equals("amd64", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.Amd64; + if (attributeValue.Equals("arm", StringComparison.OrdinalIgnoreCase)) + return ProcessorArchitecture.Arm; + throw new FileLoadException(); + } + + private static byte ParseHexNybble(char c) + { + if (c >= '0' && c <= '9') + return (byte)(c - '0'); + if (c >= 'a' && c <= 'f') + return (byte)(c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (byte)(c - 'A' + 10); + throw new FileLoadException(); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs new file mode 100644 index 000000000..6c0c38aae --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssembly.cs @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Text; +using global::System.Diagnostics; +using global::System.Reflection; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Modules; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.TypeParsing; +using global::System.Reflection.Runtime.CustomAttributes; +using global::System.Collections.Generic; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Tracing; + +namespace System.Reflection.Runtime.Assemblies +{ + // + // The runtime's implementation of an Assembly. + // + internal sealed partial class RuntimeAssembly : ExtensibleAssembly, IEquatable<RuntimeAssembly> + { + private RuntimeAssembly(MetadataReader reader, ScopeDefinitionHandle scope, IEnumerable<QScopeDefinition> overflowScopes) + { + Scope = new QScopeDefinition(reader, scope); + OverflowScopes = overflowScopes; + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Assembly_CustomAttributes(this); + + foreach (QScopeDefinition scope in AllScopes) + { + foreach (CustomAttributeData cad in RuntimeCustomAttributeData.GetCustomAttributes(this.ReflectionDomain, scope.Reader, scope.ScopeDefinition.CustomAttributes)) + yield return cad; + + ExecutionDomain executionDomain = this.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(scope.Reader, scope.Handle)) + yield return cad; + } + } + } + } + + public sealed override IEnumerable<TypeInfo> DefinedTypes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Assembly_DefinedTypes(this); + + foreach (QScopeDefinition scope in AllScopes) + { + MetadataReader reader = scope.Reader; + ScopeDefinition scopeDefinition = scope.ScopeDefinition; + IEnumerable<NamespaceDefinitionHandle> topLevelNamespaceHandles = new NamespaceDefinitionHandle[] { scopeDefinition.RootNamespaceDefinition }; + IEnumerable<NamespaceDefinitionHandle> allNamespaceHandles = reader.GetTransitiveNamespaces(topLevelNamespaceHandles); + IEnumerable<TypeDefinitionHandle> allTopLevelTypes = reader.GetTopLevelTypes(allNamespaceHandles); + IEnumerable<TypeDefinitionHandle> allTypes = reader.GetTransitiveTypes(allTopLevelTypes, publicOnly: false); + foreach (TypeDefinitionHandle typeDefinitionHandle in allTypes) + yield return RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(reader, typeDefinitionHandle); + } + } + } + + public sealed override IEnumerable<Type> ExportedTypes + { + get + { + foreach (QScopeDefinition scope in AllScopes) + { + MetadataReader reader = scope.Reader; + ScopeDefinition scopeDefinition = scope.ScopeDefinition; + ReflectionDomain reflectionDomain = this.ReflectionDomain; + IEnumerable<NamespaceDefinitionHandle> topLevelNamespaceHandles = new NamespaceDefinitionHandle[] { scopeDefinition.RootNamespaceDefinition }; + IEnumerable<NamespaceDefinitionHandle> allNamespaceHandles = reader.GetTransitiveNamespaces(topLevelNamespaceHandles); + IEnumerable<TypeDefinitionHandle> allTopLevelTypes = reader.GetTopLevelTypes(allNamespaceHandles); + IEnumerable<TypeDefinitionHandle> allTypes = reader.GetTransitiveTypes(allTopLevelTypes, publicOnly: true); + foreach (TypeDefinitionHandle typeDefinitionHandle in allTypes) + yield return reflectionDomain.ResolveTypeDefinition(reader, typeDefinitionHandle); + } + } + } + + public sealed override String FullName + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Assembly_FullName(this); + + return GetName().FullName; + } + } + + public sealed override Module ManifestModule + { + get + { + return RuntimeModule.GetRuntimeModule(this); + } + } + + public sealed override IEnumerable<Module> Modules + { + get + { + yield return ManifestModule; + } + } + + public sealed override bool Equals(Object obj) + { + RuntimeAssembly other = obj as RuntimeAssembly; + return Equals(other); + } + + public bool Equals(RuntimeAssembly other) + { + if (other == null) + return false; + if (!(this.Scope.Reader == other.Scope.Reader)) + return false; + if (!(this.Scope.Handle.Equals(other.Scope.Handle))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return Scope.Handle.GetHashCode(); + } + + public sealed override ManifestResourceInfo GetManifestResourceInfo(String resourceName) + { + ExecutionDomain executionDomain = this.ReflectionDomain as ExecutionDomain; + if (executionDomain == null) + throw new PlatformNotSupportedException(); + return executionDomain.ExecutionEnvironment.GetManifestResourceInfo(this, resourceName); + } + + public sealed override String[] GetManifestResourceNames() + { + ExecutionDomain executionDomain = this.ReflectionDomain as ExecutionDomain; + if (executionDomain == null) + throw new PlatformNotSupportedException(); + return executionDomain.ExecutionEnvironment.GetManifestResourceNames(this); + } + + public sealed override Stream GetManifestResourceStream(String name) + { + ExecutionDomain executionDomain = this.ReflectionDomain as ExecutionDomain; + if (executionDomain == null) + throw new PlatformNotSupportedException(); + return executionDomain.ExecutionEnvironment.GetManifestResourceStream(this, name); + } + + public sealed override AssemblyName GetName() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Assembly_GetName(this); + + return Scope.Handle.ToRuntimeAssemblyName(Scope.Reader).ToAssemblyName(); + } + + public sealed override Type GetType(String name, bool throwOnError, bool ignoreCase) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Assembly_GetType(this, name); + + if (name == null) + throw new ArgumentNullException(); + if (name.Length == 0) + throw new ArgumentException(); + + AssemblyQualifiedTypeName assemblyQualifiedTypeName; + try + { + assemblyQualifiedTypeName = TypeParser.ParseAssemblyQualifiedTypeName(name); + if (assemblyQualifiedTypeName.AssemblyName != null) + throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly); // Cannot specify an assembly qualifier in a typename passed to Assembly.GetType() + } + catch (ArgumentException) + { + if (throwOnError) + throw; + return null; + } + + RuntimeType result; + Exception typeLoadException = assemblyQualifiedTypeName.TypeName.TryResolve(this.ReflectionDomain, this, ignoreCase, out result); + if (typeLoadException != null) + { + if (throwOnError) + throw typeLoadException; + return null; + } + return result; + } + + internal QScopeDefinition Scope { get; private set; } + + internal IEnumerable<QScopeDefinition> OverflowScopes { get; private set; } + + internal IEnumerable<QScopeDefinition> AllScopes + { + get + { + yield return Scope; + + foreach (QScopeDefinition overflowScope in OverflowScopes) + { + yield return overflowScope; + } + } + } + + internal ReflectionDomain ReflectionDomain + { + get + { + return ReflectionCoreExecution.ExecutionDomain; //@todo: User Reflection Domains not yet supported. + } + } + } +} + + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyName.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyName.cs new file mode 100644 index 000000000..1c9ee2f43 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyName.cs @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Text; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::Internal.Reflection.Augments; + +namespace System.Reflection.Runtime.Assemblies +{ + // + // This is a private assembly name abstraction that's more suitable for use as keys in our caches. + // + // - Immutable, unlike the public AssemblyName + // - Has a useful Equals() override, unlike the public AssemblyName. + // + // We use this as our internal interchange type and only convert to and from the public AssemblyName class at public boundaries. + // + internal sealed class RuntimeAssemblyName : IEquatable<RuntimeAssemblyName> + { + public RuntimeAssemblyName(String name, Version version, String cultureName, AssemblyNameFlags flags, byte[] publicKeyOrToken) + { + Debug.Assert(name != null); + this.Name = name; + + // Optional version. + this.Version = version; + + // Optional culture name. + this.CultureName = cultureName; + + // Optional flags (this is actually an OR of the classic flags and the ContentType.) + this.Flags = flags; + + // Optional public key (if Flags.PublicKey == true) or public key token. + this.PublicKeyOrToken = publicKeyOrToken; + } + + // Simple name. + public String Name { get; private set; } + + // Optional version. + public Version Version { get; private set; } + + // Optional culture name. + public String CultureName { get; private set; } + + // Optional flags (this is actually an OR of the classic flags and the ContentType.) + public AssemblyNameFlags Flags { get; private set; } + + // Optional public key (if Flags.PublicKey == true) or public key token. + public byte[] PublicKeyOrToken { get; private set; } + + // Equality - this compares every bit of data in the RuntimeAssemblyName which is acceptable for use as keys in a cache + // where semantic duplication is permissible. This method is *not* meant to define ref->def binding rules or + // assembly binding unification rules. + public bool Equals(RuntimeAssemblyName other) + { + if (other == null) + return false; + if (!this.Name.Equals(other.Name)) + return false; + if (this.Version == null) + { + if (other.Version != null) + return false; + } + else + { + if (!this.Version.Equals(other.Version)) + return false; + } + if (!String.Equals(this.CultureName, other.CultureName)) + return false; + if (this.Flags != other.Flags) + return false; + + byte[] thisPK = this.PublicKeyOrToken; + byte[] otherPK = other.PublicKeyOrToken; + if (thisPK == null) + { + if (otherPK != null) + return false; + } + else if (otherPK == null) + { + return false; + } + else if (thisPK.Length != otherPK.Length) + { + return false; + } + else + { + for (int i = 0; i < thisPK.Length; i++) + { + if (thisPK[i] != otherPK[i]) + return false; + } + } + + return true; + } + + public sealed override bool Equals(Object obj) + { + RuntimeAssemblyName other = obj as RuntimeAssemblyName; + if (other == null) + return false; + return Equals(other); + } + + public sealed override int GetHashCode() + { + return this.Name.GetHashCode(); + } + + // + // Converts an RuntimeAssemblyName to a freshly allocated AssemblyName with no data aliasing to any other object. + // + public AssemblyName ToAssemblyName() + { + AssemblyName assemblyName = new AssemblyName(); + CopyToAssemblyName(assemblyName); + return assemblyName; + } + + // + // Copies a RuntimeAssemblyName into a freshly allocated AssemblyName with no data aliasing to any other object. + // + public void CopyToAssemblyName(AssemblyName blank) + { + blank.Name = this.Name; + if (this.Version != null) + blank.Version = this.Version; + if (this.CultureName != null) + blank.CultureName = this.CultureName; + + // Our "Flags" contain both the classic flags and the ProcessorArchitecture + ContentType bits. The public AssemblyName has separate properties for + // these. The setters for these properties quietly mask out any bits intended for the other one, so we needn't do that ourselves.. + blank.Flags = AssemblyNameHelpers.ExtractAssemblyNameFlags(this.Flags); + blank.ContentType = AssemblyNameHelpers.ExtractAssemblyContentType(this.Flags); + blank.ProcessorArchitecture = AssemblyNameHelpers.ExtractProcessorArchitecture(this.Flags); + + if (this.PublicKeyOrToken != null) + { + // We must not hand out our own copy of the PKT to AssemblyName as AssemblyName is amazingly trusting and gives untrusted callers + // full freedom to scribble on its PKT array. (As do we but we only have trusted callers!) + byte[] pkCopy = new byte[this.PublicKeyOrToken.Length]; + ((ICollection<byte>)(this.PublicKeyOrToken)).CopyTo(pkCopy, 0); + + if (0 != (this.Flags & AssemblyNameFlags.PublicKey)) + blank.SetPublicKey(pkCopy); + else + blank.SetPublicKeyToken(pkCopy); + } + + return; + } + + public String FullName + { + get + { + return AssemblyNameHelpers.ComputeDisplayName(this); + } + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs new file mode 100644 index 000000000..5e25a560d --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeCustomAttributeData.cs @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Collections.ObjectModel; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; +using global::Internal.Reflection.Tracing; +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.CustomAttributes +{ + // + // Common base class for the Runtime's implementation of CustomAttributeData. + // + internal abstract partial class RuntimeCustomAttributeData : ExtensibleCustomAttributeData + { + public abstract override Type AttributeType + { + get; + } + + public sealed override IList<CustomAttributeTypedArgument> ConstructorArguments + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.CustomAttributeData_ConstructorArguments(this); + + return new ReadOnlyCollection<CustomAttributeTypedArgument>(GetConstructorArguments(throwIfMissingMetadata: true)); + } + } + + // Equals/GetHashCode no need to override (they just implement reference equality but desktop never unified these things.) + + public sealed override IList<CustomAttributeNamedArgument> NamedArguments + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.CustomAttributeData_NamedArguments(this); + + return new ReadOnlyCollection<CustomAttributeNamedArgument>(GetNamedArguments(throwIfMissingMetadata: true)); + } + } + + public sealed override String ToString() + { + try + { + String ctorArgs = ""; + IList<CustomAttributeTypedArgument> constructorArguments = GetConstructorArguments(throwIfMissingMetadata: false); + if (constructorArguments == null) + return base.ToString(); + for (int i = 0; i < constructorArguments.Count; i++) + ctorArgs += String.Format(i == 0 ? "{0}" : ", {0}", ComputeTypedArgumentString(constructorArguments[i], typed: false)); + + String namedArgs = ""; + IList<CustomAttributeNamedArgument> namedArguments = GetNamedArguments(throwIfMissingMetadata: false); + if (namedArguments == null) + return base.ToString(); + for (int i = 0; i < namedArguments.Count; i++) + { + CustomAttributeNamedArgument namedArgument = namedArguments[i]; + + // Legacy: Desktop sets "typed" to "namedArgument.ArgumentType != typeof(Object)" - on Project N, this property is not available + // (nor conveniently computable as it's not captured in the Project N metadata.) The only consequence is that for + // the rare case of fields and properties typed "Object", we won't decorate the argument value with its actual type name. + bool typed = true; + namedArgs += String.Format( + i == 0 && ctorArgs.Length == 0 ? "{0} = {1}" : ", {0} = {1}", + namedArgument.MemberName, + ComputeTypedArgumentString(namedArgument.TypedValue, typed)); + } + + return String.Format("[{0}({1}{2})]", AttributeTypeString, ctorArgs, namedArgs); + } + catch (MissingMetadataException) + { + return base.ToString(); + } + } + + internal abstract String AttributeTypeString { get; } + + // + // If throwIfMissingMetadata is false, returns null rather than throwing a MissingMetadataException. + // + internal abstract IList<CustomAttributeTypedArgument> GetConstructorArguments(bool throwIfMissingMetadata); + + // + // If throwIfMissingMetadata is false, returns null rather than throwing a MissingMetadataException. + // + internal abstract IList<CustomAttributeNamedArgument> GetNamedArguments(bool throwIfMissingMetadata); + + // + // Computes the ToString() value for a CustomAttributeTypedArgument struct. + // + private static String ComputeTypedArgumentString(CustomAttributeTypedArgument cat, bool typed) + { + Type argumentType = cat.ArgumentType; + if (argumentType == null) + return cat.ToString(); + + FoundationTypes foundationTypes = argumentType.AsConfirmedRuntimeType().GetReflectionDomain().FoundationTypes; + Object value = cat.Value; + TypeInfo argumentTypeInfo = argumentType.GetTypeInfo(); + if (argumentTypeInfo.IsEnum) + return String.Format(typed ? "{0}" : "({1}){0}", value, argumentType.FullName); + + if (value == null) + return String.Format(typed ? "null" : "({0})null", argumentType.Name); + + if (argumentType.Equals(foundationTypes.SystemString)) + return String.Format("\"{0}\"", value); + + if (argumentType.Equals(foundationTypes.SystemChar)) + return String.Format("'{0}'", value); + + if (argumentType.Equals(foundationTypes.SystemType)) + return String.Format("typeof({0})", ((Type)value).FullName); + + else if (argumentType.IsArray) + { + String result = null; + IList<CustomAttributeTypedArgument> array = value as IList<CustomAttributeTypedArgument>; + + Type elementType = argumentType.GetElementType(); + result = String.Format(@"new {0}[{1}] {{ ", elementType.GetTypeInfo().IsEnum ? elementType.FullName : elementType.Name, array.Count); + + for (int i = 0; i < array.Count; i++) + result += String.Format(i == 0 ? "{0}" : ", {0}", ComputeTypedArgumentString(array[i], elementType != foundationTypes.SystemObject)); + + return result += " }"; + } + + return String.Format(typed ? "{0}" : "({1}){0}", value, argumentType.Name); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeNormalCustomAttributeData.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeNormalCustomAttributeData.cs new file mode 100644 index 000000000..dc6cc0456 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimeNormalCustomAttributeData.cs @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections; +using global::System.Collections.Generic; +using global::System.Collections.ObjectModel; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.CustomAttributes +{ + // + // The Runtime's implementation of CustomAttributeData for normal metadata-based attributes + // + internal sealed class RuntimeNormalCustomAttributeData : RuntimeCustomAttributeData + { + internal RuntimeNormalCustomAttributeData(ReflectionDomain reflectionDomain, MetadataReader reader, CustomAttributeHandle customAttributeHandle) + { + _reflectionDomain = reflectionDomain; + _reader = reader; + _customAttribute = customAttributeHandle.GetCustomAttribute(reader); + } + + public sealed override Type AttributeType + { + get + { + Type lazyAttributeType = _lazyAttributeType; + if (lazyAttributeType == null) + { + lazyAttributeType = _lazyAttributeType = _reflectionDomain.Resolve(_reader, _customAttribute.Type, new TypeContext(null, null)); + } + return lazyAttributeType; + } + } + + internal sealed override String AttributeTypeString + { + get + { + return _customAttribute.Type.FormatTypeName(_reader, new TypeContext(null, null), _reflectionDomain); + } + } + + // + // If throwIfMissingMetadata is false, returns null rather than throwing a MissingMetadataException. + // + internal sealed override IList<CustomAttributeTypedArgument> GetConstructorArguments(bool throwIfMissingMetadata) + { + int index = 0; + LowLevelList<Handle> lazyCtorTypeHandles = null; + LowLevelListWithIList<CustomAttributeTypedArgument> customAttributeTypedArguments = new LowLevelListWithIList<CustomAttributeTypedArgument>(); + + foreach (FixedArgumentHandle fixedArgumentHandle in _customAttribute.FixedArguments) + { + CustomAttributeTypedArgument customAttributeTypedArgument = + ParseFixedArgument( + _reader, + fixedArgumentHandle, + throwIfMissingMetadata, + delegate () + { + // If we got here, the custom attribute blob lacked type information (this is actually the typical case.) We must fallback to + // parsing the constructor's signature to get the type info. + if (lazyCtorTypeHandles == null) + { + IEnumerable<ParameterTypeSignatureHandle> parameterTypeSignatureHandles; + HandleType handleType = _customAttribute.Constructor.HandleType; + switch (handleType) + { + case HandleType.Method: + parameterTypeSignatureHandles = _customAttribute.Constructor.ToMethodHandle(_reader).GetMethod(_reader).Signature.GetMethodSignature(_reader).Parameters; + break; + + case HandleType.MemberReference: + parameterTypeSignatureHandles = _customAttribute.Constructor.ToMemberReferenceHandle(_reader).GetMemberReference(_reader).Signature.ToMethodSignatureHandle(_reader).GetMethodSignature(_reader).Parameters; + break; + default: + throw new BadImageFormatException(); + } + LowLevelList<Handle> ctorTypeHandles = new LowLevelList<Handle>(); + foreach (ParameterTypeSignatureHandle parameterTypeSignatureHandle in parameterTypeSignatureHandles) + { + ctorTypeHandles.Add(parameterTypeSignatureHandle.GetParameterTypeSignature(_reader).Type); + } + lazyCtorTypeHandles = ctorTypeHandles; + } + Handle typeHandle = lazyCtorTypeHandles[index]; + Exception exception = null; + RuntimeType argumentType = _reflectionDomain.TryResolve(_reader, typeHandle, new TypeContext(null, null), ref exception); + if (argumentType == null) + { + if (throwIfMissingMetadata) + throw exception; + return null; + } + return argumentType; + } + ); + + if (customAttributeTypedArgument.ArgumentType == null) + { + Debug.Assert(!throwIfMissingMetadata); + return null; + } + + customAttributeTypedArguments.Add(customAttributeTypedArgument); + index++; + } + + return customAttributeTypedArguments; + } + + // + // If throwIfMissingMetadata is false, returns null rather than throwing a MissingMetadataException. + // + internal sealed override IList<CustomAttributeNamedArgument> GetNamedArguments(bool throwIfMissingMetadata) + { + LowLevelListWithIList<CustomAttributeNamedArgument> customAttributeNamedArguments = new LowLevelListWithIList<CustomAttributeNamedArgument>(); + foreach (NamedArgumentHandle namedArgumentHandle in _customAttribute.NamedArguments) + { + NamedArgument namedArgument = namedArgumentHandle.GetNamedArgument(_reader); + String memberName = namedArgument.Name.GetString(_reader); + bool isField = (namedArgument.Flags == NamedArgumentMemberKind.Field); + CustomAttributeTypedArgument typedValue = + ParseFixedArgument( + _reader, + namedArgument.Value, + throwIfMissingMetadata, + delegate () + { + // We got here because the custom attribute blob did not inclue type information. For named arguments, this is considered illegal metadata + // (ECMA always includes type info for named arguments.) + throw new BadImageFormatException(); + } + ); + if (typedValue.ArgumentType == null) + { + Debug.Assert(!throwIfMissingMetadata); + return null; + } + customAttributeNamedArguments.Add(ExtensibleCustomAttributeData.CreateCustomAttributeNamedArgument(this.AttributeType, memberName, isField, typedValue)); + } + return customAttributeNamedArguments; + } + + // Equals/GetHashCode no need to override (they just implement reference equality but desktop never unified these things.) + + // + // Helper for parsing custom attribute arguments. + // + // If throwIfMissingMetadata is false, returns default(CustomAttributeTypedArgument) rather than throwing a MissingMetadataException. + // + private CustomAttributeTypedArgument ParseFixedArgument(MetadataReader reader, FixedArgumentHandle fixedArgumentHandle, bool throwIfMissingMetadata, Func<RuntimeType> getTypeFromConstructor) + { + FixedArgument fixedArgument = fixedArgumentHandle.GetFixedArgument(reader); + RuntimeType argumentType = null; + if (fixedArgument.Type.IsNull(reader)) + { + argumentType = getTypeFromConstructor(); + if (argumentType == null) + { + Debug.Assert(!throwIfMissingMetadata); + return default(CustomAttributeTypedArgument); + } + } + else + { + Exception exception = null; + argumentType = _reflectionDomain.TryResolve(reader, fixedArgument.Type, new TypeContext(null, null), ref exception); + if (argumentType == null) + { + if (throwIfMissingMetadata) + throw exception; + else + return default(CustomAttributeTypedArgument); + } + } + + Object value; + Exception e = fixedArgument.Value.TryParseConstantValue(_reflectionDomain, reader, out value); + if (e != null) + { + if (throwIfMissingMetadata) + throw e; + else + return default(CustomAttributeTypedArgument); + } + return WrapInCustomAttributeTypedArgument(value, argumentType); + } + + // + // Wrap a custom attribute argument (or an element of an array-typed custom attribute argument) in a CustomAttributeTypeArgument structure + // for insertion into a CustomAttributeData value. + // + private CustomAttributeTypedArgument WrapInCustomAttributeTypedArgument(Object value, Type argumentType) + { + // To support reflection domains other than the execution domain, we'll have to translate argumentType to one of the values off + // _reflectionDomain.FoundationTypes rather than using the direct value of value.GetType(). It's unclear how to do this for + // enum types. Cross that bridge if ever get to it. + Debug.Assert(_reflectionDomain is ExecutionDomain); + + if (argumentType.Equals(typeof(Object))) + { + // If the declared attribute type is System.Object, we must report the type based on the runtime value. + if (value == null) + argumentType = typeof(String); // Why is null reported as System.String? Because that's what the desktop CLR does. + else if (value is Type) + argumentType = typeof(Type); // value.GetType() will not actually be System.Type - rather it will be some internal implementation type. We only want to report it as System.Type. + else + argumentType = value.GetType(); + } + + Array arrayValue = value as Array; + if (arrayValue != null) + { + if (!argumentType.IsArray) + throw new BadImageFormatException(); + Type reportedElementType = argumentType.GetElementType(); + LowLevelListWithIList<CustomAttributeTypedArgument> elementTypedArguments = new LowLevelListWithIList<CustomAttributeTypedArgument>(); + foreach (Object elementValue in arrayValue) + { + CustomAttributeTypedArgument elementTypedArgument = WrapInCustomAttributeTypedArgument(elementValue, reportedElementType); + elementTypedArguments.Add(elementTypedArgument); + } + return ExtensibleCustomAttributeData.CreateCustomAttributeTypedArgument(argumentType, new ReadOnlyCollection<CustomAttributeTypedArgument>(elementTypedArguments)); + } + else + { + return ExtensibleCustomAttributeData.CreateCustomAttributeTypedArgument(argumentType, value); + } + } + + private ReflectionDomain _reflectionDomain; + private MetadataReader _reader; + private CustomAttribute _customAttribute; + + private volatile Type _lazyAttributeType; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs new file mode 100644 index 000000000..60894f270 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/CustomAttributes/RuntimePseudoCustomAttributeData.cs @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Collections.ObjectModel; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.CustomAttributes +{ + // + // The Runtime's implementation of a pseudo-CustomAttributeData. + // + internal sealed class RuntimePseudoCustomAttributeData : RuntimeCustomAttributeData + { + public RuntimePseudoCustomAttributeData(RuntimeType attributeType, IList<CustomAttributeTypedArgument> constructorArguments, IList<CustomAttributeNamedArgument> namedArguments) + { + _attributeType = attributeType; + if (constructorArguments == null) + constructorArguments = Array.Empty<CustomAttributeTypedArgument>(); + _constructorArguments = new ReadOnlyCollection<CustomAttributeTypedArgument>(constructorArguments); + if (namedArguments == null) + namedArguments = Array.Empty<CustomAttributeNamedArgument>(); + _namedArguments = new ReadOnlyCollection<CustomAttributeNamedArgument>(namedArguments); + return; + } + + public sealed override Type AttributeType + { + get + { + return _attributeType; + } + } + + internal sealed override String AttributeTypeString + { + get + { + return _attributeType.FormatTypeName(); + } + } + + internal sealed override IList<CustomAttributeTypedArgument> GetConstructorArguments(bool throwIfMissingMetadata) + { + return _constructorArguments; + } + + internal sealed override IList<CustomAttributeNamedArgument> GetNamedArguments(bool throwIfMissingMetadata) + { + return _namedArguments; + } + + // Equals/GetHashCode no need to override (they just implement reference equality but desktop never unified these things.) + + private RuntimeType _attributeType; + private ReadOnlyCollection<CustomAttributeTypedArgument> _constructorArguments; + private ReadOnlyCollection<CustomAttributeNamedArgument> _namedArguments; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs new file mode 100644 index 000000000..d542ec8e4 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DefaultDispenserPolicy.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // For now, this is the dispenser policy used inside S.R.R. + // + internal sealed class DefaultDispenserPolicy : DispenserPolicy + { + public sealed override DispenserAlgorithm GetAlgorithm(DispenserScenario scenario) + { +#if TEST_CODEGEN_OPTIMIZATION + return DispenserAlgorithm.CreateAlways; +#else + switch (scenario) + { + // Type.GetTypeInfo() for Runtime types. + case DispenserScenario.Type_TypeInfo: + return DispenserAlgorithm.LatchesTypeInfoInsideType; + + // Metadata typedef handle to RuntimeTypeInfo + case DispenserScenario.TypeDef_TypeInfo: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // TypeInfo + Name to EventInfo + case DispenserScenario.TypeInfoAndName_EventInfo: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // TypeInfo + Name to FieldInfo + case DispenserScenario.TypeInfoAndName_FieldInfo: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // TypeInfo + Name to MethodInfo + case DispenserScenario.TypeInfoAndName_MethodInfo: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // TypeInfo + Name to PropertyInfo + case DispenserScenario.TypeInfoAndName_PropertyInfo: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // Assembly + NamespaceTypeName to Type + case DispenserScenario.AssemblyAndNamespaceTypeName_Type: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // Assembly refName to Assembly + case DispenserScenario.AssemblyRefName_Assembly: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + // RuntimeAssembly to CaseInsensitiveTypeDictionary + case DispenserScenario.RuntimeAssembly_CaseInsensitiveTypeDictionary: + return DispenserAlgorithm.ReuseAlways; + + // Scope definition handle to RuntimeAssembly + case DispenserScenario.Scope_Assembly: + return DispenserAlgorithm.ReuseAsLongAsValueIsAlive; + + default: + return DispenserAlgorithm.CreateAlways; + } +#endif //!TEST_CODEGEN_OPTIMIZATION + + } + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/Dispenser.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/Dispenser.cs new file mode 100644 index 000000000..f8806d37d --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/Dispenser.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // Abstract base for reflection caches. + // + internal abstract class Dispenser<K, V> + where K : IEquatable<K> + where V : class + { + public abstract V GetOrAdd(K key); + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs new file mode 100644 index 000000000..ac59b2d43 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserAlgorithm.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // A parameterizable monikor for the various cache algorithms available. + // + internal sealed class DispenserAlgorithm + { + public static readonly DispenserAlgorithm CreateAlways = new DispenserAlgorithm(); // Always create a new object (i.e. no caching at all.) + public static readonly DispenserAlgorithm ReuseAlways = new DispenserAlgorithm(); // Every object is saved permanently (i.e. complete unification.) + public static readonly DispenserAlgorithm ReuseAsLongAsValueIsAlive = new DispenserAlgorithm(); // Every object is saved using weak references. + + // + // Associates the value with key using a hash table but does not prevent key from gc'd. + // Restriction: The algorithm uses ConditionalWeakTable so it is subject to the following limitations: + // The key cannot be a value type. + // Keys are compared using Object.ReferenceEquals. + // + public static readonly DispenserAlgorithm ReuseAsLongAsKeyIsAlive = new DispenserAlgorithm(); + + + // ONLY usable for Dispenser<RuntimeType,RuntimeTypeInfo> - RuntimeType object stores its RuntimeTypeInfo. + public static readonly DispenserAlgorithm LatchesTypeInfoInsideType = new DispenserAlgorithm(); + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs new file mode 100644 index 000000000..0ac772c48 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserFactory.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Reflection.Runtime.TypeInfos; + +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // Creates the appropriate Dispenser for a scenario, based on the dispenser policy. + // + internal static class DispenserFactory + { + // + // Note: If your K is a valuetype, use CreateDispenserV() instead. Some algorithms will not be available for use. + // + public static Dispenser<K, V> CreateDispenser<K, V>(DispenserScenario scenario, Func<K, V> factory) + where K : class, IEquatable<K> + where V : class + { + DispenserAlgorithm algorithm = _dispenserPolicy.GetAlgorithm(scenario); + if (algorithm == DispenserAlgorithm.ReuseAsLongAsKeyIsAlive) + return new DispenserThatReusesAsLongAsKeyIsAlive<K, V>(factory); + else + return CreateDispenserV<K, V>(scenario, factory); + + throw new Exception(); + } + + + // + // This is similar to CreateDispenser() except it doesn't constrain the key to be a reference type. + // As a result, some algorithms will not be available for use. + // + public static Dispenser<K, V> CreateDispenserV<K, V>(DispenserScenario scenario, Func<K, V> factory) + where K : IEquatable<K> + where V : class + { + DispenserAlgorithm algorithm = _dispenserPolicy.GetAlgorithm(scenario); + + Debug.Assert(algorithm != DispenserAlgorithm.ReuseAsLongAsKeyIsAlive, + "Use CreateDispenser() if you want to use this algorithm. The key must not be a valuetype."); + + if (algorithm == DispenserAlgorithm.CreateAlways) + return new DispenserThatAlwaysCreates<K, V>(factory); + else if (algorithm == DispenserAlgorithm.ReuseAlways) + return new DispenserThatAlwaysReuses<K, V>(factory); + else if (algorithm == DispenserAlgorithm.ReuseAsLongAsValueIsAlive) + return new DispenserThatReusesAsLongAsValueIsAlive<K, V>(factory); + else if (algorithm == DispenserAlgorithm.LatchesTypeInfoInsideType) + return (Dispenser<K, V>)(Object)(new DispenserThatLatchesTypeInfosInsideTypes((Func<RuntimeType, RuntimeTypeInfo>)(Object)factory)); + + throw new Exception(); + } + + + private static DispenserPolicy _dispenserPolicy = new DefaultDispenserPolicy(); + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs new file mode 100644 index 000000000..527dba170 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserPolicy.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // Base class for a policy that maps dispense scenarios to the caching algorithm used. + // + internal abstract class DispenserPolicy + { + public abstract DispenserAlgorithm GetAlgorithm(DispenserScenario scenario); + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs new file mode 100644 index 000000000..7578bee4b --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserScenario.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // A monikor for each reflection cache. The name should follow the style "key" followed by underscore followed by "value". + // + internal enum DispenserScenario + { + // Type.GetTypeInfo() for Runtime types. + Type_TypeInfo, + + // Metadata typedef handle to RuntimeTypeInfo + TypeDef_TypeInfo, + + // TypeInfo + Name to EventInfo + TypeInfoAndName_EventInfo, + + // TypeInfo + Name to FieldInfo + TypeInfoAndName_FieldInfo, + + // TypeInfo + Name to MethodInfo + TypeInfoAndName_MethodInfo, + + // TypeInfo + Name to PropertyInfo + TypeInfoAndName_PropertyInfo, + + // Assembly + NamespaceTypeName to Type + AssemblyAndNamespaceTypeName_Type, + + // Assembly refName to Assembly + AssemblyRefName_Assembly, + + // RuntimeAssembly to CaseInsensitiveTypeDictionary + RuntimeAssembly_CaseInsensitiveTypeDictionary, + + // Scope definition handle to RuntimeAssembly + Scope_Assembly, + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs new file mode 100644 index 000000000..36381209a --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysCreates.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // This dispenser always creates things anew. + // + internal sealed class DispenserThatAlwaysCreates<K, V> : Dispenser<K, V> + where K : IEquatable<K> + where V : class + { + public DispenserThatAlwaysCreates(Func<K, V> factory) + { + _factory = factory; + } + + public sealed override V GetOrAdd(K key) + { + return _factory(key); + } + + private Func<K, V> _factory; + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs new file mode 100644 index 000000000..08425b433 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatAlwaysReuses.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Collections.Concurrent; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // This dispenser stores every instance permanently. + // + internal sealed class DispenserThatAlwaysReuses<K, V> : Dispenser<K, V> + where K : IEquatable<K> + where V : class + { + public DispenserThatAlwaysReuses(Func<K, V> factory) + { + _concurrentUnifier = new FactoryConcurrentUnifier(factory); + } + + public sealed override V GetOrAdd(K key) + { + return _concurrentUnifier.GetOrAdd(key); + } + + private sealed class FactoryConcurrentUnifier : ConcurrentUnifier<K, V> + { + public FactoryConcurrentUnifier(Func<K, V> factory) + { + _factory = factory; + } + + protected sealed override V Factory(K key) + { + return _factory(key); + } + + private Func<K, V> _factory; + } + + private FactoryConcurrentUnifier _concurrentUnifier; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatLatchesTypeInfosInsideTypes.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatLatchesTypeInfosInsideTypes.cs new file mode 100644 index 000000000..d5ec45aef --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatLatchesTypeInfosInsideTypes.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Reflection.Runtime.TypeInfos; + +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // This dispenser uses RuntimeType to store a reference to its RuntimeTypeInfo. + // + internal sealed class DispenserThatLatchesTypeInfosInsideTypes : Dispenser<RuntimeType, RuntimeTypeInfo> + { + public DispenserThatLatchesTypeInfosInsideTypes(Func<RuntimeType, RuntimeTypeInfo> factory) + { + _factory = factory; + } + + public sealed override RuntimeTypeInfo GetOrAdd(RuntimeType key) + { + return key.InternalGetLatchedRuntimeTypeInfo<RuntimeTypeInfo>(_factory); + } + + private Func<RuntimeType, RuntimeTypeInfo> _factory; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs new file mode 100644 index 000000000..7b26af79b --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyIsAlive.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Runtime.CompilerServices; + +namespace System.Reflection.Runtime.Dispensers +{ + internal sealed class DispenserThatReusesAsLongAsKeyIsAlive<K, V> : Dispenser<K, V> + where K : class, IEquatable<K> + where V : class + { + public DispenserThatReusesAsLongAsKeyIsAlive(Func<K, V> factory) + { + _createValueCallback = CreateValue; + _conditionalWeakTable = new ConditionalWeakTable<K, V>(); + _factory = factory; + } + + public sealed override V GetOrAdd(K key) + { + return _conditionalWeakTable.GetValue(key, _createValueCallback); + } + + private V CreateValue(K key) + { + return _factory(key); + } + + private Func<K, V> _factory; + private ConditionalWeakTable<K, V> _conditionalWeakTable; + private ConditionalWeakTable<K, V>.CreateValueCallback _createValueCallback; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs new file mode 100644 index 000000000..27f703ebf --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsKeyedValueIsAlive.cs @@ -0,0 +1,3 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs new file mode 100644 index 000000000..406ca294b --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Dispensers/DispenserThatReusesAsLongAsValueIsAlive.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Collections.Concurrent; + +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.Dispensers +{ + // + // This dispenser stores every instance using weak references. + // + internal sealed class DispenserThatReusesAsLongAsValueIsAlive<K, V> : Dispenser<K, V> + where K : IEquatable<K> + where V : class + { + public DispenserThatReusesAsLongAsValueIsAlive(Func<K, V> factory) + { + _concurrentUnifier = new FactoryConcurrentUnifierW(factory); + } + + public sealed override V GetOrAdd(K key) + { + return _concurrentUnifier.GetOrAdd(key); + } + + private sealed class FactoryConcurrentUnifierW : ConcurrentUnifierW<K, V> + { + public FactoryConcurrentUnifierW(Func<K, V> factory) + { + _factory = factory; + } + + protected sealed override V Factory(K key) + { + return _factory(key); + } + + private Func<K, V> _factory; + } + + private FactoryConcurrentUnifierW _concurrentUnifier; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs new file mode 100644 index 000000000..bd2faae86 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.ParameterInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Extensibility; +using global::Internal.Reflection.Tracing; + +namespace System.Reflection.Runtime.EventInfos +{ + // + // The runtime's implementation of EventInfo's + // + internal sealed partial class RuntimeEventInfo : ExtensibleEventInfo, ITraceableTypeMember + { + // + // eventHandle - the "tkEventDef" that identifies the event. + // definingType - the "tkTypeDef" that defined the field (this is where you get the metadata reader that created eventHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + private RuntimeEventInfo(EventHandle eventHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + _eventHandle = eventHandle; + _definingTypeInfo = definingTypeInfo; + _contextTypeInfo = contextTypeInfo; + _reader = definingTypeInfo.Reader; + _event = eventHandle.GetEvent(_reader); + } + + public sealed override void AddEventHandler(Object target, Delegate handler) + { + MethodInfo addMethod = this.AddMethod; + if (!addMethod.IsPublic) + throw new InvalidOperationException(SR.InvalidOperation_NoPublicAddMethod); + addMethod.Invoke(target, new Object[] { handler }); + } + + public sealed override MethodInfo AddMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_AddMethod(this); + + foreach (MethodSemanticsHandle methodSemanticsHandle in _event.MethodSemantics) + { + MethodSemantics methodSemantics = methodSemanticsHandle.GetMethodSemantics(_reader); + if (methodSemantics.Attributes == MethodSemanticsAttributes.AddOn) + { + return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(methodSemantics.Method, _definingTypeInfo, _contextTypeInfo); + } + } + throw new BadImageFormatException(); // Added is a required method. + } + } + + public sealed override EventAttributes Attributes + { + get + { + return _event.Flags; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_CustomAttributes(this); + + foreach (CustomAttributeData cad in RuntimeCustomAttributeData.GetCustomAttributes(_definingTypeInfo.ReflectionDomain, _reader, _event.CustomAttributes)) + yield return cad; + ExecutionDomain executionDomain = _definingTypeInfo.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(_reader, _eventHandle, _definingTypeInfo.TypeDefinitionHandle)) + yield return cad; + } + } + } + + public sealed override Type DeclaringType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_DeclaringType(this); + + return _contextTypeInfo.AsType(); + } + } + + public sealed override bool Equals(Object obj) + { + RuntimeEventInfo other = obj as RuntimeEventInfo; + if (other == null) + return false; + if (!(this._reader == other._reader)) + return false; + if (!(this._eventHandle.Equals(other._eventHandle))) + return false; + if (!(this._contextTypeInfo.Equals(other._contextTypeInfo))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _eventHandle.GetHashCode(); + } + + public sealed override Type EventHandlerType + { + get + { + return _definingTypeInfo.ReflectionDomain.Resolve(_reader, _event.Type, _contextTypeInfo.TypeContext); + } + } + + public sealed override Module Module + { + get + { + return _definingTypeInfo.Module; + } + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_Name(this); + + return _event.Name.GetString(_reader); + } + } + + public sealed override MethodInfo RaiseMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_RaiseMethod(this); + + foreach (MethodSemanticsHandle methodSemanticsHandle in _event.MethodSemantics) + { + MethodSemantics methodSemantics = methodSemanticsHandle.GetMethodSemantics(_reader); + if (methodSemantics.Attributes == MethodSemanticsAttributes.Fire) + { + return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(methodSemantics.Method, _definingTypeInfo, _contextTypeInfo); + } + } + return null; + } + } + + public sealed override void RemoveEventHandler(Object target, Delegate handler) + { + MethodInfo removeMethod = this.RemoveMethod; + if (!removeMethod.IsPublic) + throw new InvalidOperationException(SR.InvalidOperation_NoPublicRemoveMethod); + removeMethod.Invoke(target, new Object[] { handler }); + } + + public sealed override MethodInfo RemoveMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.EventInfo_RemoveMethod(this); + + foreach (MethodSemanticsHandle methodSemanticsHandle in _event.MethodSemantics) + { + MethodSemantics methodSemantics = methodSemanticsHandle.GetMethodSemantics(_reader); + if (methodSemantics.Attributes == MethodSemanticsAttributes.RemoveOn) + { + return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(methodSemantics.Method, _definingTypeInfo, _contextTypeInfo); + } + } + throw new BadImageFormatException(); // Removed is a required method. + } + } + + public sealed override String ToString() + { + MethodInfo addMethod = this.AddMethod; + ParameterInfo[] parameters = addMethod.GetParameters(); + if (parameters.Length == 0) + throw new InvalidOperationException(); // Legacy: Why is a ToString() intentionally throwing an exception? + RuntimeParameterInfo runtimeParameterInfo = (RuntimeParameterInfo)(parameters[0]); + return runtimeParameterInfo.ParameterTypeString + " " + this.Name; + } + + String ITraceableTypeMember.MemberName + { + get + { + return _event.Name.GetString(_reader); + } + } + + Type ITraceableTypeMember.ContainingType + { + get + { + return _contextTypeInfo.AsType(); + } + } + + private RuntimeEventInfo WithDebugName() + { +#if DEBUG + if (_debugName == null) + { + _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. + _debugName = ((ITraceableTypeMember)this).MemberName; + } +#endif + return this; + } + + private RuntimeNamedTypeInfo _definingTypeInfo; + private EventHandle _eventHandle; + private RuntimeTypeInfo _contextTypeInfo; + + private MetadataReader _reader; + private Event _event; + +#if DEBUG + private String _debugName; +#endif + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/LiteralFieldAccessor.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/LiteralFieldAccessor.cs new file mode 100644 index 000000000..bd1bb23e0 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/LiteralFieldAccessor.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +using FieldAccessException = global::System.MemberAccessException; + +namespace System.Reflection.Runtime.FieldInfos +{ + internal sealed class LiteralFieldAccessor : FieldAccessor + { + public LiteralFieldAccessor(Object value) + { + _value = value; + } + + public sealed override Object GetField(Object obj) + { + return _value; + } + + public sealed override void SetField(Object obj, Object value) + { + throw new FieldAccessException(SR.Acc_ReadOnly); + } + + private Object _value; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs new file mode 100644 index 000000000..545d3cc03 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; + +using global::Internal.Reflection.Tracing; + +namespace System.Reflection.Runtime.FieldInfos +{ + // + // The Runtime's implementation of fields. + // + internal sealed partial class RuntimeFieldInfo : ExtensibleFieldInfo, ITraceableTypeMember + { + // + // fieldHandle - the "tkFieldDef" that identifies the field. + // definingType - the "tkTypeDef" that defined the field (this is where you get the metadata reader that created fieldHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + private RuntimeFieldInfo(FieldHandle fieldHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + _fieldHandle = fieldHandle; + _definingTypeInfo = definingTypeInfo; + _contextTypeInfo = contextTypeInfo; + _reader = definingTypeInfo.Reader; + _field = fieldHandle.GetField(_reader); + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.FieldInfo_CustomAttributes(this); + + ReflectionDomain reflectionDomain = _definingTypeInfo.ReflectionDomain; + IEnumerable<CustomAttributeData> customAttributes = RuntimeCustomAttributeData.GetCustomAttributes(reflectionDomain, _reader, _field.CustomAttributes); + foreach (CustomAttributeData cad in customAttributes) + yield return cad; + ExecutionDomain executionDomain = _definingTypeInfo.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(_reader, _fieldHandle, _definingTypeInfo.TypeDefinitionHandle)) + yield return cad; + } + } + } + + public sealed override FieldAttributes Attributes + { + get + { + return _field.Flags; + } + } + + public sealed override Type DeclaringType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.FieldInfo_DeclaringType(this); + + return _contextTypeInfo.AsType(); + } + } + + public sealed override Type FieldType + { + get + { + return this.FieldRuntimeType; + } + } + + public sealed override Object GetValue(Object obj) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.FieldInfo_GetValue(this, obj); + + FieldAccessor fieldAccessor = this.FieldAccessor; + return fieldAccessor.GetField(obj); + } + + public sealed override Module Module + { + get + { + return _definingTypeInfo.Module; + } + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.FieldInfo_Name(this); + + return _field.Name.GetString(_reader); + } + } + + public sealed override void SetValue(Object obj, Object value) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.FieldInfo_SetValue(this, obj, value); + + FieldAccessor fieldAccessor = this.FieldAccessor; + fieldAccessor.SetField(obj, value); + } + + public sealed override String ToString() + { + TypeContext typeContext = _contextTypeInfo.TypeContext; + Handle typeHandle = _field.Signature.GetFieldSignature(_reader).Type; + return typeHandle.FormatTypeName(_reader, typeContext, _definingTypeInfo.ReflectionDomain) + " " + this.Name; + } + + public sealed override bool Equals(Object obj) + { + RuntimeFieldInfo other = obj as RuntimeFieldInfo; + if (other == null) + return false; + if (!(this._reader == other._reader)) + return false; + if (!(this._fieldHandle.Equals(other._fieldHandle))) + return false; + if (!(this._contextTypeInfo.Equals(other._contextTypeInfo))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _fieldHandle.GetHashCode(); + } + + String ITraceableTypeMember.MemberName + { + get + { + return _field.Name.GetString(_reader); + } + } + + Type ITraceableTypeMember.ContainingType + { + get + { + return _contextTypeInfo.AsType(); + } + } + + private FieldAccessor FieldAccessor + { + get + { + FieldAccessor fieldAccessor = _lazyFieldAccessor; + if (fieldAccessor == null) + { + if (this.IsLiteral) + { + if (!(_definingTypeInfo.ReflectionDomain is ExecutionDomain)) + throw new NotSupportedException(); // Cannot instantiate a boxed enum on a non-execution domain. + // Legacy: ECMA335 does not require that the metadata literal match the type of the field that declares it. + // For desktop compat, we return the metadata literal as is and do not attempt to convert or validate against the Field type. + + Object defaultValue; + if (!ReflectionCoreExecution.ExecutionEnvironment.GetDefaultValueIfAny( + _reader, + _fieldHandle, + this.FieldType, + this.CustomAttributes, + out defaultValue)) + { + throw new BadImageFormatException(); // Field marked literal but has no default value. + } + + _lazyFieldAccessor = fieldAccessor = new LiteralFieldAccessor(defaultValue); + } + else + { + _lazyFieldAccessor = fieldAccessor = ReflectionCoreExecution.ExecutionEnvironment.TryGetFieldAccessor(this.DeclaringType.TypeHandle, this.FieldType.TypeHandle, _fieldHandle); + if (fieldAccessor == null) + throw this._definingTypeInfo.ReflectionDomain.CreateNonInvokabilityException(this); + } + } + return fieldAccessor; + } + } + + private RuntimeType FieldRuntimeType + { + get + { + TypeContext typeContext = _contextTypeInfo.TypeContext; + Handle typeHandle = _field.Signature.GetFieldSignature(_reader).Type; + return _definingTypeInfo.ReflectionDomain.Resolve(_reader, typeHandle, typeContext); + } + } + + private RuntimeFieldInfo WithDebugName() + { +#if DEBUG + if (_debugName == null) + { + _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. + _debugName = ((ITraceableTypeMember)this).MemberName; + } +#endif + return this; + } + + private RuntimeNamedTypeInfo _definingTypeInfo; + private FieldHandle _fieldHandle; + private RuntimeTypeInfo _contextTypeInfo; + + private MetadataReader _reader; + private Field _field; + + private volatile FieldAccessor _lazyFieldAccessor = null; + +#if DEBUG + private String _debugName; +#endif + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs new file mode 100644 index 000000000..16e80353e --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Assignability.cs @@ -0,0 +1,405 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Reflection; +using System.Diagnostics; +using System.Reflection.Runtime.Types; +using System.Reflection.Runtime.TypeInfos; + +using Internal.Reflection.Core; + +namespace System.Reflection.Runtime.General +{ + internal static class Assignability + { + public static bool IsAssignableFrom(TypeInfo toTypeInfo, TypeInfo fromTypeInfo, FoundationTypes foundationTypes) + { + if (toTypeInfo == null) + throw new NullReferenceException(); + if (fromTypeInfo == null) + return false; // It would be more appropriate to throw ArgumentNullException here, but returning "false" is the desktop-compat behavior. + + if (fromTypeInfo.Equals(toTypeInfo)) + return true; + + if (toTypeInfo.IsGenericTypeDefinition) + { + // Asking whether something can cast to a generic type definition is arguably meaningless. The desktop CLR Reflection layer converts all + // generic type definitions to generic type instantiations closed over the formal generic type parameters. The .NET Native framework + // keeps the two separate. Fortunately, under either interpretation, returning "false" unless the two types are identical is still a + // defensible behavior. To avoid having the rest of the code deal with the differing interpretations, we'll short-circuit this now. + return false; + } + + if (fromTypeInfo.IsGenericTypeDefinition) + { + // The desktop CLR Reflection layer converts all generic type definitions to generic type instantiations closed over the formal + // generic type parameters. The .NET Native framework keeps the two separate. For the purpose of IsAssignableFrom(), + // it makes sense to unify the two for the sake of backward compat. We'll just make the transform here so that the rest of code + // doesn't need to know about this quirk. + fromTypeInfo = fromTypeInfo.GetGenericTypeDefinition().MakeGenericType(fromTypeInfo.GenericTypeParameters).GetTypeInfo(); + } + + if (fromTypeInfo.CanCastTo(toTypeInfo, foundationTypes)) + return true; + + Type toType = toTypeInfo.AsType(); + Type fromType = fromTypeInfo.AsType(); + + // Desktop compat: IsAssignableFrom() considers T as assignable to Nullable<T> (but does not check if T is a generic parameter.) + if (!fromType.IsGenericParameter) + { + Type nullableUnderlyingType = Nullable.GetUnderlyingType(toType); + if (nullableUnderlyingType != null && nullableUnderlyingType.Equals(fromType)) + return true; + } + return false; + } + + private static bool CanCastTo(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes) + { + if (fromTypeInfo.Equals(toTypeInfo)) + return true; + + if (fromTypeInfo.IsArray) + { + if (toTypeInfo.IsInterface) + return fromTypeInfo.CanCastArrayToInterface(toTypeInfo, foundationTypes); + + Type toType = toTypeInfo.AsType(); + if (fromTypeInfo.IsSubclassOf(toType)) + return true; // T[] is castable to Array or Object. + + if (!toTypeInfo.IsArray) + return false; + + int rank = fromTypeInfo.GetArrayRank(); + if (rank != toTypeInfo.GetArrayRank()) + return false; + + bool fromTypeIsSzArray = fromTypeInfo.IsSzArray(foundationTypes); + bool toTypeIsSzArray = toTypeInfo.IsSzArray(foundationTypes); + if (fromTypeIsSzArray != toTypeIsSzArray) + { + // T[] is assignable to T[*] but not vice-versa. + if (!(rank == 1 && !toTypeIsSzArray)) + { + return false; // T[*] is not castable to T[] + } + } + + TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo(); + TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo(); + return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes); + } + + if (fromTypeInfo.IsByRef) + { + if (!toTypeInfo.IsByRef) + return false; + + TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo(); + TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo(); + return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes); + } + + if (fromTypeInfo.IsPointer) + { + Type toType = toTypeInfo.AsType(); + if (toType.Equals(foundationTypes.SystemObject)) + return true; // T* is castable to Object. + + if (toType.Equals(foundationTypes.SystemUIntPtr)) + return true; // T* is castable to UIntPtr (but not IntPtr) + + if (!toTypeInfo.IsPointer) + return false; + + TypeInfo toElementTypeInfo = toTypeInfo.GetElementType().GetTypeInfo(); + TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo(); + return fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes); + } + + if (fromTypeInfo.IsGenericParameter) + { + // + // A generic parameter can be cast to any of its constraints, or object, if none are specified, or ValueType if the "struct" constraint is + // specified. + // + // This has to be coded as its own case as TypeInfo.BaseType on a generic parameter doesn't always return what you'd expect. + // + Type toType = toTypeInfo.AsType(); + if (toType.Equals(foundationTypes.SystemObject)) + return true; + + if (toType.Equals(foundationTypes.SystemValueType)) + { + GenericParameterAttributes attributes = fromTypeInfo.GenericParameterAttributes; + if ((attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) + return true; + } + + foreach (Type constraintType in fromTypeInfo.GetGenericParameterConstraints()) + { + if (constraintType.GetTypeInfo().CanCastTo(toTypeInfo, foundationTypes)) + return true; + } + + return false; + } + + if (toTypeInfo.IsArray || toTypeInfo.IsByRef || toTypeInfo.IsPointer || toTypeInfo.IsGenericParameter) + return false; + + if (fromTypeInfo.MatchesWithVariance(toTypeInfo, foundationTypes)) + return true; + + if (toTypeInfo.IsInterface) + { + foreach (Type ifc in fromTypeInfo.ImplementedInterfaces) + { + if (ifc.GetTypeInfo().MatchesWithVariance(toTypeInfo, foundationTypes)) + return true; + } + return false; + } + else + { + // Interfaces are always castable to System.Object. The code below will not catch this as interfaces report their BaseType as null. + if (toTypeInfo.AsType().Equals(foundationTypes.SystemObject) && fromTypeInfo.IsInterface) + return true; + + TypeInfo walk = fromTypeInfo; + for (;;) + { + Type baseType = walk.BaseType; + if (baseType == null) + return false; + walk = baseType.GetTypeInfo(); + if (walk.MatchesWithVariance(toTypeInfo, foundationTypes)) + return true; + } + } + } + + private static bool IsSzArray(this TypeInfo typeInfo, FoundationTypes foundationTypes) + { + if (!typeInfo.IsArray) + return false; + + if (typeInfo.GetArrayRank() != 1) + return false; + + if (((RuntimeTypeInfo)typeInfo).RuntimeType.InternalIsMultiDimArray) + return false; + + return true; + } + + // + // Check a base type or implemented interface type for equivalence (taking into account variance for generic instantiations.) + // Does not check ancestors recursively. + // + private static bool MatchesWithVariance(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes) + { + Debug.Assert(!(fromTypeInfo.IsArray || fromTypeInfo.IsByRef || fromTypeInfo.IsPointer || fromTypeInfo.IsGenericParameter)); + Debug.Assert(!(toTypeInfo.IsArray || toTypeInfo.IsByRef || toTypeInfo.IsPointer || toTypeInfo.IsGenericParameter)); + + if (fromTypeInfo.Equals(toTypeInfo)) + return true; + + if (!(fromTypeInfo.AsType().IsConstructedGenericType && toTypeInfo.AsType().IsConstructedGenericType)) + return false; + + TypeInfo genericTypeDefinition = fromTypeInfo.GetGenericTypeDefinition().GetTypeInfo(); + if (!genericTypeDefinition.AsType().Equals(toTypeInfo.GetGenericTypeDefinition())) + return false; + + Type[] fromTypeArguments = fromTypeInfo.GenericTypeArguments; + Type[] toTypeArguments = toTypeInfo.GenericTypeArguments; + Type[] genericTypeParameters = genericTypeDefinition.GenericTypeParameters; + for (int i = 0; i < genericTypeParameters.Length; i++) + { + TypeInfo fromTypeArgumentInfo = fromTypeArguments[i].GetTypeInfo(); + TypeInfo toTypeArgumentInfo = toTypeArguments[i].GetTypeInfo(); + + GenericParameterAttributes attributes = genericTypeParameters[i].GetTypeInfo().GenericParameterAttributes; + switch (attributes & GenericParameterAttributes.VarianceMask) + { + case GenericParameterAttributes.Covariant: + if (!(fromTypeArgumentInfo.IsGcReferenceTypeAndCastableTo(toTypeArgumentInfo, foundationTypes))) + return false; + break; + + case GenericParameterAttributes.Contravariant: + if (!(toTypeArgumentInfo.IsGcReferenceTypeAndCastableTo(fromTypeArgumentInfo, foundationTypes))) + return false; + break; + + case GenericParameterAttributes.None: + if (!(fromTypeArgumentInfo.Equals(toTypeArgumentInfo))) + return false; + break; + + default: + throw new BadImageFormatException(); // Unexpected variance value in metadata. + } + } + return true; + } + + // + // A[] can cast to B[] if one of the following are true: + // + // A can cast to B under variance rules. + // + // A and B are both integers or enums and have the same reduced type (i.e. represent the same-sized integer, ignoring signed/unsigned differences.) + // "char" is not interchangable with short/ushort. "bool" is not interchangable with byte/sbyte. + // + // For desktop compat, A& and A* follow the same rules. + // + private static bool IsElementTypeCompatibleWith(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes) + { + if (fromTypeInfo.IsGcReferenceTypeAndCastableTo(toTypeInfo, foundationTypes)) + return true; + + Type reducedFromType = fromTypeInfo.AsType().ReducedType(foundationTypes); + Type reducedToType = toTypeInfo.AsType().ReducedType(foundationTypes); + if (reducedFromType.Equals(reducedToType)) + return true; + + return false; + } + + private static Type ReducedType(this Type t, FoundationTypes foundationTypes) + { + if (t.GetTypeInfo().IsEnum) + t = Enum.GetUnderlyingType(t); + + if (t.Equals(foundationTypes.SystemByte)) + return foundationTypes.SystemSByte; + + if (t.Equals(foundationTypes.SystemUInt16)) + return foundationTypes.SystemInt16; + + if (t.Equals(foundationTypes.SystemUInt32)) + return foundationTypes.SystemInt32; + + if (t.Equals(foundationTypes.SystemUInt64)) + return foundationTypes.SystemInt64; + + if (t.Equals(foundationTypes.SystemUIntPtr) || t.Equals(foundationTypes.SystemIntPtr)) + { +#if WIN64 + return foundationTypes.SystemInt64; +#else + return foundationTypes.SystemInt32; +#endif + } + + return t; + } + + // + // Contra/CoVariance. + // + // IEnumerable<D> can cast to IEnumerable<B> if D can cast to B and if there's no possibility that D is a value type. + // + private static bool IsGcReferenceTypeAndCastableTo(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes) + { + if (fromTypeInfo.Equals(toTypeInfo)) + return true; + + if (fromTypeInfo.ProvablyAGcReferenceType(foundationTypes)) + return fromTypeInfo.CanCastTo(toTypeInfo, foundationTypes); + + return false; + } + + // + // A true result indicates that a type can never be a value type. This is important when testing variance-compatibility. + // + private static bool ProvablyAGcReferenceType(this TypeInfo t, FoundationTypes foundationTypes) + { + if (t.IsGenericParameter) + { + GenericParameterAttributes attributes = t.GenericParameterAttributes; + if ((attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0) + return true; // generic parameter with a "class" constraint. + } + + return t.ProvablyAGcReferenceTypeHelper(foundationTypes); + } + + private static bool ProvablyAGcReferenceTypeHelper(this TypeInfo t, FoundationTypes foundationTypes) + { + if (t.IsArray) + return true; + + if (t.IsByRef || t.IsPointer) + return false; + + if (t.IsGenericParameter) + { + // We intentionally do not check for a "class" constraint on generic parameter ancestors. + // That's because this property does not propagate up the constraining hierarchy. + // (e.g. "class A<S, T> where S : T, where T : class" does not guarantee that S is a class.) + + foreach (Type constraintType in t.GetGenericParameterConstraints()) + { + if (constraintType.GetTypeInfo().ProvablyAGcReferenceTypeHelper(foundationTypes)) + return true; + } + return false; + } + + return t.IsClass && !t.Equals(foundationTypes.SystemObject) && !t.Equals(foundationTypes.SystemValueType) && !t.Equals(foundationTypes.SystemEnum); + } + + // + // T[] casts to IList<T>. This could be handled by the normal ancestor-walking code + // but for one complication: T[] also casts to IList<U> if T[] casts to U[]. + // + private static bool CanCastArrayToInterface(this TypeInfo fromTypeInfo, TypeInfo toTypeInfo, FoundationTypes foundationTypes) + { + Debug.Assert(fromTypeInfo.IsArray); + Debug.Assert(toTypeInfo.IsInterface); + + Type toType = toTypeInfo.AsType(); + + if (toType.IsConstructedGenericType) + { + Type[] toTypeGenericTypeArguments = toTypeInfo.GenericTypeArguments; + if (toTypeGenericTypeArguments.Length != 1) + return false; + TypeInfo toElementTypeInfo = toTypeGenericTypeArguments[0].GetTypeInfo(); + + Type toTypeGenericTypeDefinition = toTypeInfo.GetGenericTypeDefinition(); + TypeInfo fromElementTypeInfo = fromTypeInfo.GetElementType().GetTypeInfo(); + foreach (Type ifc in fromTypeInfo.ImplementedInterfaces) + { + if (ifc.IsConstructedGenericType) + { + Type ifcGenericTypeDefinition = ifc.GetGenericTypeDefinition(); + if (ifcGenericTypeDefinition.Equals(toTypeGenericTypeDefinition)) + { + if (fromElementTypeInfo.IsElementTypeCompatibleWith(toElementTypeInfo, foundationTypes)) + return true; + } + } + } + return false; + } + else + { + foreach (Type ifc in fromTypeInfo.ImplementedInterfaces) + { + if (ifc.Equals(toType)) + return true; + } + return false; + } + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs new file mode 100644 index 000000000..9da335371 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/Dispensers.cs @@ -0,0 +1,614 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.IO; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.Dispensers; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.PropertyInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; + +using global::Internal.Metadata.NativeFormat; + +//================================================================================================================= +// This file collects the various chokepoints that create the various Runtime*Info objects. This allows +// easy reviewing of the overall caching and unification policy. +// +// The dispenser functions are defined as static members of the associated Info class. This permits us +// to keep the constructors private to ensure that these really are the only ways to obtain these objects. +//================================================================================================================= + +namespace System.Reflection.Runtime.Assemblies +{ + //----------------------------------------------------------------------------------------------------------- + // Assemblies (maps 1-1 with a MetadataReader/ScopeDefinitionHandle. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeAssembly : ExtensibleAssembly + { + internal static RuntimeAssembly GetRuntimeAssembly(ReflectionDomain reflectionDomain, RuntimeAssemblyName assemblyRefName) + { + RuntimeAssembly result; + Exception assemblyLoadException = TryGetRuntimeAssembly(reflectionDomain, assemblyRefName, out result); + if (assemblyLoadException != null) + throw assemblyLoadException; + return result; + } + + internal static Exception TryGetRuntimeAssembly(ReflectionDomain reflectionDomain, RuntimeAssemblyName assemblyRefName, out RuntimeAssembly result) + { + Debug.Assert(reflectionDomain == ReflectionCoreExecution.ExecutionDomain, "User Reflection Domains not yet implemented."); + result = _assemblyRefNameToAssemblyDispenser.GetOrAdd(assemblyRefName); + if (result != null) + return null; + else + return new FileNotFoundException(SR.Format(SR.FileNotFound_AssemblyNotFound, assemblyRefName.FullName)); + } + + private static Dispenser<RuntimeAssemblyName, RuntimeAssembly> _assemblyRefNameToAssemblyDispenser = + DispenserFactory.CreateDispenser<RuntimeAssemblyName, RuntimeAssembly>( + DispenserScenario.AssemblyRefName_Assembly, + delegate (RuntimeAssemblyName assemblyRefName) + { + ReflectionDomain reflectionDomain = ReflectionCoreExecution.ExecutionDomain; //@todo: Need to use the correct reflection domain! + AssemblyBinder binder = reflectionDomain.ReflectionDomainSetup.AssemblyBinder; + AssemblyName convertedAssemblyRefName = assemblyRefName.ToAssemblyName(); + MetadataReader reader; + ScopeDefinitionHandle scope; + Exception exception; + IEnumerable<QScopeDefinition> overflowScopes; + if (!binder.Bind(convertedAssemblyRefName, out reader, out scope, out overflowScopes, out exception)) + return null; + return GetRuntimeAssembly(reader, scope, overflowScopes, reflectionDomain); + } + ); + + + private static RuntimeAssembly GetRuntimeAssembly(MetadataReader reader, ScopeDefinitionHandle scope, IEnumerable<QScopeDefinition> overflows, ReflectionDomain reflectionDomain) + { + return _scopeToAssemblyDispenser.GetOrAdd(new RuntimeAssemblyKey(reader, scope, overflows)); + } + + private static Dispenser<RuntimeAssemblyKey, RuntimeAssembly> _scopeToAssemblyDispenser = + DispenserFactory.CreateDispenserV<RuntimeAssemblyKey, RuntimeAssembly>( + DispenserScenario.Scope_Assembly, + delegate (RuntimeAssemblyKey qScopeDefinition) + { + return new RuntimeAssembly(qScopeDefinition.Reader, qScopeDefinition.Handle, qScopeDefinition.Overflows); + } + ); + + //----------------------------------------------------------------------------------------------------------- + // Captures a qualified scope (a reader plus a handle) representing the canonical definition of an assembly, + // plus a set of "overflow" scopes representing additional pieces of the assembly. + //----------------------------------------------------------------------------------------------------------- + private struct RuntimeAssemblyKey : IEquatable<RuntimeAssemblyKey> + { + public RuntimeAssemblyKey(MetadataReader reader, ScopeDefinitionHandle handle, IEnumerable<QScopeDefinition> overflows) + { + _reader = reader; + _handle = handle; + _overflows = overflows; + } + + public MetadataReader Reader { get { return _reader; } } + public ScopeDefinitionHandle Handle { get { return _handle; } } + public IEnumerable<QScopeDefinition> Overflows { get { return _overflows; } } + public ScopeDefinition ScopeDefinition + { + get + { + return _handle.GetScopeDefinition(_reader); + } + } + + public override bool Equals(Object obj) + { + if (!(obj is RuntimeAssemblyKey)) + return false; + return Equals((RuntimeAssemblyKey)obj); + } + + + public bool Equals(RuntimeAssemblyKey other) + { + // Equality depends only on the canonical definition of an assembly, not + // the overflows. + if (!(this._reader == other._reader)) + return false; + if (!(this._handle.Equals(other._handle))) + return false; + return true; + } + + public override int GetHashCode() + { + return _handle.GetHashCode(); + } + + private readonly MetadataReader _reader; + private readonly ScopeDefinitionHandle _handle; + private readonly IEnumerable<QScopeDefinition> _overflows; + } + } +} + +namespace System.Reflection.Runtime.Modules +{ + //----------------------------------------------------------------------------------------------------------- + // Modules (these exist only because Modules still exist in the Win8P surface area. There is a 1-1 + // mapping between Assemblies and Modules.) + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeModule : ExtensibleModule + { + internal static RuntimeModule GetRuntimeModule(RuntimeAssembly assembly) + { + return new RuntimeModule(assembly); + } + } +} + +namespace System.Reflection.Runtime.TypeInfos +{ + //----------------------------------------------------------------------------------------------------------- + // TypeInfos in general. + //----------------------------------------------------------------------------------------------------------- + internal abstract partial class RuntimeTypeInfo : ExtensibleTypeInfo + { + internal static RuntimeTypeInfo GetRuntimeTypeInfo(RuntimeType runtimeType) + { + RuntimeTypeInfo runtimeTypeInfo = _typeToTypeInfoDispenser.GetOrAdd(runtimeType); +#if DEBUG + if (runtimeType != null) + runtimeTypeInfo.EstablishDebugName(); +#endif + return runtimeTypeInfo; + } + + private static Dispenser<RuntimeType, RuntimeTypeInfo> _typeToTypeInfoDispenser = + DispenserFactory.CreateDispenser<RuntimeType, RuntimeTypeInfo>(DispenserScenario.Type_TypeInfo, CreateRuntimeTypeInfo); + + private static RuntimeTypeInfo CreateRuntimeTypeInfo(RuntimeType runtimeType) + { + if (runtimeType.HasElementType) + { + if (runtimeType.IsArray) + return RuntimeArrayTypeInfo.GetRuntimeArrayTypeInfo(runtimeType); + else + return RuntimeHasElementTypeInfo.GetRuntimeHasElementypeInfo(runtimeType); + } + else if (runtimeType.IsConstructedGenericType) + { + RuntimeTypeHandle typeHandle; + if (runtimeType.InternalTryGetTypeHandle(out typeHandle) && ReflectionCoreExecution.ExecutionEnvironment.IsReflectionBlocked(typeHandle)) + return RuntimeBlockedTypeInfo.GetRuntimeBlockedTypeInfo(runtimeType); + return RuntimeConstructedGenericTypeInfo.GetRuntimeConstructedGenericTypeInfo(runtimeType); + } + else + { + RuntimeInspectionOnlyNamedType inspectionOnlyNamedType = runtimeType as RuntimeInspectionOnlyNamedType; + if (inspectionOnlyNamedType != null) + { + return inspectionOnlyNamedType.GetInspectionOnlyNamedRuntimeTypeInfo(); + } + else + { + RuntimeGenericParameterType genericParameterType = runtimeType as RuntimeGenericParameterType; + if (genericParameterType != null) + { + return RuntimeGenericParameterTypeInfo.GetRuntimeGenericParameterTypeInfo(genericParameterType); + } + else + { + MetadataReader reader; + TypeDefinitionHandle typeDefHandle; + if (ReflectionCoreExecution.ExecutionEnvironment.TryGetMetadataForNamedType(runtimeType.TypeHandle, out reader, out typeDefHandle)) + return RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(reader, typeDefHandle); + if (ReflectionCoreExecution.ExecutionEnvironment.IsReflectionBlocked(runtimeType.TypeHandle)) + return RuntimeBlockedTypeInfo.GetRuntimeBlockedTypeInfo(runtimeType); + else + return RuntimeNoMetadataNamedTypeInfo.GetRuntimeNoMetadataNamedTypeInfo(runtimeType); + } + } + } + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for type definitions (i.e. "Foo" and "Foo<>" but not "Foo<int>") + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeNamedTypeInfo : RuntimeTypeInfo + { + internal static RuntimeNamedTypeInfo GetRuntimeNamedTypeInfo(MetadataReader metadataReader, TypeDefinitionHandle typeDefHandle) + { + return _typeDefToRuntimeTypeInfoDispenser.GetOrAdd(new QTypeDefinition(metadataReader, typeDefHandle)); + } + + private static Dispenser<QTypeDefinition, RuntimeNamedTypeInfo> _typeDefToRuntimeTypeInfoDispenser = + DispenserFactory.CreateDispenserV<QTypeDefinition, RuntimeNamedTypeInfo>( + DispenserScenario.TypeDef_TypeInfo, + delegate (QTypeDefinition qTypeDefinition) + { + return new RuntimeNamedTypeInfo(qTypeDefinition.Reader, qTypeDefinition.Handle); + } + ); + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for type definitions (i.e. "Foo" and "Foo<>" but not "Foo<int>") that aren't opted into metadata. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeNoMetadataNamedTypeInfo : RuntimeTypeInfo + { + internal static RuntimeNoMetadataNamedTypeInfo GetRuntimeNoMetadataNamedTypeInfo(RuntimeType runtimeType) + { + return new RuntimeNoMetadataNamedTypeInfo(runtimeType); + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos that represent type definitions (i.e. Foo or Foo<>) or constructed generic types (Foo<int>) + // that can never be reflection-enabled due to the framework Reflection block. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeBlockedTypeInfo : RuntimeTypeInfo + { + internal static RuntimeBlockedTypeInfo GetRuntimeBlockedTypeInfo(RuntimeType runtimeType) + { + return new RuntimeBlockedTypeInfo(runtimeType); + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for Array, Pointer and ByRef types. + //----------------------------------------------------------------------------------------------------------- + internal partial class RuntimeHasElementTypeInfo : RuntimeTypeInfo + { + internal static RuntimeHasElementTypeInfo GetRuntimeHasElementypeInfo(RuntimeType hasElementType) + { + return new RuntimeHasElementTypeInfo(hasElementType); + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for Array types. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeArrayTypeInfo : RuntimeHasElementTypeInfo + { + internal static RuntimeArrayTypeInfo GetRuntimeArrayTypeInfo(RuntimeType hasElementType) + { + return new RuntimeArrayTypeInfo(hasElementType); + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for Constructed generic types ("Foo<int>") + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeConstructedGenericTypeInfo : RuntimeTypeInfo + { + internal static RuntimeConstructedGenericTypeInfo GetRuntimeConstructedGenericTypeInfo(RuntimeType runtimeConstructedGenericType) + { + return new RuntimeConstructedGenericTypeInfo(runtimeConstructedGenericType); + } + } + + //----------------------------------------------------------------------------------------------------------- + // TypeInfos for Generic type parameters (for both types and methods.) + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeGenericParameterTypeInfo : RuntimeTypeInfo + { + internal static RuntimeGenericParameterTypeInfo GetRuntimeGenericParameterTypeInfo(RuntimeGenericParameterType runtimeGenericParameterType) + { + return new RuntimeGenericParameterTypeInfo(runtimeGenericParameterType); + } + } +} + +namespace System.Reflection.Runtime.Types +{ + //----------------------------------------------------------------------------------------------------------- + // Types for named types that don't have EETypes. + //----------------------------------------------------------------------------------------------------------- + internal partial class RuntimeInspectionOnlyNamedType : RuntimeType + { + internal static RuntimeInspectionOnlyNamedType GetRuntimeInspectionOnlyNamedType(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle) + { + return new RuntimeInspectionOnlyNamedType(reader, typeDefinitionHandle); + } + } +} + +namespace System.Reflection.Runtime.FieldInfos +{ + //----------------------------------------------------------------------------------------------------------- + // FieldInfos + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeFieldInfo : ExtensibleFieldInfo + { + internal static RuntimeFieldInfo GetRuntimeFieldInfo(FieldHandle fieldHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + return new RuntimeFieldInfo(fieldHandle, definingTypeInfo, contextTypeInfo).WithDebugName(); + } + } +} + +namespace System.Reflection.Runtime.MethodInfos +{ + //----------------------------------------------------------------------------------------------------------- + // ConstructorInfos + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimePlainConstructorInfo : RuntimeConstructorInfo + { + internal static RuntimePlainConstructorInfo GetRuntimePlainConstructorInfo(MethodHandle methodHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + return new RuntimePlainConstructorInfo(methodHandle, definingTypeInfo, contextTypeInfo); + } + } + + //----------------------------------------------------------------------------------------------------------- + // Constructors for array types. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo + { + internal static RuntimeSyntheticConstructorInfo GetRuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeType declaringType, RuntimeType[] runtimeParameterTypesAndReturn, InvokerOptions options, Func<Object, Object[], Object> invoker) + { + return new RuntimeSyntheticConstructorInfo(syntheticMethodId, declaringType, runtimeParameterTypesAndReturn, options, invoker); + } + } + + //----------------------------------------------------------------------------------------------------------- + // MethodInfos for method definitions (i.e. Foo.Moo() or Foo.Moo<>() but not Foo.Moo<int>) + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeNamedMethodInfo : RuntimeMethodInfo + { + internal static RuntimeNamedMethodInfo GetRuntimeNamedMethodInfo(MethodHandle methodHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + RuntimeNamedMethodInfo method = new RuntimeNamedMethodInfo(methodHandle, definingTypeInfo, contextTypeInfo); + method.WithDebugName(); + return method; + } + } + + //----------------------------------------------------------------------------------------------------------- + // MethodInfos for constructed generic methods (Foo.Moo<int> but not Foo.Moo<>) + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeConstructedGenericMethodInfo : RuntimeMethodInfo + { + internal static RuntimeMethodInfo GetRuntimeConstructedGenericMethodInfo(RuntimeNamedMethodInfo genericMethodDefinition, RuntimeType[] genericTypeArguments) + { + return new RuntimeConstructedGenericMethodInfo(genericMethodDefinition, genericTypeArguments).WithDebugName(); + } + } + + //----------------------------------------------------------------------------------------------------------- + // MethodInfos for the Get/Set methods on array types. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo + { + internal static RuntimeMethodInfo GetRuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeType declaringType, RuntimeType[] runtimeParameterTypesAndReturn, InvokerOptions options, Func<Object, Object[], Object> invoker) + { + return new RuntimeSyntheticMethodInfo(syntheticMethodId, name, declaringType, runtimeParameterTypesAndReturn, options, invoker).WithDebugName(); + } + } +} + +namespace System.Reflection.Runtime.PropertyInfos +{ + //----------------------------------------------------------------------------------------------------------- + // PropertyInfos + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimePropertyInfo : ExtensiblePropertyInfo + { + internal static RuntimePropertyInfo GetRuntimePropertyInfo(PropertyHandle propertyHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + return new RuntimePropertyInfo(propertyHandle, definingTypeInfo, contextTypeInfo).WithDebugName(); + } + } +} + +namespace System.Reflection.Runtime.EventInfos +{ + //----------------------------------------------------------------------------------------------------------- + // EventInfos + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeEventInfo : ExtensibleEventInfo + { + internal static RuntimeEventInfo GetRuntimeEventInfo(EventHandle eventHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + return new RuntimeEventInfo(eventHandle, definingTypeInfo, contextTypeInfo).WithDebugName(); + } + } +} + +namespace System.Reflection.Runtime.ParameterInfos +{ + //----------------------------------------------------------------------------------------------------------- + // ParameterInfos for MethodBase objects with no Parameter metadata. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeThinMethodParameterInfo : RuntimeMethodParameterInfo + { + internal static RuntimeThinMethodParameterInfo GetRuntimeThinMethodParameterInfo(MethodBase member, int position, ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeHandle, TypeContext typeContext) + { + return new RuntimeThinMethodParameterInfo(member, position, reflectionDomain, reader, typeHandle, typeContext); + } + } + + //----------------------------------------------------------------------------------------------------------- + // ParameterInfos for MethodBase objects with Parameter metadata. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeFatMethodParameterInfo : RuntimeMethodParameterInfo + { + internal static RuntimeFatMethodParameterInfo GetRuntimeFatMethodParameterInfo(MethodBase member, MethodHandle methodHandle, int position, ParameterHandle parameterHandle, ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeHandle, TypeContext typeContext) + { + return new RuntimeFatMethodParameterInfo(member, methodHandle, position, parameterHandle, reflectionDomain, reader, typeHandle, typeContext); + } + } + + //----------------------------------------------------------------------------------------------------------- + // ParameterInfos returned by PropertyInfo.GetIndexParameters() + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimePropertyIndexParameterInfo : RuntimeParameterInfo + { + internal static RuntimePropertyIndexParameterInfo GetRuntimePropertyIndexParameterInfo(RuntimePropertyInfo member, RuntimeParameterInfo backingParameter) + { + return new RuntimePropertyIndexParameterInfo(member, backingParameter); + } + } + + //----------------------------------------------------------------------------------------------------------- + // ParameterInfos returned by Get/Set methods on array types. + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class RuntimeSyntheticParameterInfo : RuntimeParameterInfo + { + internal static RuntimeSyntheticParameterInfo GetRuntimeSyntheticParameterInfo(MemberInfo member, int position, RuntimeType parameterType) + { + return new RuntimeSyntheticParameterInfo(member, position, parameterType); + } + } +} + +namespace System.Reflection.Runtime.CustomAttributes +{ + //----------------------------------------------------------------------------------------------------------- + // CustomAttributeData objects returned by various CustomAttributes properties. + //----------------------------------------------------------------------------------------------------------- + internal abstract partial class RuntimeCustomAttributeData : ExtensibleCustomAttributeData + { + internal static IEnumerable<CustomAttributeData> GetCustomAttributes(ReflectionDomain reflectionDomain, MetadataReader reader, IEnumerable<CustomAttributeHandle> customAttributeHandles) + { + foreach (CustomAttributeHandle customAttributeHandle in customAttributeHandles) + yield return GetCustomAttributeData(reflectionDomain, reader, customAttributeHandle); + } + + private static CustomAttributeData GetCustomAttributeData(ReflectionDomain reflectionDomain, MetadataReader reader, CustomAttributeHandle customAttributeHandle) + { + return new RuntimeNormalCustomAttributeData(reflectionDomain, reader, customAttributeHandle); + } + } +} + +namespace System.Reflection.Runtime.TypeParsing +{ + //----------------------------------------------------------------------------------------------------------- + // Name looks of namespace types. (Affects both type reference resolution and Type.GetType() calls.) + //----------------------------------------------------------------------------------------------------------- + internal sealed partial class NamespaceTypeName : NamedTypeName + { + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = _runtimeNamespaceTypeByNameDispenser.GetOrAdd(new NamespaceTypeNameKey(reflectionDomain, currentAssembly, this)); + if (result != null) + return null; + if (!ignoreCase) + return new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFound, this.ToString(), currentAssembly.FullName)); + + return TryResolveCaseInsensitive(reflectionDomain, currentAssembly, out result); + } + + private static Dispenser<NamespaceTypeNameKey, RuntimeType> _runtimeNamespaceTypeByNameDispenser = + DispenserFactory.CreateDispenserV<NamespaceTypeNameKey, RuntimeType>( + DispenserScenario.AssemblyAndNamespaceTypeName_Type, + delegate (NamespaceTypeNameKey key) + { + RuntimeType result; + Exception typeLoadException = key.NamespaceTypeName.UncachedTryResolveCaseSensitive(key.ReflectionDomain, key.RuntimeAssembly, out result); + if (typeLoadException != null) + return null; + else + return result; + } + ); + + private static LowLevelDictionary<String, QHandle> GetCaseInsensitiveTypeDictionary(RuntimeAssembly assembly) + { + return _caseInsensitiveTypeDictionaryDispenser.GetOrAdd(assembly); + } + + private static Dispenser<RuntimeAssembly, LowLevelDictionary<String, QHandle>> _caseInsensitiveTypeDictionaryDispenser = + DispenserFactory.CreateDispenserV<RuntimeAssembly, LowLevelDictionary<String, QHandle>>( + DispenserScenario.RuntimeAssembly_CaseInsensitiveTypeDictionary, + CreateCaseInsensitiveTypeDictionary + ); + + + // + // Hash key for resolving NamespaceTypeNames to RuntimeTypes. + // + private struct NamespaceTypeNameKey : IEquatable<NamespaceTypeNameKey> + { + public NamespaceTypeNameKey(ReflectionDomain reflectionDomain, RuntimeAssembly runtimeAssembly, NamespaceTypeName namespaceTypeName) + { + _reflectionDomain = reflectionDomain; + _runtimeAssembly = runtimeAssembly; + _namespaceTypeName = namespaceTypeName; + } + + public ReflectionDomain ReflectionDomain + { + get + { + return _reflectionDomain; + } + } + + public RuntimeAssembly RuntimeAssembly + { + get + { + return _runtimeAssembly; + } + } + + public NamespaceTypeName NamespaceTypeName + { + get + { + return _namespaceTypeName; + } + } + + public override bool Equals(Object obj) + { + if (!(obj is NamespaceTypeNameKey)) + return false; + return Equals((NamespaceTypeNameKey)obj); + } + + public bool Equals(NamespaceTypeNameKey other) + { + if (!(this._namespaceTypeName._name.Equals(other._namespaceTypeName._name))) + return false; + if (!(this._namespaceTypeName._namespaceParts.Length == other._namespaceTypeName._namespaceParts.Length)) + return false; + int count = this._namespaceTypeName._namespaceParts.Length; + for (int i = 0; i < count; i++) + { + if (!(this._namespaceTypeName._namespaceParts[i] == other._namespaceTypeName._namespaceParts[i])) + return false; + } + if (!(this._runtimeAssembly.Equals(other._runtimeAssembly))) + return false; + return true; + } + + public override int GetHashCode() + { + return _namespaceTypeName._name.GetHashCode(); + } + + private ReflectionDomain _reflectionDomain; + private RuntimeAssembly _runtimeAssembly; + private NamespaceTypeName _namespaceTypeName; + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs new file mode 100644 index 000000000..541aa70d2 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/MetadataReaderExtensions.cs @@ -0,0 +1,548 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Text; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.TypeParsing; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + // + // Collect various metadata reading tasks for better chunking... + // + internal static class MetadataReaderExtensions + { + public static string GetString(this ConstantStringValueHandle handle, MetadataReader reader) + { + return reader.GetConstantStringValue(handle).Value; + } + + // Useful for namespace Name string which can be a null handle. + public static String GetStringOrNull(this ConstantStringValueHandle handle, MetadataReader reader) + { + if (reader.IsNull(handle)) + return null; + return reader.GetConstantStringValue(handle).Value; + } + + public static bool StringOrNullEquals(this ConstantStringValueHandle handle, String valueOrNull, MetadataReader reader) + { + if (valueOrNull == null) + return handle.IsNull(reader); + if (handle.IsNull(reader)) + return false; + return handle.StringEquals(valueOrNull, reader); + } + + // Needed for RuntimeMappingTable access + public static int AsInt(this TypeDefinitionHandle typeDefinitionHandle) + { + unsafe + { + return *(int*)&typeDefinitionHandle; + } + } + + public static TypeDefinitionHandle AsTypeDefinitionHandle(this int i) + { + unsafe + { + return *(TypeDefinitionHandle*)&i; + } + } + + public static int AsInt(this MethodHandle methodHandle) + { + unsafe + { + return *(int*)&methodHandle; + } + } + + public static MethodHandle AsMethodHandle(this int i) + { + unsafe + { + return *(MethodHandle*)&i; + } + } + + public static int AsInt(this FieldHandle fieldHandle) + { + unsafe + { + return *(int*)&fieldHandle; + } + } + + public static FieldHandle AsFieldHandle(this int i) + { + unsafe + { + return *(FieldHandle*)&i; + } + } + + + public static bool IsTypeDefRefOrSpecHandle(this Handle handle, MetadataReader reader) + { + HandleType handleType = handle.HandleType; + return handleType == HandleType.TypeDefinition || + handleType == HandleType.TypeReference || + handleType == HandleType.TypeSpecification; + } + + public static bool IsNamespaceDefinitionHandle(this Handle handle, MetadataReader reader) + { + HandleType handleType = handle.HandleType; + return handleType == HandleType.NamespaceDefinition; + } + + public static bool IsNamespaceReferenceHandle(this Handle handle, MetadataReader reader) + { + HandleType handleType = handle.HandleType; + return handleType == HandleType.NamespaceReference; + } + + // Conversion where a invalid handle type indicates bad metadata rather a mistake by the caller. + public static ScopeReferenceHandle ToExpectedScopeReferenceHandle(this Handle handle, MetadataReader reader) + { + try + { + return handle.ToScopeReferenceHandle(reader); + } + catch (ArgumentException) + { + throw new BadImageFormatException(); + } + } + + // Conversion where a invalid handle type indicates bad metadata rather a mistake by the caller. + public static NamespaceReferenceHandle ToExpectedNamespaceReferenceHandle(this Handle handle, MetadataReader reader) + { + try + { + return handle.ToNamespaceReferenceHandle(reader); + } + catch (ArgumentException) + { + throw new BadImageFormatException(); + } + } + + // Conversion where a invalid handle type indicates bad metadata rather a mistake by the caller. + public static TypeDefinitionHandle ToExpectedTypeDefinitionHandle(this Handle handle, MetadataReader reader) + { + try + { + return handle.ToTypeDefinitionHandle(reader); + } + catch (ArgumentException) + { + throw new BadImageFormatException(); + } + } + + public static MethodSignature ParseMethodSignature(this Handle handle, MetadataReader reader) + { + return handle.ToMethodSignatureHandle(reader).GetMethodSignature(reader); + } + + public static FieldSignature ParseFieldSignature(this Handle handle, MetadataReader reader) + { + return handle.ToFieldSignatureHandle(reader).GetFieldSignature(reader); + } + + public static PropertySignature ParsePropertySignature(this Handle handle, MetadataReader reader) + { + return handle.ToPropertySignatureHandle(reader).GetPropertySignature(reader); + } + + // + // Used to split methods between DeclaredMethods and DeclaredConstructors. + // + public static bool IsConstructor(this MethodHandle methodHandle, MetadataReader reader) + { + Method method = methodHandle.GetMethod(reader); + return IsConstructor(ref method, reader); + } + + // This is specially designed for a hot path so we make some compromises in the signature: + // + // - "method" is passed by reference even though no side-effects are intended. + // + public static bool IsConstructor(ref Method method, MetadataReader reader) + { + if ((method.Flags & (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName)) != (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName)) + return false; + + ConstantStringValueHandle nameHandle = method.Name; + return nameHandle.StringEquals(ConstructorInfo.ConstructorName, reader) || nameHandle.StringEquals(ConstructorInfo.TypeConstructorName, reader); + } + + public static Object ParseConstantValue(this Handle handle, ReflectionDomain reflectionDomain, MetadataReader reader) + { + Object value; + Exception exception = handle.TryParseConstantValue(reflectionDomain, reader, out value); + if (exception != null) + throw exception; + return value; + } + + public static Exception TryParseConstantValue(this Handle handle, ReflectionDomain reflectionDomain, MetadataReader reader, out Object value) + { + HandleType handleType = handle.HandleType; + switch (handleType) + { + case HandleType.ConstantBooleanValue: + value = handle.ToConstantBooleanValueHandle(reader).GetConstantBooleanValue(reader).Value; + return null; + case HandleType.ConstantStringValue: + value = handle.ToConstantStringValueHandle(reader).GetConstantStringValue(reader).Value; + return null; + case HandleType.ConstantCharValue: + value = handle.ToConstantCharValueHandle(reader).GetConstantCharValue(reader).Value; + return null; + case HandleType.ConstantByteValue: + value = handle.ToConstantByteValueHandle(reader).GetConstantByteValue(reader).Value; + return null; + case HandleType.ConstantSByteValue: + value = handle.ToConstantSByteValueHandle(reader).GetConstantSByteValue(reader).Value; + return null; + case HandleType.ConstantInt16Value: + value = handle.ToConstantInt16ValueHandle(reader).GetConstantInt16Value(reader).Value; + return null; + case HandleType.ConstantUInt16Value: + value = handle.ToConstantUInt16ValueHandle(reader).GetConstantUInt16Value(reader).Value; + return null; + case HandleType.ConstantInt32Value: + value = handle.ToConstantInt32ValueHandle(reader).GetConstantInt32Value(reader).Value; + return null; + case HandleType.ConstantUInt32Value: + value = handle.ToConstantUInt32ValueHandle(reader).GetConstantUInt32Value(reader).Value; + return null; + case HandleType.ConstantInt64Value: + value = handle.ToConstantInt64ValueHandle(reader).GetConstantInt64Value(reader).Value; + return null; + case HandleType.ConstantUInt64Value: + value = handle.ToConstantUInt64ValueHandle(reader).GetConstantUInt64Value(reader).Value; + return null; + case HandleType.ConstantSingleValue: + value = handle.ToConstantSingleValueHandle(reader).GetConstantSingleValue(reader).Value; + return null; + case HandleType.ConstantDoubleValue: + value = handle.ToConstantDoubleValueHandle(reader).GetConstantDoubleValue(reader).Value; + return null; + case HandleType.TypeDefinition: + case HandleType.TypeReference: + case HandleType.TypeSpecification: + { + Exception exception = null; + value = reflectionDomain.TryResolve(reader, handle, new TypeContext(null, null), ref exception); + return (value == null) ? exception : null; + } + case HandleType.ConstantReferenceValue: + value = null; + return null; + default: + { + Exception exception; + value = handle.TryParseConstantArray(reflectionDomain, reader, out exception); + if (value == null) + return exception; + return null; + } + } + } + + public static IEnumerable TryParseConstantArray(this Handle handle, ReflectionDomain reflectionDomain, MetadataReader reader, out Exception exception) + { + exception = null; + + HandleType handleType = handle.HandleType; + switch (handleType) + { + case HandleType.ConstantBooleanArray: + return handle.ToConstantBooleanArrayHandle(reader).GetConstantBooleanArray(reader).Value; + + case HandleType.ConstantStringArray: + return handle.ToConstantStringArrayHandle(reader).GetConstantStringArray(reader).Value; + + case HandleType.ConstantCharArray: + return handle.ToConstantCharArrayHandle(reader).GetConstantCharArray(reader).Value; + + case HandleType.ConstantByteArray: + return handle.ToConstantByteArrayHandle(reader).GetConstantByteArray(reader).Value; + + case HandleType.ConstantSByteArray: + return handle.ToConstantSByteArrayHandle(reader).GetConstantSByteArray(reader).Value; + + case HandleType.ConstantInt16Array: + return handle.ToConstantInt16ArrayHandle(reader).GetConstantInt16Array(reader).Value; + + case HandleType.ConstantUInt16Array: + return handle.ToConstantUInt16ArrayHandle(reader).GetConstantUInt16Array(reader).Value; + + case HandleType.ConstantInt32Array: + return handle.ToConstantInt32ArrayHandle(reader).GetConstantInt32Array(reader).Value; + + case HandleType.ConstantUInt32Array: + return handle.ToConstantUInt32ArrayHandle(reader).GetConstantUInt32Array(reader).Value; + + case HandleType.ConstantInt64Array: + return handle.ToConstantInt64ArrayHandle(reader).GetConstantInt64Array(reader).Value; + + case HandleType.ConstantUInt64Array: + return handle.ToConstantUInt64ArrayHandle(reader).GetConstantUInt64Array(reader).Value; + + case HandleType.ConstantSingleArray: + return handle.ToConstantSingleArrayHandle(reader).GetConstantSingleArray(reader).Value; + + case HandleType.ConstantDoubleArray: + return handle.ToConstantDoubleArrayHandle(reader).GetConstantDoubleArray(reader).Value; + + case HandleType.ConstantHandleArray: + { + Handle[] constantHandles = handle.ToConstantHandleArrayHandle(reader).GetConstantHandleArray(reader).Value.ToArray(); + object[] elements = new object[constantHandles.Length]; + for (int i = 0; i < constantHandles.Length; i++) + { + exception = constantHandles[i].TryParseConstantValue(reflectionDomain, reader, out elements[i]); + if (exception != null) + return null; + } + return elements; + } + default: + throw new BadImageFormatException(); + } + } + + // + // Lightweight check to see if a custom attribute's is of a well-known type. + // + // This check performs without instantating the Type object and bloating memory usage. On the flip side, + // it doesn't check on whether the type is defined in a paricular assembly. The desktop CLR typically doesn't + // check this either so this is useful from a compat persective as well. + // + public static bool IsCustomAttributeOfType(this CustomAttributeHandle customAttributeHandle, + MetadataReader reader, + String ns, + String name) + { + String[] namespaceParts = ns.Split('.'); + Handle typeHandle = customAttributeHandle.GetCustomAttribute(reader).Type; + HandleType handleType = typeHandle.HandleType; + if (handleType == HandleType.TypeDefinition) + { + TypeDefinition typeDefinition = typeHandle.ToTypeDefinitionHandle(reader).GetTypeDefinition(reader); + if (!typeDefinition.Name.StringEquals(name, reader)) + return false; + NamespaceDefinitionHandle nsHandle = typeDefinition.NamespaceDefinition; + int idx = namespaceParts.Length; + while (idx-- != 0) + { + String namespacePart = namespaceParts[idx]; + NamespaceDefinition namespaceDefinition = nsHandle.GetNamespaceDefinition(reader); + if (!namespaceDefinition.Name.StringOrNullEquals(namespacePart, reader)) + return false; + if (!namespaceDefinition.ParentScopeOrNamespace.IsNamespaceDefinitionHandle(reader)) + return false; + nsHandle = namespaceDefinition.ParentScopeOrNamespace.ToNamespaceDefinitionHandle(reader); + } + if (!nsHandle.GetNamespaceDefinition(reader).Name.StringOrNullEquals(null, reader)) + return false; + return true; + } + else if (handleType == HandleType.TypeReference) + { + TypeReference typeReference = typeHandle.ToTypeReferenceHandle(reader).GetTypeReference(reader); + if (!typeReference.TypeName.StringEquals(name, reader)) + return false; + if (!typeReference.ParentNamespaceOrType.IsNamespaceReferenceHandle(reader)) + return false; + NamespaceReferenceHandle nsHandle = typeReference.ParentNamespaceOrType.ToNamespaceReferenceHandle(reader); + int idx = namespaceParts.Length; + while (idx-- != 0) + { + String namespacePart = namespaceParts[idx]; + NamespaceReference namespaceReference = nsHandle.GetNamespaceReference(reader); + if (!namespaceReference.Name.StringOrNullEquals(namespacePart, reader)) + return false; + if (!namespaceReference.ParentScopeOrNamespace.IsNamespaceReferenceHandle(reader)) + return false; + nsHandle = namespaceReference.ParentScopeOrNamespace.ToNamespaceReferenceHandle(reader); + } + if (!nsHandle.GetNamespaceReference(reader).Name.StringOrNullEquals(null, reader)) + return false; + return true; + } + else + throw new NotSupportedException(); + } + + + public static String ToNamespaceName(this NamespaceDefinitionHandle namespaceDefinitionHandle, MetadataReader reader) + { + String ns = ""; + for (; ;) + { + NamespaceDefinition currentNamespaceDefinition = namespaceDefinitionHandle.GetNamespaceDefinition(reader); + String name = currentNamespaceDefinition.Name.GetStringOrNull(reader); + if (name != null) + { + if (ns.Length != 0) + ns = "." + ns; + ns = name + ns; + } + Handle nextHandle = currentNamespaceDefinition.ParentScopeOrNamespace; + HandleType handleType = nextHandle.HandleType; + if (handleType == HandleType.ScopeDefinition) + break; + if (handleType == HandleType.NamespaceDefinition) + { + namespaceDefinitionHandle = nextHandle.ToNamespaceDefinitionHandle(reader); + continue; + } + + throw new BadImageFormatException(SR.Bif_InvalidMetadata); + } + return ns; + } + + public static IEnumerable<NamespaceDefinitionHandle> GetTransitiveNamespaces(this MetadataReader reader, IEnumerable<NamespaceDefinitionHandle> namespaceHandles) + { + foreach (NamespaceDefinitionHandle namespaceHandle in namespaceHandles) + { + yield return namespaceHandle; + + NamespaceDefinition namespaceDefinition = namespaceHandle.GetNamespaceDefinition(reader); + foreach (NamespaceDefinitionHandle childNamespaceHandle in GetTransitiveNamespaces(reader, namespaceDefinition.NamespaceDefinitions)) + yield return childNamespaceHandle; + } + } + + public static IEnumerable<TypeDefinitionHandle> GetTopLevelTypes(this MetadataReader reader, IEnumerable<NamespaceDefinitionHandle> namespaceHandles) + { + foreach (NamespaceDefinitionHandle namespaceHandle in namespaceHandles) + { + NamespaceDefinition namespaceDefinition = namespaceHandle.GetNamespaceDefinition(reader); + foreach (TypeDefinitionHandle typeDefinitionHandle in namespaceDefinition.TypeDefinitions) + { + yield return typeDefinitionHandle; + } + } + } + + public static IEnumerable<TypeDefinitionHandle> GetTransitiveTypes(this MetadataReader reader, IEnumerable<TypeDefinitionHandle> typeDefinitionHandles, bool publicOnly) + { + foreach (TypeDefinitionHandle typeDefinitionHandle in typeDefinitionHandles) + { + TypeDefinition typeDefinition = typeDefinitionHandle.GetTypeDefinition(reader); + + if (publicOnly) + { + TypeAttributes visibility = typeDefinition.Flags & TypeAttributes.VisibilityMask; + if (visibility != TypeAttributes.Public && visibility != TypeAttributes.NestedPublic) + continue; + } + + yield return typeDefinitionHandle; + + foreach (TypeDefinitionHandle nestedTypeDefinitionHandle in GetTransitiveTypes(reader, typeDefinition.NestedTypes, publicOnly)) + yield return nestedTypeDefinitionHandle; + } + } + + public static AssemblyQualifiedTypeName ToAssemblyQualifiedTypeName(this NamespaceReferenceHandle namespaceReferenceHandle, String typeName, MetadataReader reader) + { + LowLevelList<String> namespaceParts = new LowLevelList<String>(8); + NamespaceReference namespaceReference; + for (; ;) + { + namespaceReference = namespaceReferenceHandle.GetNamespaceReference(reader); + String namespacePart = namespaceReference.Name.GetStringOrNull(reader); + if (namespacePart == null) + break; + namespaceParts.Add(namespacePart); + namespaceReferenceHandle = namespaceReference.ParentScopeOrNamespace.ToExpectedNamespaceReferenceHandle(reader); + } + + ScopeReferenceHandle scopeReferenceHandle = namespaceReference.ParentScopeOrNamespace.ToExpectedScopeReferenceHandle(reader); + RuntimeAssemblyName assemblyName = scopeReferenceHandle.ToRuntimeAssemblyName(reader); + return new AssemblyQualifiedTypeName(new NamespaceTypeName(namespaceParts.ToArray(), typeName), assemblyName); + } + + public static RuntimeAssemblyName ToRuntimeAssemblyName(this ScopeDefinitionHandle scopeDefinitionHandle, MetadataReader reader) + { + ScopeDefinition scopeDefinition = scopeDefinitionHandle.GetScopeDefinition(reader); + return CreateRuntimeAssemblyNameFromMetadata( + reader, + scopeDefinition.Name, + scopeDefinition.MajorVersion, + scopeDefinition.MinorVersion, + scopeDefinition.BuildNumber, + scopeDefinition.RevisionNumber, + scopeDefinition.Culture, + scopeDefinition.PublicKey, + scopeDefinition.Flags + ); + } + + public static RuntimeAssemblyName ToRuntimeAssemblyName(this ScopeReferenceHandle scopeReferenceHandle, MetadataReader reader) + { + ScopeReference scopeReference = scopeReferenceHandle.GetScopeReference(reader); + return CreateRuntimeAssemblyNameFromMetadata( + reader, + scopeReference.Name, + scopeReference.MajorVersion, + scopeReference.MinorVersion, + scopeReference.BuildNumber, + scopeReference.RevisionNumber, + scopeReference.Culture, + scopeReference.PublicKeyOrToken, + scopeReference.Flags + ); + } + + private static RuntimeAssemblyName CreateRuntimeAssemblyNameFromMetadata( + MetadataReader reader, + ConstantStringValueHandle name, + ushort majorVersion, + ushort minorVersion, + ushort buildNumber, + ushort revisionNumber, + ConstantStringValueHandle culture, + IEnumerable<byte> publicKeyOrToken, + AssemblyFlags assemblyFlags) + { + AssemblyNameFlags assemblyNameFlags = AssemblyNameFlags.None; + if (0 != (assemblyFlags & AssemblyFlags.PublicKey)) + assemblyNameFlags |= AssemblyNameFlags.PublicKey; + if (0 != (assemblyFlags & AssemblyFlags.Retargetable)) + assemblyNameFlags |= AssemblyNameFlags.Retargetable; + int contentType = ((int)assemblyFlags) & 0x00000E00; + assemblyNameFlags |= (AssemblyNameFlags)contentType; + + return new RuntimeAssemblyName( + name.GetString(reader), + new Version(majorVersion, minorVersion, buildNumber, revisionNumber), + culture.GetStringOrNull(reader), + assemblyNameFlags, + publicKeyOrToken.ToArray() + ); + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs new file mode 100644 index 000000000..5b8246b14 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/NamespaceChain.cs @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Text; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + // + // Since computation of the fullname and the declaring assembly both require walking up the namespace chain, + // cache both results the first time we walk the chain. + // + internal sealed class NamespaceChain + { + internal NamespaceChain(MetadataReader reader, NamespaceDefinitionHandle innerMostNamespaceHandle) + { + NamespaceDefinition currentNamespaceDefinition = innerMostNamespaceHandle.GetNamespaceDefinition(reader); + ConstantStringValueHandle currentNameHandle = currentNamespaceDefinition.Name; + Handle currentNamespaceHandle = innerMostNamespaceHandle.ToHandle(reader); + LowLevelList<String> names = new LowLevelList<String>(); + for (; ;) + { + String name = currentNameHandle.GetStringOrNull(reader); + names.Add(name); + currentNamespaceHandle = currentNamespaceDefinition.ParentScopeOrNamespace; + HandleType handleType = currentNamespaceHandle.HandleType; + if (handleType == HandleType.ScopeDefinition) + break; + if (handleType == HandleType.NamespaceDefinition) + { + NamespaceDefinitionHandle nsHandle = currentNamespaceHandle.ToNamespaceDefinitionHandle(reader); + currentNamespaceDefinition = nsHandle.GetNamespaceDefinition(reader); + currentNameHandle = currentNamespaceDefinition.Name; + continue; + } + + throw new BadImageFormatException(SR.Bif_InvalidMetadata); + } + + DefiningScope = currentNamespaceHandle.ToScopeDefinitionHandle(reader); + + int count = names.Count; + if (count == 0) + { + // Every namespace chain has to start with the root namespace. + throw new BadImageFormatException(); + } + else if (count == 1) + { + // The root namespace. For compat with the desktop, TypeInfo.NameSpaces returns null in this case. + NameSpace = null; + } + else + { + // Namespace has at least one non-root component. + StringBuilder sb = new StringBuilder(); + int idx = count - 1; + while (idx-- != 0) + { + String name = names[idx]; + if (name == null) + throw new BadImageFormatException(); // null namespace fragment found in middle. + sb.Append(name); + if (idx != 0) + sb.Append('.'); + } + NameSpace = sb.ToString(); + } + } + + internal String NameSpace { get; private set; } + internal ScopeDefinitionHandle DefiningScope { get; private set; } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QHandles.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QHandles.cs new file mode 100644 index 000000000..2b90c771e --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/QHandles.cs @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// Collection of "qualified handle" tuples. +// + +using global::System; +using global::System.Collections.Generic; +using global::System.Diagnostics; + +using global::Internal.Metadata.NativeFormat; + +namespace Internal.Reflection.Core +{ + public struct QScopeDefinition : IEquatable<QScopeDefinition> + { + public QScopeDefinition(MetadataReader reader, ScopeDefinitionHandle handle) + { + _reader = reader; + _handle = handle; + } + + public MetadataReader Reader { get { return _reader; } } + public ScopeDefinitionHandle Handle { get { return _handle; } } + public ScopeDefinition ScopeDefinition + { + get + { + return _handle.GetScopeDefinition(_reader); + } + } + + public override bool Equals(Object obj) + { + if (!(obj is QScopeDefinition)) + return false; + return Equals((QScopeDefinition)obj); + } + + public bool Equals(QScopeDefinition other) + { + if (!(this._reader == other._reader)) + return false; + if (!(this._handle.Equals(other._handle))) + return false; + return true; + } + + public override int GetHashCode() + { + return _handle.GetHashCode(); + } + + private MetadataReader _reader; + private ScopeDefinitionHandle _handle; + } +} + +namespace System.Reflection.Runtime.General +{ + internal struct QHandle : IEquatable<QHandle> + { + public QHandle(MetadataReader reader, Handle handle) + { + _reader = reader; + _handle = handle; + } + + public MetadataReader Reader { get { return _reader; } } + public Handle Handle { get { return _handle; } } + + public override bool Equals(Object obj) + { + if (!(obj is QHandle)) + return false; + return Equals((QHandle)obj); + } + + public bool Equals(QHandle other) + { + if (!(this._reader == other._reader)) + return false; + if (!(this._handle.Equals(other._handle))) + return false; + return true; + } + + public override int GetHashCode() + { + return _handle.GetHashCode(); + } + + private MetadataReader _reader; + private Handle _handle; + } + + + internal struct QTypeDefinition : IEquatable<QTypeDefinition> + { + public QTypeDefinition(MetadataReader reader, TypeDefinitionHandle handle) + { + _reader = reader; + _handle = handle; + } + + public MetadataReader Reader { get { return _reader; } } + public TypeDefinitionHandle Handle { get { return _handle; } } + + public override bool Equals(Object obj) + { + if (!(obj is QTypeDefinition)) + return false; + return Equals((QTypeDefinition)obj); + } + + public bool Equals(QTypeDefinition other) + { + if (!(this._reader == other._reader)) + return false; + if (!(this._handle.Equals(other._handle))) + return false; + return true; + } + + public override int GetHashCode() + { + return _handle.GetHashCode(); + } + + private MetadataReader _reader; + private TypeDefinitionHandle _handle; + } + + + internal struct QTypeDefRefOrSpec + { + public QTypeDefRefOrSpec(MetadataReader reader, Handle handle, bool skipCheck = false) + { + if (!skipCheck) + { + if (!handle.IsTypeDefRefOrSpecHandle(reader)) + throw new BadImageFormatException(); + } + Debug.Assert(handle.IsTypeDefRefOrSpecHandle(reader)); + _reader = reader; + _handle = handle; + } + + public MetadataReader Reader { get { return _reader; } } + public Handle Handle { get { return _handle; } } + + public static readonly QTypeDefRefOrSpec Null = default(QTypeDefRefOrSpec); + + private MetadataReader _reader; + private Handle _handle; + } + + internal struct QGenericParameter : IEquatable<QGenericParameter> + { + public QGenericParameter(MetadataReader reader, GenericParameterHandle handle) + { + _reader = reader; + _handle = handle; + } + + public MetadataReader Reader { get { return _reader; } } + public GenericParameterHandle Handle { get { return _handle; } } + + public override bool Equals(Object obj) + { + if (!(obj is QGenericParameter)) + return false; + return Equals((QGenericParameter)obj); + } + + public bool Equals(QGenericParameter other) + { + if (!(this._reader == other._reader)) + return false; + if (!(this._handle.Equals(other._handle))) + return false; + return true; + } + + public override int GetHashCode() + { + return _handle.GetHashCode(); + } + + private MetadataReader _reader; + private GenericParameterHandle _handle; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs new file mode 100644 index 000000000..4b9b33e6e --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ReflectionCoreCallbacksImplementation.cs @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.FieldInfos; +using global::System.Reflection.Runtime.MethodInfos; + +using global::Internal.Reflection.Augments; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + internal sealed class ReflectionCoreCallbacksImplementation : ReflectionCoreCallbacks + { + internal ReflectionCoreCallbacksImplementation() + { + } + + public sealed override TypeInfo GetTypeInfo(Type type) + { + RuntimeType runtimeType = type as RuntimeType; + if (runtimeType != null) + return runtimeType.GetRuntimeTypeInfo(); + IReflectableType reflectableType = type as IReflectableType; + if (reflectableType != null) + return reflectableType.GetTypeInfo(); + + throw runtimeType.GetReflectionDomain().CreateMissingMetadataException(type); + } + + public sealed override Assembly Load(AssemblyName refName) + { + if (refName == null) + throw new ArgumentNullException("assemblyRef"); + return RuntimeAssembly.GetRuntimeAssembly(ReflectionCoreExecution.ExecutionDomain, refName.ToRuntimeAssemblyName()); + } + + // + // This overload of GetMethodForHandle only accepts handles for methods declared on non-generic types (the method, however, + // can be an instance of a generic method.) To resolve handles for methods declared on generic types, you must pass + // the declaring type explicitly using the two-argument overload of GetMethodFromHandle. + // + // This is a vestige from desktop generic sharing that got itself enshrined in the code generated by the C# compiler for Linq Expressions. + // + public sealed override MethodBase GetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle) + { + ExecutionEnvironment executionEnvironment = ReflectionCoreExecution.ExecutionEnvironment; + MethodHandle methodHandle; + RuntimeTypeHandle declaringTypeHandle; + RuntimeTypeHandle[] genericMethodTypeArgumentHandles; + if (!executionEnvironment.TryGetMethodFromHandle(runtimeMethodHandle, out declaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles)) + throw new ArgumentException(SR.Argument_InvalidHandle); + + MethodBase methodBase = ReflectionCoreExecution.ExecutionDomain.GetMethod(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles); + if (methodBase.DeclaringType.IsConstructedGenericType) // For compat with desktop, insist that the caller pass us the declaring type to resolve members of generic types. + throw new ArgumentException(SR.Format(SR.Argument_MethodDeclaringTypeGeneric, methodBase)); + return methodBase; + } + + // + // This overload of GetMethodHandle can handle all method handles. + // + public sealed override MethodBase GetMethodFromHandle(RuntimeMethodHandle runtimeMethodHandle, RuntimeTypeHandle declaringTypeHandle) + { + ExecutionEnvironment executionEnvironment = ReflectionCoreExecution.ExecutionEnvironment; + MethodHandle methodHandle; + RuntimeTypeHandle[] genericMethodTypeArgumentHandles; + if (!executionEnvironment.TryGetMethodFromHandleAndType(runtimeMethodHandle, declaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles)) + { + // This may be a method declared on a non-generic type: this api accepts that too so try the other table. + RuntimeTypeHandle actualDeclaringTypeHandle; + if (!executionEnvironment.TryGetMethodFromHandle(runtimeMethodHandle, out actualDeclaringTypeHandle, out methodHandle, out genericMethodTypeArgumentHandles)) + throw new ArgumentException(SR.Argument_InvalidHandle); + if (!actualDeclaringTypeHandle.Equals(declaringTypeHandle)) + throw new ArgumentException(SR.Format(SR.Argument_ResolveMethodHandle, + ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(declaringTypeHandle), + ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(actualDeclaringTypeHandle))); + } + + MethodBase methodBase = ReflectionCoreExecution.ExecutionDomain.GetMethod(declaringTypeHandle, methodHandle, genericMethodTypeArgumentHandles); + return methodBase; + } + + // + // This overload of GetFieldForHandle only accepts handles for fields declared on non-generic types. To resolve handles for fields + // declared on generic types, you must pass the declaring type explicitly using the two-argument overload of GetFieldFromHandle. + // + // This is a vestige from desktop generic sharing that got itself enshrined in the code generated by the C# compiler for Linq Expressions. + // + public sealed override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle) + { + ExecutionEnvironment executionEnvironment = ReflectionCoreExecution.ExecutionEnvironment; + FieldHandle fieldHandle; + RuntimeTypeHandle declaringTypeHandle; + if (!executionEnvironment.TryGetFieldFromHandle(runtimeFieldHandle, out declaringTypeHandle, out fieldHandle)) + throw new ArgumentException(SR.Argument_InvalidHandle); + + FieldInfo fieldInfo = GetFieldInfo(declaringTypeHandle, fieldHandle); + if (fieldInfo.DeclaringType.IsConstructedGenericType) // For compat with desktop, insist that the caller pass us the declaring type to resolve members of generic types. + throw new ArgumentException(SR.Format(SR.Argument_FieldDeclaringTypeGeneric, fieldInfo)); + return fieldInfo; + } + + // + // This overload of GetFieldHandle can handle all field handles. + // + public sealed override FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle, RuntimeTypeHandle declaringTypeHandle) + { + ExecutionEnvironment executionEnvironment = ReflectionCoreExecution.ExecutionEnvironment; + FieldHandle fieldHandle; + if (!executionEnvironment.TryGetFieldFromHandleAndType(runtimeFieldHandle, declaringTypeHandle, out fieldHandle)) + { + // This may be a field declared on a non-generic type: this api accepts that too so try the other table. + RuntimeTypeHandle actualDeclaringTypeHandle; + if (!executionEnvironment.TryGetFieldFromHandle(runtimeFieldHandle, out actualDeclaringTypeHandle, out fieldHandle)) + throw new ArgumentException(SR.Argument_InvalidHandle); + if (!actualDeclaringTypeHandle.Equals(declaringTypeHandle)) + throw new ArgumentException(SR.Format(SR.Argument_ResolveFieldHandle, + ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(declaringTypeHandle), + ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(actualDeclaringTypeHandle))); + } + + FieldInfo fieldInfo = GetFieldInfo(declaringTypeHandle, fieldHandle); + return fieldInfo; + } + + public sealed override void InitializeAssemblyName(AssemblyName blank, String fullName) + { + RuntimeAssemblyName runtimeAssemblyName = AssemblyNameParser.Parse(fullName); + runtimeAssemblyName.CopyToAssemblyName(blank); + } + + public sealed override String ComputeAssemblyNameFullName(AssemblyName assemblyName) + { + return AssemblyNameHelpers.ComputeDisplayName(assemblyName.ToRuntimeAssemblyName()); + } + + public sealed override byte[] ComputePublicKeyToken(byte[] publicKey) + { + return AssemblyNameHelpers.ComputePublicKeyToken(publicKey); + } + + private FieldInfo GetFieldInfo(RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle) + { + RuntimeType declaringType = ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(declaringTypeHandle); + RuntimeTypeInfo contextTypeInfo = declaringType.GetRuntimeTypeInfo(); + RuntimeNamedTypeInfo definingTypeInfo = contextTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + MetadataReader reader = definingTypeInfo.Reader; + return RuntimeFieldInfo.GetRuntimeFieldInfo(fieldHandle, definingTypeInfo, contextTypeInfo); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeNamespaceInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeNamespaceInfo.cs new file mode 100644 index 000000000..27f703ebf --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeNamespaceInfo.cs @@ -0,0 +1,3 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeExtensions.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeExtensions.cs new file mode 100644 index 000000000..4d2735cd0 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeExtensions.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Reflection.Runtime.TypeInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.General +{ + internal static class RuntimeTypeExtensions + { + public static RuntimeTypeInfo GetRuntimeTypeInfo(this RuntimeType runtimeType) + { + return RuntimeTypeInfo.GetRuntimeTypeInfo(runtimeType); + } + + public static RUNTIMETYPEINFO GetRuntimeTypeInfo<RUNTIMETYPEINFO>(this Type type) + where RUNTIMETYPEINFO : RuntimeTypeInfo + { + Debug.Assert(type is RuntimeType); + return (RUNTIMETYPEINFO)(type.GetTypeInfo()); + } + + public static ReflectionDomain GetReflectionDomain(this RuntimeType runtimeType) + { + return ReflectionCoreExecution.ExecutionDomain; //@todo: User Reflection Domains not yet supported. + } + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeUnifierEx.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeUnifierEx.cs new file mode 100644 index 000000000..5c9961100 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/RuntimeTypeUnifierEx.cs @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Collections.Generic; +using global::System.Collections.Concurrent; +using global::System.Runtime.CompilerServices; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + // + // ! If you change this policy to not unify all instances, you must change the implementation of Equals/GetHashCode in the runtime type classes. + // + // The RuntimeTypeUnifier and its companion RuntimeTypeUnifierEx maintains a record of all System.Type objects + // created by the runtime. The split into two classes is an artifact of reflection being implemented partly in System.Private.CoreLib and + // partly in S.R.R. + // + // Though the present incarnation enforces the "one instance per semantic identity rule", its surface area is also designed + // to be able to switch to a non-unified model if desired. + // + // ! If you do switch away from a "one instance per semantic identity rule", you must also change the implementation + // ! of RuntimeType.Equals() and RuntimeType.GetHashCode(). + // + + internal static class RuntimeTypeUnifierEx + { + // + // Retrieves the unified Type object for a named type that has metadata associated with it. + // + public static RuntimeType GetNamedType(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle) + { + return TypeTableForNamedTypes.Table.GetOrAdd(new QTypeDefinition(reader, typeDefinitionHandle)).WithDebugName(); + } + + // + // Type table for all named types that have metadata associated with it. + // + private sealed class TypeTableForNamedTypes : ConcurrentUnifierW<QTypeDefinition, RuntimeType> + { + private TypeTableForNamedTypes() { } + + protected sealed override RuntimeType Factory(QTypeDefinition qTypeDefinition) + { + RuntimeTypeHandle runtimeTypeHandle; + if (ReflectionCoreExecution.ExecutionEnvironment.TryGetNamedTypeForMetadata(qTypeDefinition.Reader, qTypeDefinition.Handle, out runtimeTypeHandle)) + return ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(runtimeTypeHandle); + else + return RuntimeInspectionOnlyNamedType.GetRuntimeInspectionOnlyNamedType(qTypeDefinition.Reader, qTypeDefinition.Handle); + } + + public static TypeTableForNamedTypes Table = new TypeTableForNamedTypes(); + } + + + + // + // Retrieves the unified Type object for a generic type parameter type. + // + internal static RuntimeType GetRuntimeGenericParameterTypeForTypes(RuntimeNamedTypeInfo typeOwner, GenericParameterHandle genericParameterHandle) + { + RuntimeGenericParameterTypeForTypes.UnificationKey key = new RuntimeGenericParameterTypeForTypes.UnificationKey(typeOwner.Reader, typeOwner.TypeDefinitionHandle, genericParameterHandle); + return GenericParameterTypeForTypesTable.Table.GetOrAdd(key).WithDebugName(); + } + + private sealed class GenericParameterTypeForTypesTable : ConcurrentUnifierW<RuntimeGenericParameterTypeForTypes.UnificationKey, RuntimeGenericParameterTypeForTypes> + { + protected sealed override RuntimeGenericParameterTypeForTypes Factory(RuntimeGenericParameterTypeForTypes.UnificationKey key) + { + RuntimeNamedTypeInfo typeOwner = RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(key.Reader, key.TypeDefinitionHandle); + return new RuntimeGenericParameterTypeForTypes(key.Reader, key.GenericParameterHandle, typeOwner); + } + + public static GenericParameterTypeForTypesTable Table = new GenericParameterTypeForTypesTable(); + } + + + // + // Retrieves the unified Type object for a generic method parameter type. + // + internal static RuntimeGenericParameterTypeForMethods GetRuntimeGenericParameterTypeForMethods(RuntimeNamedMethodInfo methodOwner, MetadataReader reader, GenericParameterHandle genericParameterHandle) + { + RuntimeGenericParameterTypeForMethods.UnificationKey key = new RuntimeGenericParameterTypeForMethods.UnificationKey(methodOwner, reader, genericParameterHandle); + return GenericParameterTypeForMethodsTable.Table.GetOrAdd(key); + } + + private sealed class GenericParameterTypeForMethodsTable : ConcurrentUnifierWKeyed<RuntimeGenericParameterTypeForMethods.UnificationKey, RuntimeGenericParameterTypeForMethods> + { + protected sealed override RuntimeGenericParameterTypeForMethods Factory(RuntimeGenericParameterTypeForMethods.UnificationKey key) + { + return new RuntimeGenericParameterTypeForMethods(key.Reader, key.GenericParameterHandle, key.MethodOwner); + } + + public static GenericParameterTypeForMethodsTable Table = new GenericParameterTypeForMethodsTable(); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static RuntimeType WithDebugName(this RuntimeType runtimeType) + { +#if DEBUG + if (runtimeType != null) + runtimeType.EstablishDebugName(); +#endif + return runtimeType; + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs new file mode 100644 index 000000000..42e70b21c --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ToStringUtils.cs @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.TypeParsing; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + internal static class ToStringUtils + { + // + // This is a port of the desktop CLR's RuntimeType.FormatTypeName() routine. This routine is used by various Reflection ToString() methods + // to display the name of a type. Do not use for any other purpose as it inherits some pretty quirky desktop behavior. + // + // The Project N version takes a raw metadata handle rather than a completed type so that it remains robust in the face of missing metadata. + // + public static String FormatTypeName(this Handle typeDefRefOrSpecHandle, MetadataReader reader, TypeContext typeContext, ReflectionDomain reflectionDomain) + { + try + { + // Though we wrap this in a try-catch as a failsafe, this code must still strive to avoid triggering MissingMetadata exceptions + // (non-error exceptions are very annoying when debugging.) + + Exception exception = null; + RuntimeType runtimeType = reflectionDomain.TryResolve(reader, typeDefRefOrSpecHandle, typeContext, ref exception); + if (runtimeType == null) + return UnavailableType; + + // Because this runtimeType came from a successful TryResolve() call, it is safe to querying the TypeInfo's of the type and its component parts. + // If we're wrong, we do have the safety net of a try-catch. + return runtimeType.FormatTypeName(); + } + catch (Exception) + { + return UnavailableType; + } + } + + // + // This is a port of the desktop CLR's RuntimeType.FormatTypeName() routine. This routine is used by various Reflection ToString() methods + // to display the name of a type. Do not use for any other purpose as it inherits some pretty quirky desktop behavior. + // + // The Project N version takes a raw metadata handle rather than a completed type so that it remains robust in the face of missing metadata. + // + public static String FormatTypeName(this RuntimeType runtimeType) + { + try + { + // Though we wrap this in a try-catch as a failsafe, this code must still strive to avoid triggering MissingMetadata exceptions + // (non-error exceptions are very annoying when debugging.) + + ReflectionDomain reflectionDomain = runtimeType.GetReflectionDomain(); + + // Legacy: this doesn't make sense, why use only Name for nested types but otherwise + // ToString() which contains namespace. + RuntimeType rootElementType = runtimeType; + while (rootElementType.HasElementType) + rootElementType = rootElementType.InternalRuntimeElementType; + if (rootElementType.IsNested) + { + String name = runtimeType.InternalNameIfAvailable; + return name == null ? UnavailableType : name; + } + + // Legacy: why removing "System"? Is it just because C# has keywords for these types? + // If so why don't we change it to lower case to match the C# keyword casing? + FoundationTypes foundationTypes = reflectionDomain.FoundationTypes; + String typeName = runtimeType.ToString(); + if (typeName.StartsWith("System.")) + { + foreach (Type pt in reflectionDomain.PrimitiveTypes) + { + if (pt.Equals(rootElementType) || rootElementType.Equals(foundationTypes.SystemVoid)) + { + typeName = typeName.Substring("System.".Length); + break; + } + } + } + return typeName; + } + catch (Exception) + { + return UnavailableType; + } + } + + public const String UnavailableType = "UnknownType"; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeContext.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeContext.cs new file mode 100644 index 000000000..00ef752c5 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeContext.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.General +{ + // + // Passed as an argument to code that parses signatures or typespecs. Specifies the subsitution values for ET_VAR and ET_MVAR elements inside the signature. + // Both may be null if no generic parameters are expected. + // + + internal struct TypeContext + { + internal TypeContext(RuntimeType[] genericTypeArguments, RuntimeType[] genericMethodArguments) + { + _genericTypeArguments = genericTypeArguments; + _genericMethodArguments = genericMethodArguments; + } + + internal RuntimeType[] GenericTypeArguments + { + get + { + return _genericTypeArguments; + } + } + + internal RuntimeType[] GenericMethodArguments + { + get + { + return _genericMethodArguments; + } + } + + private RuntimeType[] _genericTypeArguments; + private RuntimeType[] _genericMethodArguments; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeExtensions.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeExtensions.cs new file mode 100644 index 000000000..2a7af61ba --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeExtensions.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.General +{ + internal static class TypeExtensions + { + public static RuntimeType AsConfirmedRuntimeType(this Type type) + { + RuntimeType runtimeType = type as RuntimeType; + if (runtimeType == null) + throw new InvalidOperationException(); + return runtimeType; + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs new file mode 100644 index 000000000..ed78c1219 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/TypeResolver.cs @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.TypeParsing; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.General +{ + internal static class TypeResolver + { + // + // Main routine to resolve a typeDef/Ref/Spec. + // + internal static RuntimeType Resolve(this ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeDefRefOrSpec, TypeContext typeContext) + { + Exception exception = null; + RuntimeType runtimeType = reflectionDomain.TryResolve(reader, typeDefRefOrSpec, typeContext, ref exception); + if (runtimeType == null) + throw exception; + return runtimeType; + } + + internal static RuntimeType TryResolve(this ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeDefRefOrSpec, TypeContext typeContext, ref Exception exception) + { + HandleType handleType = typeDefRefOrSpec.HandleType; + if (handleType == HandleType.TypeDefinition) + return reflectionDomain.ResolveTypeDefinition(reader, typeDefRefOrSpec.ToTypeDefinitionHandle(reader)); + else if (handleType == HandleType.TypeReference) + return reflectionDomain.TryResolveTypeReference(reader, typeDefRefOrSpec.ToTypeReferenceHandle(reader), ref exception); + else if (handleType == HandleType.TypeSpecification) + return reflectionDomain.TryResolveTypeSignature(reader, typeDefRefOrSpec.ToTypeSpecificationHandle(reader), typeContext, ref exception); + else + throw new BadImageFormatException(); // Expected TypeRef, Def or Spec. + } + + + // + // Main routine to resolve a typeDefinition. + // + internal static RuntimeType ResolveTypeDefinition(this ReflectionDomain reflectionDomain, MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle) + { + return RuntimeTypeUnifierEx.GetNamedType(reader, typeDefinitionHandle); + } + + // + // Main routine to parse a metadata type specification signature. + // + private static RuntimeType TryResolveTypeSignature(this ReflectionDomain reflectionDomain, MetadataReader reader, TypeSpecificationHandle typeSpecHandle, TypeContext typeContext, ref Exception exception) + { + Handle typeHandle = typeSpecHandle.GetTypeSpecification(reader).Signature; + switch (typeHandle.HandleType) + { + case HandleType.ArraySignature: + { + ArraySignature sig = typeHandle.ToArraySignatureHandle(reader).GetArraySignature(reader); + int rank = sig.Rank; + if (rank <= 0) + throw new BadImageFormatException(); // Bad rank. + RuntimeType elementType = reflectionDomain.TryResolve(reader, sig.ElementType, typeContext, ref exception); + if (elementType == null) + return null; + return ReflectionCoreNonPortable.GetMultiDimArrayType(elementType, rank); + } + + case HandleType.ByReferenceSignature: + { + ByReferenceSignature sig = typeHandle.ToByReferenceSignatureHandle(reader).GetByReferenceSignature(reader); + RuntimeType targetType = reflectionDomain.TryResolve(reader, sig.Type, typeContext, ref exception); + if (targetType == null) + return null; + return ReflectionCoreNonPortable.GetByRefType(targetType); + } + + case HandleType.MethodTypeVariableSignature: + { + MethodTypeVariableSignature sig = typeHandle.ToMethodTypeVariableSignatureHandle(reader).GetMethodTypeVariableSignature(reader); + return typeContext.GenericMethodArguments[sig.Number]; + } + + case HandleType.PointerSignature: + { + PointerSignature sig = typeHandle.ToPointerSignatureHandle(reader).GetPointerSignature(reader); + RuntimeType targetType = reflectionDomain.TryResolve(reader, sig.Type, typeContext, ref exception); + if (targetType == null) + return null; + return ReflectionCoreNonPortable.GetPointerType(targetType); + } + + case HandleType.SZArraySignature: + { + SZArraySignature sig = typeHandle.ToSZArraySignatureHandle(reader).GetSZArraySignature(reader); + RuntimeType elementType = reflectionDomain.TryResolve(reader, sig.ElementType, typeContext, ref exception); + if (elementType == null) + return null; + return ReflectionCoreNonPortable.GetArrayType(elementType); + } + + case HandleType.TypeDefinition: + { + return reflectionDomain.ResolveTypeDefinition(reader, typeHandle.ToTypeDefinitionHandle(reader)); + } + + case HandleType.TypeInstantiationSignature: + { + TypeInstantiationSignature sig = typeHandle.ToTypeInstantiationSignatureHandle(reader).GetTypeInstantiationSignature(reader); + RuntimeType genericTypeDefinition = reflectionDomain.TryResolve(reader, sig.GenericType, typeContext, ref exception); + if (genericTypeDefinition == null) + return null; + LowLevelList<RuntimeType> genericTypeArguments = new LowLevelList<RuntimeType>(); + foreach (Handle genericTypeArgumentHandle in sig.GenericTypeArguments) + { + RuntimeType genericTypeArgument = reflectionDomain.TryResolve(reader, genericTypeArgumentHandle, typeContext, ref exception); + if (genericTypeArgument == null) + return null; + genericTypeArguments.Add(genericTypeArgument); + } + return ReflectionCoreNonPortable.GetConstructedGenericType(genericTypeDefinition, genericTypeArguments.ToArray()); + } + + case HandleType.TypeReference: + { + return reflectionDomain.TryResolveTypeReference(reader, typeHandle.ToTypeReferenceHandle(reader), ref exception); + } + + case HandleType.TypeVariableSignature: + { + TypeVariableSignature sig = typeHandle.ToTypeVariableSignatureHandle(reader).GetTypeVariableSignature(reader); + return typeContext.GenericTypeArguments[sig.Number]; + } + + default: + throw new NotSupportedException(); // Unexpected Type signature type. + } + } + + // + // Main routine to resolve a typeReference. + // + private static RuntimeType TryResolveTypeReference(this ReflectionDomain reflectionDomain, MetadataReader reader, TypeReferenceHandle typeReferenceHandle, ref Exception exception) + { + { + ExecutionDomain executionDomain = reflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + RuntimeTypeHandle resolvedRuntimeTypeHandle; + if (executionDomain.ExecutionEnvironment.TryGetNamedTypeForTypeReference(reader, typeReferenceHandle, out resolvedRuntimeTypeHandle)) + return ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(resolvedRuntimeTypeHandle); + } + } + + TypeReference typeReference = typeReferenceHandle.GetTypeReference(reader); + String name = typeReference.TypeName.GetString(reader); + Handle parent = typeReference.ParentNamespaceOrType; + HandleType parentType = parent.HandleType; + TypeInfo outerTypeInfo = null; + + // Check if this is a reference to a nested type. + + if (parentType == HandleType.TypeDefinition) + { + outerTypeInfo = RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(reader, parent.ToTypeDefinitionHandle(reader)); + } + else if (parentType == HandleType.TypeReference) + { + RuntimeType outerType = reflectionDomain.TryResolveTypeReference(reader, parent.ToTypeReferenceHandle(reader), ref exception); + if (outerType == null) + return null; + outerTypeInfo = outerType.GetTypeInfo(); // Since we got to outerType via a metadata reference, we're assured GetTypeInfo() won't throw a MissingMetadataException. + } + if (outerTypeInfo != null) + { + // It was a nested type. We've already resolved the containing type recursively - just find the nested among its direct children. + TypeInfo resolvedTypeInfo = outerTypeInfo.GetDeclaredNestedType(name); + if (resolvedTypeInfo == null) + { + exception = reflectionDomain.CreateMissingMetadataException(outerTypeInfo, name); + return null; + } + return (RuntimeType)(resolvedTypeInfo.AsType()); + } + + + // If we got here, the typeReference was to a non-nested type. + if (parentType == HandleType.NamespaceReference) + { + AssemblyQualifiedTypeName assemblyQualifiedTypeName = parent.ToNamespaceReferenceHandle(reader).ToAssemblyQualifiedTypeName(name, reader); + RuntimeType runtimeType; + exception = assemblyQualifiedTypeName.TryResolve(reflectionDomain, null, /*ignoreCase: */false, out runtimeType); + if (exception != null) + return null; + return runtimeType; + } + + throw new BadImageFormatException(); // Expected TypeReference parent to be typeRef, typeDef or namespaceRef. + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs new file mode 100644 index 000000000..42215e92b --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/OpenMethodInvoker.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + internal sealed class OpenMethodInvoker : MethodInvoker + { + public sealed override Object Invoke(Object thisObject, Object[] arguments) + { + throw new InvalidOperationException(SR.Arg_UnboundGenParam); + } + + public sealed override Delegate CreateDelegate(RuntimeTypeHandle delegateType, Object target, bool isStatic, bool isVirtual, bool isOpen) + { + throw new InvalidOperationException(SR.Arg_UnboundGenParam); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs new file mode 100644 index 000000000..705469dd8 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // The runtime's implementation of non-constructor MethodInfo's that represent an open or closed costruction of a generic method. + // + internal sealed partial class RuntimeConstructedGenericMethodInfo : RuntimeMethodInfo + { + private RuntimeConstructedGenericMethodInfo(RuntimeNamedMethodInfo genericMethodDefinition, RuntimeType[] genericTypeArguments) + { + _genericMethodDefinition = genericMethodDefinition; + _genericTypeArguments = genericTypeArguments; + } + + public sealed override MethodAttributes Attributes + { + get + { + return _genericMethodDefinition.Attributes; + } + } + + public sealed override CallingConventions CallingConvention + { + get + { + return _genericMethodDefinition.CallingConvention; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return _genericMethodDefinition.CustomAttributes; + } + } + + public sealed override bool Equals(Object obj) + { + RuntimeConstructedGenericMethodInfo other = obj as RuntimeConstructedGenericMethodInfo; + if (other == null) + return false; + if (!this._genericMethodDefinition.Equals(other._genericMethodDefinition)) + return false; + if (this._genericTypeArguments.Length != other._genericTypeArguments.Length) + return false; + for (int i = 0; i < _genericTypeArguments.Length; i++) + { + if (!this._genericTypeArguments[i].Equals(other._genericTypeArguments[i])) + return false; + } + return true; + } + + public sealed override int GetHashCode() + { + return _genericMethodDefinition.GetHashCode(); + } + + public sealed override MethodInfo GetGenericMethodDefinition() + { + return _genericMethodDefinition; + } + + public sealed override bool IsGenericMethod + { + get + { + return true; + } + } + + public sealed override bool IsGenericMethodDefinition + { + get + { + return false; + } + } + + public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) + { + throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this)); + } + + public sealed override MethodImplAttributes MethodImplementationFlags + { + get + { + return _genericMethodDefinition.MethodImplementationFlags; + } + } + + public sealed override Module Module + { + get + { + return _genericMethodDefinition.Module; + } + } + + public sealed override String ToString() + { + return _genericMethodDefinition.ComputeToString(this); + } + + protected sealed override MethodInvoker UncachedMethodInvoker + { + get + { + return ReflectionCoreExecution.ExecutionEnvironment.GetMethodInvoker( + _genericMethodDefinition.Reader, + _genericMethodDefinition.RuntimeDeclaringType, + _genericMethodDefinition.MethodHandle, + _genericTypeArguments, + this); + } + } + + internal sealed override RuntimeType RuntimeDeclaringType + { + get + { + return _genericMethodDefinition.RuntimeDeclaringType; + } + } + + internal sealed override RuntimeType[] RuntimeGenericArgumentsOrParameters + { + get + { + return _genericTypeArguments; + } + } + + internal sealed override String RuntimeName + { + get + { + return _genericMethodDefinition.RuntimeName; + } + } + + internal sealed override RuntimeParameterInfo[] GetRuntimeParametersAndReturn(RuntimeMethodInfo contextMethod) + { + return _genericMethodDefinition.GetRuntimeParametersAndReturn(this); + } + + private RuntimeNamedMethodInfo _genericMethodDefinition; + private RuntimeType[] _genericTypeArguments; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs new file mode 100644 index 000000000..34d42d94f --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Tracing; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // The runtime's implementation of ConstructorInfo. + // + internal abstract partial class RuntimeConstructorInfo : ExtensibleConstructorInfo + { + public abstract override MethodAttributes Attributes { get; } + + public abstract override CallingConventions CallingConvention { get; } + + public sealed override bool ContainsGenericParameters + { + get + { + return DeclaringType.GetTypeInfo().ContainsGenericParameters; + } + } + + public abstract override IEnumerable<CustomAttributeData> CustomAttributes { get; } + + public abstract override Type DeclaringType { get; } + + public sealed override Type[] GetGenericArguments() + { + // Constructors cannot be generic. Desktop compat dictates that We throw NotSupported rather than returning a 0-length array. + throw new NotSupportedException(); + } + + public sealed override ParameterInfo[] GetParameters() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_GetParameters(this); + + RuntimeParameterInfo[] runtimeParametersAndReturn = this.RuntimeParametersAndReturn; + if (runtimeParametersAndReturn.Length == 1) + return Array.Empty<ParameterInfo>(); + ParameterInfo[] result = new ParameterInfo[runtimeParametersAndReturn.Length - 1]; + for (int i = 0; i < result.Length; i++) + result[i] = runtimeParametersAndReturn[i + 1]; + return result; + } + + public abstract override Object Invoke(Object[] parameters); + + public sealed override Object Invoke(Object obj, Object[] parameters) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_Invoke(this, obj, parameters); + + if (parameters == null) + parameters = Array.Empty<Object>(); + MethodInvoker methodInvoker; + try + { + methodInvoker = this.MethodInvoker; + } + catch (Exception) + { + // + // Project N compat note: On the desktop, ConstructorInfo.Invoke(Object[]) specifically forbids invoking static constructors (and + // for us, that check is embedded inside the MethodInvoker property call.) Howver, MethodBase.Invoke(Object, Object[]) allows it. This was + // probably an oversight on the desktop. We choose not to support this loophole on Project N for the following reasons: + // + // 1. The Project N toolchain aggressively replaces static constructors with static initialization data whenever possible. + // So the static constructor may no longer exist. + // + // 2. Invoking the static constructor through Reflection is not very useful as it invokes the static constructor whether or not + // it was already run. Since static constructors are specifically one-shot deals, this will almost certainly mess up the + // type's internal assumptions. + // + + if (this.IsStatic) + throw new PlatformNotSupportedException(SR.Acc_NotClassInit); + throw; + } + + return methodInvoker.Invoke(obj, parameters); + } + + public sealed override Module Module + { + get + { + return DeclaringType.GetTypeInfo().Module; + } + } + + public sealed override bool IsGenericMethod + { + get + { + return false; + } + } + + public sealed override bool IsGenericMethodDefinition + { + get + { + return false; + } + } + + public abstract override MethodImplAttributes MethodImplementationFlags { get; } + + public abstract override String Name { get; } + + public abstract override bool Equals(Object obj); + + public abstract override int GetHashCode(); + + public abstract override String ToString(); + + protected MethodInvoker MethodInvoker + { + get + { + if (_lazyMethodInvoker == null) + { + _lazyMethodInvoker = UncachedMethodInvoker; + } + return _lazyMethodInvoker; + } + } + + protected abstract RuntimeParameterInfo[] RuntimeParametersAndReturn { get; } + + protected abstract MethodInvoker UncachedMethodInvoker { get; } + + private volatile MethodInvoker _lazyMethodInvoker = null; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodCommon.cs new file mode 100644 index 000000000..97b67f77c --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodCommon.cs @@ -0,0 +1,308 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Text; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // Implements methods and properties common to RuntimeMethodInfo and RuntimeConstructorInfo. In a sensible world, this + // struct would be a common base class for RuntimeMethodInfo and RuntimeConstructorInfo. But those types are forced + // to derive from MethodInfo and ConstructorInfo because of the way the Reflection API are designed. Hence, + // we use containment as a substitute. + // + internal struct RuntimeMethodCommon + { + // + // methodHandle - the "tkMethodDef" that identifies the method. + // definingType - the "tkTypeDef" that defined the method (this is where you get the metadata reader that created methodHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + public RuntimeMethodCommon(MethodHandle methodHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + _definingTypeInfo = definingTypeInfo; + _methodHandle = methodHandle; + _contextTypeInfo = contextTypeInfo; + _reader = definingTypeInfo.Reader; + _method = methodHandle.GetMethod(_reader); + } + + public MethodAttributes Attributes + { + get + { + return _method.Flags; + } + } + + public CallingConventions CallingConvention + { + get + { + return MethodSignature.CallingConvention; + } + } + + // Compute the ToString() value in a pay-to-play-safe way. + public String ComputeToString(MethodBase contextMethod, RuntimeType[] methodTypeArguments) + { + RuntimeParameterInfo[] runtimeParametersAndReturn = this.GetRuntimeParametersAndReturn(contextMethod, methodTypeArguments); + return ComputeToString(contextMethod, methodTypeArguments, runtimeParametersAndReturn); + } + + + public static String ComputeToString(MethodBase contextMethod, RuntimeType[] methodTypeArguments, RuntimeParameterInfo[] runtimeParametersAndReturn) + { + StringBuilder sb = new StringBuilder(30); + sb.Append(runtimeParametersAndReturn[0].ParameterTypeString); + sb.Append(' '); + sb.Append(contextMethod.Name); + if (methodTypeArguments.Length != 0) + { + String sep = ""; + sb.Append('['); + foreach (RuntimeType methodTypeArgument in methodTypeArguments) + { + sb.Append(sep); + sep = ","; + String name = methodTypeArgument.InternalNameIfAvailable; + if (name == null) + name = ToStringUtils.UnavailableType; + sb.Append(methodTypeArgument.Name); + } + sb.Append(']'); + } + sb.Append('('); + sb.Append(ComputeParametersString(runtimeParametersAndReturn, 1)); + sb.Append(')'); + + return sb.ToString(); + } + + // Used by method and property ToString() methods to display the list of parameter types. Replicates the behavior of MethodBase.ConstructParameters() + // but in a pay-to-play-safe way. + public static String ComputeParametersString(RuntimeParameterInfo[] runtimeParametersAndReturn, int startIndex) + { + StringBuilder sb = new StringBuilder(30); + for (int i = startIndex; i < runtimeParametersAndReturn.Length; i++) + { + if (i != startIndex) + sb.Append(", "); + String parameterTypeString = runtimeParametersAndReturn[i].ParameterTypeString; + + // Legacy: Why use "ByRef" for by ref parameters? What language is this? + // VB uses "ByRef" but it should precede (not follow) the parameter name. + // Why don't we just use "&"? + if (parameterTypeString.EndsWith("&")) + parameterTypeString = parameterTypeString.Substring(0, parameterTypeString.Length - 1) + " ByRef"; + sb.Append(parameterTypeString); + } + return sb.ToString(); + } + + public RuntimeTypeInfo ContextTypeInfo + { + get + { + return _contextTypeInfo; + } + } + + public IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + IEnumerable<CustomAttributeData> customAttributes = RuntimeCustomAttributeData.GetCustomAttributes(_definingTypeInfo.ReflectionDomain, _reader, _method.CustomAttributes); + foreach (CustomAttributeData cad in customAttributes) + yield return cad; + ExecutionDomain executionDomain = this.DefiningTypeInfo.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(_reader, _methodHandle, _definingTypeInfo.TypeDefinitionHandle)) + yield return cad; + } + } + } + + public RuntimeType DeclaringType + { + get + { + return _contextTypeInfo.RuntimeType; + } + } + + public RuntimeNamedTypeInfo DefiningTypeInfo + { + get + { + return _definingTypeInfo; + } + } + + public MethodImplAttributes MethodImplementationFlags + { + get + { + return _method.ImplFlags; + } + } + + public Module Module + { + get + { + return _definingTypeInfo.Module; + } + } + + // + // Returns the ParameterInfo objects for the return parameter (in element 0), and the method parameters (in elements 1..length). + // + // The ParameterInfo objects will report "contextMethod" as their Member property and use it to get type variable information from + // the contextMethod's declaring type. The actual metadata, however, comes from "this." + // + // The methodTypeArguments provides the fill-ins for any method type variable elements in the parameter type signatures. + // + // Does not array-copy. + // + public RuntimeMethodParameterInfo[] GetRuntimeParametersAndReturn(MethodBase contextMethod, RuntimeType[] methodTypeArguments) + { + MetadataReader reader = _reader; + TypeContext typeContext = contextMethod.DeclaringType.GetRuntimeTypeInfo<RuntimeTypeInfo>().TypeContext; + typeContext = new TypeContext(typeContext.GenericTypeArguments, methodTypeArguments); + ReflectionDomain reflectionDomain = _definingTypeInfo.ReflectionDomain; + MethodSignature methodSignature = this.MethodSignature; + LowLevelList<Handle> typeSignatures = new LowLevelList<Handle>(10); + typeSignatures.Add(methodSignature.ReturnType.GetReturnTypeSignature(_reader).Type); + foreach (ParameterTypeSignatureHandle parameterTypeSignatureHandle in methodSignature.Parameters) + { + typeSignatures.Add(parameterTypeSignatureHandle.GetParameterTypeSignature(_reader).Type); + } + int count = typeSignatures.Count; + + RuntimeMethodParameterInfo[] result = new RuntimeMethodParameterInfo[count]; + foreach (ParameterHandle parameterHandle in _method.Parameters) + { + Parameter parameterRecord = parameterHandle.GetParameter(_reader); + int index = parameterRecord.Sequence; + result[index] = + RuntimeFatMethodParameterInfo.GetRuntimeFatMethodParameterInfo( + contextMethod, + _methodHandle, + index - 1, + parameterHandle, + reflectionDomain, + reader, + typeSignatures[index], + typeContext); + } + for (int i = 0; i < count; i++) + { + if (result[i] == null) + { + result[i] = + RuntimeThinMethodParameterInfo.GetRuntimeThinMethodParameterInfo( + contextMethod, + i - 1, + reflectionDomain, + reader, + typeSignatures[i], + typeContext); + } + } + return result; + } + + public String Name + { + get + { + return _method.Name.GetString(_reader); + } + } + + public MetadataReader Reader + { + get + { + return _reader; + } + } + + public MethodHandle MethodHandle + { + get + { + return _methodHandle; + } + } + + public override bool Equals(Object obj) + { + if (!(obj is RuntimeMethodCommon)) + return false; + return Equals((RuntimeMethodCommon)obj); + } + + public bool Equals(RuntimeMethodCommon other) + { + if (!(this._reader == other._reader)) + return false; + if (!(this._methodHandle.Equals(other._methodHandle))) + return false; + if (!(this._contextTypeInfo.Equals(other._contextTypeInfo))) + return false; + return true; + } + + public override int GetHashCode() + { + return _methodHandle.GetHashCode() ^ _contextTypeInfo.GetHashCode(); + } + + private MethodSignature MethodSignature + { + get + { + return _method.Signature.GetMethodSignature(_reader); + } + } + + private RuntimeNamedTypeInfo _definingTypeInfo; + private MethodHandle _methodHandle; + private RuntimeTypeInfo _contextTypeInfo; + + private MetadataReader _reader; + + private Method _method; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs new file mode 100644 index 000000000..a482f17ba --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -0,0 +1,402 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // Abstract base class for RuntimeNamedMethodInfo, RuntimeConstructedGenericMethodInfo. + // + internal abstract class RuntimeMethodInfo : ExtensibleMethodInfo, ITraceableTypeMember + { + protected RuntimeMethodInfo() + { + } + + public abstract override MethodAttributes Attributes + { + get; + } + + public abstract override CallingConventions CallingConvention + { + get; + } + + public sealed override bool ContainsGenericParameters + { + get + { + if (DeclaringType.GetTypeInfo().ContainsGenericParameters) + return true; + + if (!IsGenericMethod) + return false; + + Type[] pis = GetGenericArguments(); + for (int i = 0; i < pis.Length; i++) + { + if (pis[i].GetTypeInfo().ContainsGenericParameters) + return true; + } + + return false; + } + } + + public sealed override Delegate CreateDelegate(Type delegateType) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodInfo_CreateDelegate(this, delegateType); + + // Legacy: The only difference between calling CreateDelegate(type) and CreateDelegate(type, null) is that the former + // disallows closed instance delegates for V1.1 backward compatibility. + return CreateDelegate(delegateType, null, allowClosedInstanceDelegates: false); + } + + public sealed override Delegate CreateDelegate(Type delegateType, Object target) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodInfo_CreateDelegate(this, delegateType, target); + + return CreateDelegate(delegateType, target, allowClosedInstanceDelegates: true); + } + + public abstract override IEnumerable<CustomAttributeData> CustomAttributes + { + get; + } + + public sealed override Type DeclaringType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_DeclaringType(this); + return this.RuntimeDeclaringType; + } + } + + public abstract override bool Equals(object obj); + + public sealed override Type[] GetGenericArguments() + { + RuntimeType[] genericArgumentsOrParameters = this.RuntimeGenericArgumentsOrParameters; + if (genericArgumentsOrParameters.Length == 0) + return Array.Empty<Type>(); + Type[] result = new Type[genericArgumentsOrParameters.Length]; + for (int i = 0; i < genericArgumentsOrParameters.Length; i++) + result[i] = genericArgumentsOrParameters[i]; + return result; + } + + public abstract override MethodInfo GetGenericMethodDefinition(); + + public abstract override int GetHashCode(); + + public sealed override ParameterInfo[] GetParameters() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_GetParameters(this); + + RuntimeParameterInfo[] runtimeParameterInfos = this.GetRuntimeParametersAndReturn(this); + if (runtimeParameterInfos.Length == 1) + return Array.Empty<ParameterInfo>(); + ParameterInfo[] result = new ParameterInfo[runtimeParameterInfos.Length - 1]; + for (int i = 0; i < result.Length; i++) + result[i] = runtimeParameterInfos[i + 1]; + return result; + } + + public sealed override Object Invoke(Object obj, Object[] parameters) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_Invoke(this, obj, parameters); + + if (parameters == null) + parameters = Array.Empty<Object>(); + MethodInvoker methodInvoker = this.MethodInvoker; + return methodInvoker.Invoke(obj, parameters); + } + + public abstract override bool IsGenericMethod + { + get; + } + + public abstract override bool IsGenericMethodDefinition + { + get; + } + + public abstract override MethodInfo MakeGenericMethod(params Type[] typeArguments); + + public abstract override MethodImplAttributes MethodImplementationFlags + { + get; + } + + public abstract override Module Module + { + get; + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_Name(this); + return this.RuntimeName; + } + } + + public sealed override ParameterInfo ReturnParameter + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodInfo_ReturnParameter(this); + + return this.GetRuntimeParametersAndReturn(this)[0]; + } + } + + public sealed override Type ReturnType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodInfo_ReturnType(this); + + return ReturnParameter.ParameterType; + } + } + + public abstract override String ToString(); + + Type ITraceableTypeMember.ContainingType + { + get + { + return this.RuntimeDeclaringType; + } + } + + String ITraceableTypeMember.MemberName + { + get + { + return this.RuntimeName; + } + } + + internal abstract RuntimeType RuntimeDeclaringType + { + get; + } + + internal abstract String RuntimeName + { + get; + } + + protected abstract MethodInvoker UncachedMethodInvoker { get; } + + // + // The non-public version of MethodInfo.GetGenericArguments() (does not array-copy and has a more truthful name.) + // + internal abstract RuntimeType[] RuntimeGenericArgumentsOrParameters { get; } + + // + // The non-public version of MethodInfo.GetParameters() (does not array-copy.) + // The first element is actually the ReturnParameter value. + // + internal abstract RuntimeParameterInfo[] GetRuntimeParametersAndReturn(RuntimeMethodInfo contextMethod); + + internal MethodInvoker MethodInvoker + { + get + { + MethodInvoker methodInvoker = _lazyMethodInvoker; + if (methodInvoker == null) + { + if (ReturnType.IsByRef) + throw new NotSupportedException(SR.NotSupported_ByRefReturn); + methodInvoker = _lazyMethodInvoker = this.UncachedMethodInvoker; + } + return methodInvoker; + } + } + + private volatile MethodInvoker _lazyMethodInvoker = null; + + + // + // Common CreateDelegate worker. + // + private Delegate CreateDelegate(Type delegateType, Object target, bool allowClosedInstanceDelegates) + { + if (delegateType == null) + throw new ArgumentNullException("delegateType"); + + ExecutionEnvironment executionEnvironment = ReflectionCoreExecution.ExecutionEnvironment; + RuntimeTypeHandle delegateTypeHandle = delegateType.TypeHandle; + if (!executionEnvironment.IsAssignableFrom(typeof(Delegate).TypeHandle, delegateTypeHandle)) + throw new ArgumentException(SR.Arg_MustBeDelegate); + IEnumerator<MethodInfo> invokeMethodEnumerator = delegateType.GetTypeInfo().GetDeclaredMethods("Invoke").GetEnumerator(); + if (!invokeMethodEnumerator.MoveNext()) + { + // No Invoke method found. Since delegate types are compiler constructed, the most likely cause is missing metadata rather than + // a missing Invoke method. + + // We're deliberating calling FullName rather than ToString() because if it's the type that's missing metadata, + // the FullName property constructs a more informative MissingMetadataException than we can. + String fullName = delegateType.FullName; + throw new MissingMetadataException(SR.Format(SR.Arg_InvokeMethodMissingMetadata, fullName)); // No invoke method found. + } + MethodInfo invokeMethod = invokeMethodEnumerator.Current; + if (invokeMethodEnumerator.MoveNext()) + throw new ArgumentException(SR.Arg_MustBeDelegate); // Multiple invoke methods found. + + // Make sure the return type is assignment-compatible. + CheckIsAssignableFrom(executionEnvironment, invokeMethod.ReturnParameter.ParameterType, this.ReturnParameter.ParameterType); + + IList<ParameterInfo> delegateParameters = invokeMethod.GetParameters(); + IList<ParameterInfo> targetParameters = this.GetParameters(); + IEnumerator<ParameterInfo> delegateParameterEnumerator = delegateParameters.GetEnumerator(); + IEnumerator<ParameterInfo> targetParameterEnumerator = targetParameters.GetEnumerator(); + + bool isStatic = this.IsStatic; + bool isOpen; + if (isStatic) + { + if (delegateParameters.Count == targetParameters.Count) + { + // Open static: This is the "typical" case of calling a static method. + isOpen = true; + if (target != null) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + } + else + { + // Closed static: This is the "weird" v2.0 case where the delegate is closed over the target method's first parameter. + // (it make some kinda sense if you think of extension methods.) + isOpen = false; + if (!targetParameterEnumerator.MoveNext()) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + if (target != null) + CheckIsAssignableFrom(executionEnvironment, targetParameterEnumerator.Current.ParameterType, target.GetType()); + } + } + else + { + if (delegateParameters.Count == targetParameters.Count) + { + // Closed instance: This is the "typical" case of invoking an instance method. + isOpen = false; + if (!allowClosedInstanceDelegates) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + if (target != null) + CheckIsAssignableFrom(executionEnvironment, this.DeclaringType, target.GetType()); + } + else + { + // Open instance: This is the "weird" v2.0 case where the delegate has a leading extra parameter that's assignable to the target method's + // declaring type. + if (!delegateParameterEnumerator.MoveNext()) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + isOpen = true; + CheckIsAssignableFrom(executionEnvironment, this.DeclaringType, delegateParameterEnumerator.Current.ParameterType); + if (target != null) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + } + } + + // Verify that the parameters that the delegate and method have in common are assignment-compatible. + while (delegateParameterEnumerator.MoveNext()) + { + if (!targetParameterEnumerator.MoveNext()) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + CheckIsAssignableFrom(executionEnvironment, targetParameterEnumerator.Current.ParameterType, delegateParameterEnumerator.Current.ParameterType); + } + if (targetParameterEnumerator.MoveNext()) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + + return this.MethodInvoker.CreateDelegate(delegateType.TypeHandle, target, isStatic: isStatic, isVirtual: false, isOpen: isOpen); + } + + + private static void CheckIsAssignableFrom(ExecutionEnvironment executionEnvironment, Type dstType, Type srcType) + { + // byref types do not have a TypeHandle so we must treat these separately. + if (dstType.IsByRef && srcType.IsByRef) + { + if (!dstType.Equals(srcType)) + throw new ArgumentException(SR.Arg_DlgtTargMeth); + } + + // Enable pointers (which don't necessarily have typehandles). todo:be able to handle intptr <-> pointer, check if we need to handle + // casts via pointer where the pointer types aren't identical + if (dstType.Equals(srcType)) + { + return; + } + + // If assignment compatible in the normal way, allow + if (executionEnvironment.IsAssignableFrom(dstType.TypeHandle, srcType.TypeHandle)) + { + return; + } + + // they are not compatible yet enums can go into each other if their underlying element type is the same + // or into their equivalent integral type + Type dstTypeUnderlying = dstType; + if (dstType.GetTypeInfo().IsEnum) + { + dstTypeUnderlying = Enum.GetUnderlyingType(dstType); + } + Type srcTypeUnderlying = srcType; + if (srcType.GetTypeInfo().IsEnum) + { + srcTypeUnderlying = Enum.GetUnderlyingType(srcType); + } + if (dstTypeUnderlying.Equals(srcTypeUnderlying)) + { + return; + } + + throw new ArgumentException(SR.Arg_DlgtTargMeth); + } + + protected RuntimeMethodInfo WithDebugName() + { +#if DEBUG + if (_debugName == null) + { + _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. + _debugName = ((ITraceableTypeMember)this).MemberName; + } +#endif + return this; + } + +#if DEBUG + private String _debugName; +#endif + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs new file mode 100644 index 000000000..d7fa9f08d --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs @@ -0,0 +1,245 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // The runtime's implementation of non-constructor MethodInfo's that represent a method definition. + // + internal sealed partial class RuntimeNamedMethodInfo : RuntimeMethodInfo + { + // + // methodHandle - the "tkMethodDef" that identifies the method. + // definingType - the "tkTypeDef" that defined the method (this is where you get the metadata reader that created methodHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + private RuntimeNamedMethodInfo(MethodHandle methodHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + : base() + { + _common = new RuntimeMethodCommon(methodHandle, definingTypeInfo, contextTypeInfo); + } + + public sealed override MethodAttributes Attributes + { + get + { + return _common.Attributes; + } + } + + public sealed override CallingConventions CallingConvention + { + get + { + return _common.CallingConvention; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_CustomAttributes(this); + + return _common.CustomAttributes; + } + } + + public sealed override MethodInfo GetGenericMethodDefinition() + { + if (IsGenericMethodDefinition) + return this; + throw new InvalidOperationException(); + } + + public sealed override bool IsGenericMethod + { + get + { + return IsGenericMethodDefinition; + } + } + + public sealed override bool IsGenericMethodDefinition + { + get + { + Method method = _common.MethodHandle.GetMethod(_common.Reader); + return method.GenericParameters.GetEnumerator().MoveNext(); + } + } + + public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodInfo_MakeGenericMethod(this, typeArguments); + + if (typeArguments == null) + throw new ArgumentNullException("typeArguments"); + if (GenericTypeParameters.Length == 0) + throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this)); + RuntimeType[] genericTypeArguments = new RuntimeType[typeArguments.Length]; + for (int i = 0; i < typeArguments.Length; i++) + { + if (typeArguments[i] == null) + throw new ArgumentNullException(); + + genericTypeArguments[i] = typeArguments[i] as RuntimeType; + if (genericTypeArguments[i] == null) + throw new ArgumentException(SR.Format(SR.Reflection_CustomReflectionObjectsNotSupported, typeArguments[i]), "typeArguments[" + i + "]"); // Not a runtime type. + } + if (typeArguments.Length != GenericTypeParameters.Length) + throw new ArgumentException(SR.Format(SR.Argument_NotEnoughGenArguments, typeArguments.Length, GenericTypeParameters.Length)); + RuntimeMethodInfo methodInfo = (RuntimeMethodInfo)RuntimeConstructedGenericMethodInfo.GetRuntimeConstructedGenericMethodInfo(this, genericTypeArguments); + MethodInvoker methodInvoker = methodInfo.MethodInvoker; // For compatibility with other Make* apis, trigger any MissingMetadataExceptions now rather than later. + return methodInfo; + } + + public sealed override MethodImplAttributes MethodImplementationFlags + { + get + { + return _common.MethodImplementationFlags; + } + } + + public sealed override Module Module + { + get + { + return _common.Module; + } + } + + public sealed override String ToString() + { + return ComputeToString(this); + } + + public sealed override bool Equals(Object obj) + { + RuntimeNamedMethodInfo other = obj as RuntimeNamedMethodInfo; + if (other == null) + return false; + return this._common.Equals(other._common); + } + + public sealed override int GetHashCode() + { + return _common.GetHashCode(); + } + + internal String ComputeToString(RuntimeMethodInfo contextMethod) + { + return _common.ComputeToString(contextMethod, contextMethod.RuntimeGenericArgumentsOrParameters); + } + + internal MethodHandle MethodHandle + { + get + { + return _common.MethodHandle; + } + } + + internal MetadataReader Reader + { + get + { + return _common.Reader; + } + } + + internal sealed override RuntimeType[] RuntimeGenericArgumentsOrParameters + { + get + { + return this.GenericTypeParameters; + } + } + + internal sealed override RuntimeParameterInfo[] GetRuntimeParametersAndReturn(RuntimeMethodInfo contextMethod) + { + return _common.GetRuntimeParametersAndReturn(contextMethod, contextMethod.RuntimeGenericArgumentsOrParameters); + } + + internal sealed override RuntimeType RuntimeDeclaringType + { + get + { + return _common.DeclaringType; + } + } + + internal sealed override String RuntimeName + { + get + { + return _common.Name; + } + } + + private RuntimeType[] GenericTypeParameters + { + get + { + LowLevelList<RuntimeType> genericTypeParameters = new LowLevelList<RuntimeType>(); + Method method = _common.MethodHandle.GetMethod(_common.Reader); + foreach (GenericParameterHandle genericParameterHandle in method.GenericParameters) + { + RuntimeNamedMethodInfo owningMethod = this; + if (DeclaringType.IsConstructedGenericType) + { + // Desktop compat: Constructed generic types and their generic type definitions share the same Type objects for method generic parameters. + RuntimeNamedTypeInfo genericTypeDefinition = DeclaringType.GetGenericTypeDefinition().GetRuntimeTypeInfo<RuntimeNamedTypeInfo>(); + owningMethod = RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(MethodHandle, genericTypeDefinition, genericTypeDefinition); + } + RuntimeType genericParameterType = RuntimeTypeUnifierEx.GetRuntimeGenericParameterTypeForMethods(owningMethod, owningMethod._common.Reader, genericParameterHandle); + genericTypeParameters.Add(genericParameterType); + } + return genericTypeParameters.ToArray(); + } + } + + protected sealed override MethodInvoker UncachedMethodInvoker + { + get + { + return ReflectionCoreExecution.ExecutionEnvironment.GetMethodInvoker(_common.Reader, _common.DeclaringType, _common.MethodHandle, Array.Empty<RuntimeType>(), this); + } + } + + private readonly RuntimeMethodCommon _common; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs new file mode 100644 index 000000000..8aa7039e4 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs @@ -0,0 +1,166 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // The runtime's implementation of ConstructorInfo's represented in the metadata (this is the 99% case.) + // + internal sealed partial class RuntimePlainConstructorInfo : RuntimeConstructorInfo + { + // + // methodHandle - the "tkMethodDef" that identifies the method. + // definingType - the "tkTypeDef" that defined the method (this is where you get the metadata reader that created methodHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + private RuntimePlainConstructorInfo(MethodHandle methodHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + _common = new RuntimeMethodCommon(methodHandle, definingTypeInfo, contextTypeInfo); + } + + public sealed override MethodAttributes Attributes + { + get + { + return _common.Attributes; + } + } + + public sealed override CallingConventions CallingConvention + { + get + { + return _common.CallingConvention; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_CustomAttributes(this); + + return _common.CustomAttributes; + } + } + + public sealed override Type DeclaringType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_DeclaringType(this); + + return _common.DeclaringType; + } + } + + public sealed override Object Invoke(Object[] parameters) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.ConstructorInfo_Invoke(this, parameters); + + if (parameters == null) + parameters = Array.Empty<Object>(); + + // Most objects are allocated by NewObject and their constructors return "void". But in many frameworks, + // there are "weird" cases (e.g. String) where the constructor must do both the allocation and initialization. + // Reflection.Core does not hardcode these special cases. It's up to the ExecutionEnvironment to steer + // us the right way by coordinating the implementation of NewObject and MethodInvoker. + Object newObject = ReflectionCoreExecution.ExecutionEnvironment.NewObject(this.DeclaringType.TypeHandle); + Object ctorAllocatedObject = this.MethodInvoker.Invoke(newObject, parameters); + return newObject != null ? newObject : ctorAllocatedObject; + } + + public sealed override MethodImplAttributes MethodImplementationFlags + { + get + { + return _common.MethodImplementationFlags; + } + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.MethodBase_Name(this); + + return _common.Name; + } + } + + public sealed override bool Equals(Object obj) + { + RuntimePlainConstructorInfo other = obj as RuntimePlainConstructorInfo; + if (other == null) + return false; + return this._common.Equals(other._common); + } + + public sealed override int GetHashCode() + { + return _common.GetHashCode(); + } + + public sealed override String ToString() + { + return _common.ComputeToString(this, Array.Empty<RuntimeType>()); + } + + protected sealed override RuntimeParameterInfo[] RuntimeParametersAndReturn + { + get + { + return _common.GetRuntimeParametersAndReturn(this, Array.Empty<RuntimeType>()); + } + } + + protected sealed override MethodInvoker UncachedMethodInvoker + { + get + { + if (this._common.DefiningTypeInfo.IsAbstract) + throw new MemberAccessException(SR.Format(SR.Acc_CreateAbstEx, this._common.DefiningTypeInfo.FullName)); + + if (this.IsStatic) + throw new MemberAccessException(SR.Acc_NotClassInit); + + return ReflectionCoreExecution.ExecutionEnvironment.GetMethodInvoker(_common.Reader, _common.DeclaringType, _common.MethodHandle, Array.Empty<RuntimeType>(), this); + } + } + + private RuntimeMethodCommon _common; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs new file mode 100644 index 000000000..854033ef4 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // The runtime's implementation of constructors exposed on array types. + // + internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo + { + private RuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeType declaringType, RuntimeType[] runtimeParameterTypesAndReturn, InvokerOptions options, Func<Object, Object[], Object> invoker) + { + _syntheticMethodId = syntheticMethodId; + _declaringType = declaringType; + _options = options; + _invoker = invoker; + _runtimeParameterTypesAndReturn = runtimeParameterTypesAndReturn; + } + + public sealed override MethodAttributes Attributes + { + get + { + return MethodAttributes.Public | MethodAttributes.PrivateScope | MethodAttributes.RTSpecialName; + } + } + + public sealed override CallingConventions CallingConvention + { + get + { + return CallingConventions.Standard | CallingConventions.HasThis; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override Type DeclaringType + { + get + { + return _declaringType; + } + } + + public sealed override Object Invoke(Object[] parameters) + { + if (parameters == null) + parameters = Array.Empty<Object>(); + + Object ctorAllocatedObject = this.MethodInvoker.Invoke(null, parameters); + return ctorAllocatedObject; + } + + public sealed override MethodImplAttributes MethodImplementationFlags + { + get + { + return MethodImplAttributes.IL; + } + } + + public sealed override String Name + { + get + { + return ConstructorName; + } + } + + public sealed override bool Equals(object obj) + { + RuntimeSyntheticConstructorInfo other = obj as RuntimeSyntheticConstructorInfo; + if (other == null) + return false; + if (this._syntheticMethodId != other._syntheticMethodId) + return false; + if (!(this._declaringType.Equals(other._declaringType))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return this._declaringType.GetHashCode(); + } + + public sealed override String ToString() + { + return RuntimeMethodCommon.ComputeToString(this, Array.Empty<RuntimeType>(), RuntimeParametersAndReturn); + } + + protected sealed override RuntimeParameterInfo[] RuntimeParametersAndReturn + { + get + { + RuntimeParameterInfo[] runtimeParametersAndReturn = _lazyRuntimeParametersAndReturn; + if (runtimeParametersAndReturn == null) + { + runtimeParametersAndReturn = new RuntimeParameterInfo[_runtimeParameterTypesAndReturn.Length]; + for (int i = 0; i < runtimeParametersAndReturn.Length; i++) + { + runtimeParametersAndReturn[i] = RuntimeSyntheticParameterInfo.GetRuntimeSyntheticParameterInfo(this, i - 1, _runtimeParameterTypesAndReturn[i]); + } + _lazyRuntimeParametersAndReturn = runtimeParametersAndReturn; + } + return runtimeParametersAndReturn; + } + } + + protected sealed override MethodInvoker UncachedMethodInvoker + { + get + { + RuntimeTypeHandle[] runtimeParameterTypeHandles = new RuntimeTypeHandle[_runtimeParameterTypesAndReturn.Length - 1]; + for (int i = 1; i < _runtimeParameterTypesAndReturn.Length; i++) + runtimeParameterTypeHandles[i - 1] = _runtimeParameterTypesAndReturn[i].TypeHandle; + return ReflectionCoreExecution.ExecutionEnvironment.GetSyntheticMethodInvoker( + _declaringType.TypeHandle, + runtimeParameterTypeHandles, + _options, + _invoker); + } + } + + private volatile RuntimeParameterInfo[] _lazyRuntimeParametersAndReturn; + + private SyntheticMethodId _syntheticMethodId; + private RuntimeType _declaringType; + private RuntimeType[] _runtimeParameterTypesAndReturn; + private InvokerOptions _options; + private Func<Object, Object[], Object> _invoker; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs new file mode 100644 index 000000000..6b0dc7fe9 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + // + // These methods implement the Get/Set methods on array types. + // + internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo + { + private RuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeType declaringType, RuntimeType[] runtimeParameterTypesAndReturn, InvokerOptions options, Func<Object, Object[], Object> invoker) + { + _syntheticMethodId = syntheticMethodId; + _name = name; + _declaringType = declaringType; + _options = options; + _invoker = invoker; + _runtimeParameterTypesAndReturn = runtimeParameterTypesAndReturn; + } + + public sealed override MethodAttributes Attributes + { + get + { + return MethodAttributes.Public | MethodAttributes.PrivateScope; + } + } + + public sealed override CallingConventions CallingConvention + { + get + { + return CallingConventions.Standard | CallingConventions.HasThis; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override bool Equals(Object obj) + { + RuntimeSyntheticMethodInfo other = obj as RuntimeSyntheticMethodInfo; + if (other == null) + return false; + if (this._syntheticMethodId != other._syntheticMethodId) + return false; + if (!(this._declaringType.Equals(other._declaringType))) + return false; + return true; + } + + public sealed override MethodInfo GetGenericMethodDefinition() + { + throw new InvalidOperationException(); + } + + public sealed override int GetHashCode() + { + return this._declaringType.GetHashCode(); + } + + public sealed override bool IsGenericMethod + { + get + { + return false; + } + } + + public sealed override bool IsGenericMethodDefinition + { + get + { + return false; + } + } + + public sealed override MethodInfo MakeGenericMethod(params Type[] typeArguments) + { + throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this)); + } + + public sealed override MethodImplAttributes MethodImplementationFlags + { + get + { + return MethodImplAttributes.IL; + } + } + + public sealed override Module Module + { + get + { + return this.DeclaringType.GetTypeInfo().Assembly.ManifestModule; + } + } + + public sealed override String ToString() + { + return RuntimeMethodCommon.ComputeToString(this, Array.Empty<RuntimeType>(), GetRuntimeParametersAndReturn(this)); + } + + protected sealed override MethodInvoker UncachedMethodInvoker + { + get + { + RuntimeTypeHandle[] runtimeParameterTypeHandles = new RuntimeTypeHandle[_runtimeParameterTypesAndReturn.Length - 1]; + for (int i = 1; i < _runtimeParameterTypesAndReturn.Length; i++) + runtimeParameterTypeHandles[i - 1] = _runtimeParameterTypesAndReturn[i].TypeHandle; + return ReflectionCoreExecution.ExecutionEnvironment.GetSyntheticMethodInvoker( + _declaringType.TypeHandle, + runtimeParameterTypeHandles, + _options, + _invoker); + } + } + + internal sealed override RuntimeType[] RuntimeGenericArgumentsOrParameters + { + get + { + return Array.Empty<RuntimeType>(); + } + } + + internal sealed override RuntimeType RuntimeDeclaringType + { + get + { + return _declaringType; + } + } + + internal sealed override String RuntimeName + { + get + { + return _name; + } + } + + internal sealed override RuntimeParameterInfo[] GetRuntimeParametersAndReturn(RuntimeMethodInfo contextMethod) + { + RuntimeParameterInfo[] runtimeParametersAndReturn = _lazyRuntimeParametersAndReturn; + if (runtimeParametersAndReturn == null) + { + runtimeParametersAndReturn = new RuntimeParameterInfo[_runtimeParameterTypesAndReturn.Length]; + for (int i = 0; i < runtimeParametersAndReturn.Length; i++) + { + runtimeParametersAndReturn[i] = RuntimeSyntheticParameterInfo.GetRuntimeSyntheticParameterInfo(this, i - 1, _runtimeParameterTypesAndReturn[i]); + } + _lazyRuntimeParametersAndReturn = runtimeParametersAndReturn; + } + return runtimeParametersAndReturn; + } + + private volatile RuntimeParameterInfo[] _lazyRuntimeParametersAndReturn; + + private String _name; + private SyntheticMethodId _syntheticMethodId; + private RuntimeType _declaringType; + private RuntimeType[] _runtimeParameterTypesAndReturn; + private InvokerOptions _options; + private Func<Object, Object[], Object> _invoker; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs new file mode 100644 index 000000000..9fdd73b59 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/SyntheticMethodId.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.ParameterInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.MethodInfos +{ + internal enum SyntheticMethodId + { + ArrayCtor = 1, + ArrayMultiDimCtor = 2, + ArrayGet = 3, + ArraySet = 4, + ArrayAddress = 5, + + // Ids from 0x80000000..0xffffffff are reserved for the jagged array constructors + // (e.g. a type such as T[][][][] has three such constructors so we need three ID's. + // We stick the parameter count into the lower bits to generate unique ids.) + ArrayCtorJagged = unchecked((int)0x80000000), + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs new file mode 100644 index 000000000..62030bb23 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Modules/RuntimeModule.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Collections.Generic; + +using global::Internal.Reflection.Extensibility; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Modules +{ + // + // The runtime's implementation of a Module. + // + // Modules are quite meaningless in ProjectN but we have to keep up the appearances since they still exist in Win8P's surface area. + // As far as ProjectN is concerned, each Assembly has one module whose name is "<Unknown>". + // + internal sealed partial class RuntimeModule : ExtensibleModule + { + private RuntimeModule(RuntimeAssembly assembly) + : base() + { + _assembly = assembly; + } + + public sealed override Assembly Assembly + { + get + { + return _assembly; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override String FullyQualifiedName + { + get + { + return "<Unknown>"; + } + } + + public sealed override String Name + { + get + { + return this.Assembly.GetName().Name; + } + } + + public sealed override bool Equals(Object o) + { + RuntimeModule other = o as RuntimeModule; + if (other == null) + return false; + return this._assembly.Equals(other._assembly); + } + + public sealed override int GetHashCode() + { + return _assembly.GetHashCode(); + } + + public sealed override Type GetType(String name, bool throwOnError, bool ignoreCase) + { + return _assembly.GetType(name, throwOnError, ignoreCase); + } + + public sealed override String ToString() + { + return "<Unknown>"; + } + + private Assembly _assembly; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs new file mode 100644 index 000000000..606a99f92 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeFatMethodParameterInfo.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // + // This implements ParameterInfo objects owned by MethodBase objects that have an associated Parameter metadata entity. + // + internal sealed partial class RuntimeFatMethodParameterInfo : RuntimeMethodParameterInfo + { + private RuntimeFatMethodParameterInfo(MethodBase member, MethodHandle methodHandle, int position, ParameterHandle parameterHandle, ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeHandle, TypeContext typeContext) + : base(member, position, reflectionDomain, reader, typeHandle, typeContext) + { + _methodHandle = methodHandle; + _parameterHandle = parameterHandle; + _parameter = parameterHandle.GetParameter(reader); + } + + public sealed override ParameterAttributes Attributes + { + get + { + return _parameter.Flags; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + ReflectionDomain reflectionDomain = this.ReflectionDomain; + IEnumerable<CustomAttributeData> customAttributes = RuntimeCustomAttributeData.GetCustomAttributes(reflectionDomain, this.Reader, _parameter.CustomAttributes); + foreach (CustomAttributeData cad in customAttributes) + yield return cad; + ExecutionDomain executionDomain = reflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + MethodHandle declaringMethodHandle = _methodHandle; + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(this.Reader, _parameterHandle, declaringMethodHandle)) + yield return cad; + } + } + } + + public sealed override Object DefaultValue + { + get + { + return DefaultValueInfo.Item2; + } + } + + public sealed override bool HasDefaultValue + { + get + { + return DefaultValueInfo.Item1; + } + } + + public sealed override String Name + { + get + { + return _parameter.Name.GetStringOrNull(this.Reader); + } + } + + private Tuple<bool, Object> DefaultValueInfo + { + get + { + Tuple<bool, Object> defaultValueInfo = _lazyDefaultValueInfo; + if (defaultValueInfo == null) + { + if (!(this.ReflectionDomain is ExecutionDomain)) + throw new NotSupportedException(); + + Object defaultValue; + bool hasDefaultValue = ReflectionCoreExecution.ExecutionEnvironment.GetDefaultValueIfAny( + this.Reader, + _parameterHandle, + this.ParameterType, + this.CustomAttributes, + out defaultValue); + if (!hasDefaultValue) + { + defaultValue = IsOptional ? Missing.Value : DBNull.Value; + } + defaultValueInfo = _lazyDefaultValueInfo = Tuple.Create(hasDefaultValue, defaultValue); + } + return defaultValueInfo; + } + } + + private MethodHandle _methodHandle; + private ParameterHandle _parameterHandle; + private Parameter _parameter; + private volatile Tuple<bool, Object> _lazyDefaultValueInfo; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs new file mode 100644 index 000000000..adaf12843 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeMethodParameterInfo.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // + // Abstract base for all ParameterInfo objects exposed by runtime MethodBase objects + // (including the ReturnParameter.) + // + internal abstract class RuntimeMethodParameterInfo : RuntimeParameterInfo + { + protected RuntimeMethodParameterInfo(MethodBase member, int position, ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeHandle, TypeContext typeContext) + : base(member, position) + { + _reflectionDomain = reflectionDomain; + Reader = reader; + _typeHandle = typeHandle; + _typeContext = typeContext; + } + + public sealed override Type ParameterType + { + get + { + return _reflectionDomain.Resolve(this.Reader, _typeHandle, _typeContext); + } + } + + internal sealed override string ParameterTypeString + { + get + { + return _typeHandle.FormatTypeName(this.Reader, _typeContext, _reflectionDomain); + } + } + + protected MetadataReader Reader { get; private set; } + + + private ReflectionDomain _reflectionDomain; + private Handle _typeHandle; + private TypeContext _typeContext; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs new file mode 100644 index 000000000..2aa89dfec --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // + // Abstract base for all ParameterInfo objects created by the Runtime. + // + internal abstract class RuntimeParameterInfo : ExtensibleParameterInfo + { + protected RuntimeParameterInfo(MemberInfo member, int position) + { + _member = member; + _position = position; + } + + public abstract override ParameterAttributes Attributes { get; } + public abstract override IEnumerable<CustomAttributeData> CustomAttributes { get; } + public abstract override Object DefaultValue { get; } + + public sealed override bool Equals(Object obj) + { + RuntimeParameterInfo other = obj as RuntimeParameterInfo; + if (other == null) + return false; + if (this._position != other._position) + return false; + if (!(this._member.Equals(other._member))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _member.GetHashCode(); + } + + public abstract override bool HasDefaultValue { get; } + + public sealed override MemberInfo Member + { + get + { + return _member; + } + } + + public abstract override String Name { get; } + public abstract override Type ParameterType { get; } + + public sealed override int Position + { + get + { + return _position; + } + } + + public sealed override String ToString() + { + return this.ParameterTypeString + " " + this.Name; + } + + // Gets the ToString() output of ParameterType in a pay-to-play-safe way: Other Reflection ToString() methods should always use this rather than + // "ParameterType.ToString()". + internal abstract String ParameterTypeString { get; } + + protected ReflectionDomain ReflectionDomain + { + get + { + return ReflectionCoreExecution.ExecutionDomain; //@TODO: User Reflection Domains not yet supported. + } + } + + private MemberInfo _member; + private int _position; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs new file mode 100644 index 000000000..e431daedd --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimePropertyIndexParameterInfo.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.PropertyInfos; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // + // This implements ParameterInfo objects returned by PropertyInfo.GetIndexParameters(). Basically, they're identical to the underling accessor method's + // ParameterInfo's except that the Member property returns the PropertyInfo rather than a MethodBase. + // + internal sealed partial class RuntimePropertyIndexParameterInfo : RuntimeParameterInfo + { + private RuntimePropertyIndexParameterInfo(RuntimePropertyInfo member, RuntimeParameterInfo backingParameter) + : base(member, backingParameter.Position) + { + _backingParameter = backingParameter; + } + + public sealed override ParameterAttributes Attributes + { + get + { + return _backingParameter.Attributes; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return _backingParameter.CustomAttributes; + } + } + + public sealed override Object DefaultValue + { + get + { + return _backingParameter.DefaultValue; + } + } + + public sealed override bool HasDefaultValue + { + get + { + return _backingParameter.HasDefaultValue; + } + } + + public sealed override String Name + { + get + { + return _backingParameter.Name; + } + } + + public sealed override Type ParameterType + { + get + { + return _backingParameter.ParameterType; + } + } + + internal sealed override String ParameterTypeString + { + get + { + return _backingParameter.ParameterTypeString; + } + } + + private RuntimeParameterInfo _backingParameter; + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs new file mode 100644 index 000000000..5e6f5d849 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeSyntheticParameterInfo.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // This class is used for the "Get/Set" methods on array types. + internal sealed partial class RuntimeSyntheticParameterInfo : RuntimeParameterInfo + { + private RuntimeSyntheticParameterInfo(MemberInfo memberInfo, int position, RuntimeType parameterType) + : base(memberInfo, position) + { + _parameterType = parameterType; + } + + public sealed override ParameterAttributes Attributes + { + get + { + return ParameterAttributes.None; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override Object DefaultValue + { + get + { + return null; // Legacy: This is what the desktop returns. + } + } + + public sealed override bool HasDefaultValue + { + get + { + return false; // Legacy: Desktop strangely returns true but since we fixed this in Project N for other HasDefaultValues, we'll do so here as well. + } + } + + public sealed override String Name + { + get + { + return null; // Legacy: This is what the dekstop returns. + } + } + + public sealed override Type ParameterType + { + get + { + return _parameterType; + } + } + + internal sealed override String ParameterTypeString + { + get + { + return _parameterType.FormatTypeName(); + } + } + + private RuntimeType _parameterType; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs new file mode 100644 index 000000000..8173715d5 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/ParameterInfos/RuntimeThinMethodParameterInfo.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.ParameterInfos +{ + // + // This implements ParameterInfo objects owned by MethodBase objects that have no associated Parameter metadata. (In practice, + // this means return type "Parameters" that don't have custom attributes. + // + internal sealed partial class RuntimeThinMethodParameterInfo : RuntimeMethodParameterInfo + { + private RuntimeThinMethodParameterInfo(MethodBase member, int position, ReflectionDomain reflectionDomain, MetadataReader reader, Handle typeHandle, TypeContext typeContext) + : base(member, position, reflectionDomain, reader, typeHandle, typeContext) + { + } + + public sealed override ParameterAttributes Attributes + { + get + { + return ParameterAttributes.None; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override Object DefaultValue + { + get + { + // Returning "null" matches the desktop behavior, though this is inconsistent with the DBNull/Missing values + // returned by non-return ParameterInfo's without default values. + return null; + } + } + + public sealed override bool HasDefaultValue + { + get + { + // COMPAT: Desktop actually returns true here, but that behavior makes no sense. + return false; + } + } + + public sealed override String Name + { + get + { + return null; + } + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs new file mode 100644 index 000000000..f0b4ed7a6 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs @@ -0,0 +1,380 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Text; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.ParameterInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; + +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.PropertyInfos +{ + // + // The runtime's implementation of PropertyInfo's + // + internal sealed partial class RuntimePropertyInfo : ExtensiblePropertyInfo, ITraceableTypeMember + { + // + // propertyHandle - the "tkPropertyDef" that identifies the property. + // definingType - the "tkTypeDef" that defined the field (this is where you get the metadata reader that created propertyHandle.) + // contextType - the type that supplies the type context (i.e. substitutions for generic parameters.) Though you + // get your raw information from "definingType", you report "contextType" as your DeclaringType property. + // + // For example: + // + // typeof(Foo<>).GetTypeInfo().DeclaredMembers + // + // The definingType and contextType are both Foo<> + // + // typeof(Foo<int,String>).GetTypeInfo().DeclaredMembers + // + // The definingType is "Foo<,>" + // The contextType is "Foo<int,String>" + // + // We don't report any DeclaredMembers for arrays or generic parameters so those don't apply. + // + private RuntimePropertyInfo(PropertyHandle propertyHandle, RuntimeNamedTypeInfo definingTypeInfo, RuntimeTypeInfo contextTypeInfo) + { + _propertyHandle = propertyHandle; + _definingTypeInfo = definingTypeInfo; + _contextTypeInfo = contextTypeInfo; + _reader = definingTypeInfo.Reader; + _property = propertyHandle.GetProperty(_reader); + } + + public sealed override PropertyAttributes Attributes + { + get + { + return _property.Flags; + } + } + + public sealed override bool CanRead + { + get + { + MethodHandle ignore; + return GetAccessor(MethodSemanticsAttributes.Getter, out ignore); + } + } + + public sealed override bool CanWrite + { + get + { + MethodHandle ignore; + return GetAccessor(MethodSemanticsAttributes.Setter, out ignore); + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_CustomAttributes(this); + + foreach (CustomAttributeData cad in RuntimeCustomAttributeData.GetCustomAttributes(_definingTypeInfo.ReflectionDomain, _reader, _property.CustomAttributes)) + yield return cad; + ExecutionDomain executionDomain = _definingTypeInfo.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(_reader, _propertyHandle, _definingTypeInfo.TypeDefinitionHandle)) + yield return cad; + } + } + } + + public sealed override Type DeclaringType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_DeclaringType(this); + + return _contextTypeInfo.AsType(); + } + } + + public sealed override bool Equals(Object obj) + { + RuntimePropertyInfo other = obj as RuntimePropertyInfo; + if (other == null) + return false; + if (!(this._reader == other._reader)) + return false; + if (!(this._propertyHandle.Equals(other._propertyHandle))) + return false; + if (!(this._contextTypeInfo.Equals(other._contextTypeInfo))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _propertyHandle.GetHashCode(); + } + + public sealed override Object GetConstantValue() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_GetConstantValue(this); + + if (!(_definingTypeInfo.ReflectionDomain is ExecutionDomain)) + throw new NotSupportedException(); // Cannot instantiate a boxed enum on a non-execution domain. + + Object defaultValue; + if (!ReflectionCoreExecution.ExecutionEnvironment.GetDefaultValueIfAny( + _reader, + _propertyHandle, + this.PropertyType, + this.CustomAttributes, + out defaultValue)) + { + throw new InvalidOperationException(); + } + return defaultValue; + } + + public sealed override ParameterInfo[] GetIndexParameters() + { + bool useGetter = CanRead; + RuntimeMethodInfo accessor = (useGetter ? Getter : Setter); + RuntimeParameterInfo[] runtimeMethodParameterInfos = accessor.GetRuntimeParametersAndReturn(accessor); + int count = runtimeMethodParameterInfos.Length - 1; // Subtract one for the return parameter. + if (!useGetter) + count--; // If we're taking the parameters off the setter, subtract one for the "value" parameter. + if (count == 0) + return Array.Empty<ParameterInfo>(); + ParameterInfo[] result = new ParameterInfo[count]; + for (int i = 0; i < count; i++) + result[i] = RuntimePropertyIndexParameterInfo.GetRuntimePropertyIndexParameterInfo(this, runtimeMethodParameterInfos[i + 1]); + return result; + } + + public sealed override MethodInfo GetMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_GetMethod(this); + + return Getter; + } + } + + public sealed override Object GetValue(Object obj, Object[] index) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_GetValue(this, obj, index); + + if (_lazyGetterInvoker == null) + { + MethodHandle getterMethodHandle; + if (!GetAccessor(MethodSemanticsAttributes.Getter, out getterMethodHandle)) + throw new ArgumentException(); + MethodAttributes getterMethodAttributes = getterMethodHandle.GetMethod(_reader).Flags; + _lazyGetterInvoker = ReflectionCoreExecution.ExecutionEnvironment.GetMethodInvoker(_reader, _contextTypeInfo.RuntimeType, getterMethodHandle, Array.Empty<RuntimeType>(), this); + } + if (index == null) + index = Array.Empty<Object>(); + return _lazyGetterInvoker.Invoke(obj, index); + } + + public sealed override Module Module + { + get + { + return _definingTypeInfo.Module; + } + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_Name(this); + + return _property.Name.GetString(_reader); + } + } + + public sealed override Type PropertyType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_PropertyType(this); + + TypeContext typeContext = _contextTypeInfo.TypeContext; + Handle typeHandle = _property.Signature.GetPropertySignature(_reader).Type; + return _contextTypeInfo.ReflectionDomain.Resolve(_reader, typeHandle, typeContext); + } + } + + public sealed override MethodInfo SetMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_SetMethod(this); + + return Setter; + } + } + + public sealed override void SetValue(Object obj, Object value, Object[] index) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.PropertyInfo_SetValue(this, obj, value, index); + + if (_lazySetterInvoker == null) + { + MethodHandle setterMethodHandle; + if (!GetAccessor(MethodSemanticsAttributes.Setter, out setterMethodHandle)) + throw new ArgumentException(); + MethodAttributes setterMethodAttributes = setterMethodHandle.GetMethod(_reader).Flags; + _lazySetterInvoker = ReflectionCoreExecution.ExecutionEnvironment.GetMethodInvoker(_reader, _contextTypeInfo.RuntimeType, setterMethodHandle, Array.Empty<RuntimeType>(), this); + } + Object[] arguments; + if (index == null) + { + arguments = new Object[] { value }; + } + else + { + arguments = new Object[index.Length + 1]; + for (int i = 0; i < index.Length; i++) + { + arguments[i] = index[i]; + } + arguments[index.Length] = value; + } + _lazySetterInvoker.Invoke(obj, arguments); + } + + public sealed override String ToString() + { + StringBuilder sb = new StringBuilder(30); + + ReflectionDomain reflectionDomain = _contextTypeInfo.ReflectionDomain; + TypeContext typeContext = _contextTypeInfo.TypeContext; + Handle typeHandle = _property.Signature.GetPropertySignature(_reader).Type; + sb.Append(typeHandle.FormatTypeName(_reader, typeContext, reflectionDomain)); + sb.Append(' '); + sb.Append(this.Name); + ParameterInfo[] indexParameters = this.GetIndexParameters(); + if (indexParameters.Length != 0) + { + RuntimeParameterInfo[] indexRuntimeParameters = new RuntimeParameterInfo[indexParameters.Length]; + for (int i = 0; i < indexParameters.Length; i++) + indexRuntimeParameters[i] = (RuntimeParameterInfo)(indexParameters[i]); + sb.Append(" ["); + sb.Append(RuntimeMethodCommon.ComputeParametersString(indexRuntimeParameters, 0)); + sb.Append(']'); + } + + return sb.ToString(); + } + + String ITraceableTypeMember.MemberName + { + get + { + return _property.Name.GetString(_reader); + } + } + + Type ITraceableTypeMember.ContainingType + { + get + { + return _contextTypeInfo.AsType(); + } + } + + private RuntimeMethodInfo Getter + { + get + { + MethodHandle getterHandle; + if (GetAccessor(MethodSemanticsAttributes.Getter, out getterHandle)) + { + return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(getterHandle, _definingTypeInfo, _contextTypeInfo); + } + return null; + } + } + + private RuntimeMethodInfo Setter + { + get + { + MethodHandle setterHandle; + if (GetAccessor(MethodSemanticsAttributes.Setter, out setterHandle)) + { + return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(setterHandle, _definingTypeInfo, _contextTypeInfo); + } + return null; + } + } + + private bool GetAccessor(MethodSemanticsAttributes methodSemanticsAttribute, out MethodHandle methodHandle) + { + foreach (MethodSemanticsHandle methodSemanticsHandle in _property.MethodSemantics) + { + MethodSemantics methodSemantics = methodSemanticsHandle.GetMethodSemantics(_reader); + if (methodSemantics.Attributes == methodSemanticsAttribute) + { + methodHandle = methodSemantics.Method; + return true; + } + } + methodHandle = default(MethodHandle); + return false; + } + + private RuntimePropertyInfo WithDebugName() + { +#if DEBUG + if (_debugName == null) + { + _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. + _debugName = ((ITraceableTypeMember)this).MemberName; + } +#endif + return this; + } + + private RuntimeNamedTypeInfo _definingTypeInfo; + private PropertyHandle _propertyHandle; + private RuntimeTypeInfo _contextTypeInfo; + + private MetadataReader _reader; + private Property _property; + + private volatile MethodInvoker _lazyGetterInvoker = null; + private volatile MethodInvoker _lazySetterInvoker = null; + +#if DEBUG + private String _debugName; +#endif + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs new file mode 100644 index 000000000..f9400fde6 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Tracing/ReflectionEventSource.cs @@ -0,0 +1,376 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.Tracing; + +namespace System.Reflection.Runtime.Tracing +{ + [EventSource(Guid = "55B578AE-32B0-48F8-822F-B3245E6FA59C", Name = "System.Reflection.Runtime.Tracing")] + internal sealed class ReflectionEventSource : EventSource + { + // Defines the singleton instance for the Resources ETW provider + public static readonly ReflectionEventSource Log = new ReflectionEventSource(); + + public static bool IsInitialized + { + get + { + return Log != null; + } + } + + private ReflectionEventSource() { } + + + #region Reflection Event Handlers + [Event(1)] + public void TypeInfo_CustomAttributes(String typeName) + { + WriteEvent(1, typeName); + } + + [Event(2)] + public void TypeInfo_Name(String typeName) + { + WriteEvent(2, typeName); + } + + [Event(3)] + public void TypeInfo_BaseType(String typeName) + { + WriteEvent(3, typeName); + } + + [Event(4)] + public void TypeInfo_DeclaredConstructors(String typeName) + { + WriteEvent(4, typeName); + } + + [Event(5)] + public void TypeInfo_DeclaredEvents(String typeName) + { + WriteEvent(5, typeName); + } + + [Event(6)] + public void TypeInfo_DeclaredFields(String typeName) + { + WriteEvent(6, typeName); + } + + [Event(7)] + public void TypeInfo_DeclaredMembers(String typeName) + { + WriteEvent(7, typeName); + } + + [Event(8)] + public void TypeInfo_DeclaredMethods(String typeName) + { + WriteEvent(8, typeName); + } + + [Event(9)] + public void TypeInfo_DeclaredNestedTypes(String typeName) + { + WriteEvent(9, typeName); + } + + [Event(10)] + public void TypeInfo_DeclaredProperties(String typeName) + { + WriteEvent(10, typeName); + } + + [Event(11)] + public void TypeInfo_DeclaringMethod(String typeName) + { + WriteEvent(11, typeName); + } + + [Event(12)] + public void TypeInfo_FullName(String typeName) + { + WriteEvent(12, typeName); + } + + [Event(13)] + public void TypeInfo_Namespace(String typeName) + { + WriteEvent(13, typeName); + } + + [Event(14)] + public void TypeInfo_GetDeclaredEvent(String typeName, String eventName) + { + WriteEvent(14, typeName, eventName); + } + + [Event(15)] + public void TypeInfo_GetDeclaredField(String typeName, String fieldName) + { + WriteEvent(15, typeName, fieldName); + } + + [Event(16)] + public void TypeInfo_GetDeclaredMethod(String typeName, String methodName) + { + WriteEvent(16, typeName, methodName); + } + + [Event(17)] + public void TypeInfo_GetDeclaredProperty(String typeName, String propertyName) + { + WriteEvent(17, typeName, propertyName); + } + + [Event(18)] + public void TypeInfo_MakeArrayType(String typeName) + { + WriteEvent(18, typeName); + } + + [Event(19)] + public void TypeInfo_MakeByRefType(String typeName) + { + WriteEvent(19, typeName); + } + + [Event(20)] + public void TypeInfo_MakeGenericType(String typeName, String typeArguments) + { + WriteEvent(20, typeName, typeArguments); + } + + [Event(21)] + public void TypeInfo_MakePointerType(String typeName) + { + WriteEvent(21, typeName); + } + + [Event(22)] + public void Assembly_DefinedTypes(String assemblyName) + { + WriteEvent(22, assemblyName); + } + + [Event(23)] + public void Assembly_GetType(String assemblyName, String typeName) + { + WriteEvent(23, assemblyName, typeName); + } + + [Event(24)] + public void Assembly_CustomAttributes(String assemblyName) + { + WriteEvent(24, assemblyName); + } + + [Event(25)] + public void Assembly_FullName(String assemblyName) + { + WriteEvent(25, assemblyName); + } + + [Event(26)] + public void Assembly_GetName(String assemblyName) + { + WriteEvent(26, assemblyName); + } + + [Event(27)] + public void CustomAttributeData_ConstructorArguments(String caName) + { + WriteEvent(27, caName); + } + + [Event(28)] + public void CustomAttributeData_NamedArguments(String caName) + { + WriteEvent(28, caName); + } + + [Event(29)] + public void EventInfo_AddMethod(String typeName, String eventName) + { + WriteEvent(29, typeName, eventName); + } + + [Event(30)] + public void EventInfo_RaiseMethod(String typeName, String eventName) + { + WriteEvent(30, typeName, eventName); + } + + [Event(31)] + public void EventInfo_RemoveMethod(String typeName, String eventName) + { + WriteEvent(31, typeName, eventName); + } + + [Event(32)] + public void EventInfo_CustomAttributes(String typeName, String eventName) + { + WriteEvent(32, typeName, eventName); + } + + [Event(33)] + public void EventInfo_Name(String typeName, String eventName) + { + WriteEvent(33, typeName, eventName); + } + + [Event(34)] + public void EventInfo_DeclaringType(String typeName, String eventName) + { + WriteEvent(34, typeName, eventName); + } + + [Event(35)] + public void FieldInfo_SetValue(String typeName, String fieldName) + { + WriteEvent(35, typeName, fieldName); + } + + [Event(36)] + public void FieldInfo_GetValue(String typeName, String fieldName) + { + WriteEvent(36, typeName, fieldName); + } + + [Event(37)] + public void FieldInfo_CustomAttributes(String typeName, String fieldName) + { + WriteEvent(37, typeName, fieldName); + } + + [Event(38)] + public void FieldInfo_Name(String typeName, String fieldName) + { + WriteEvent(38, typeName, fieldName); + } + + [Event(39)] + public void FieldInfo_DeclaringType(String typeName, String fieldName) + { + WriteEvent(39, typeName, fieldName); + } + + [Event(40)] + public void MethodBase_CustomAttributes(String typeName, String methodName) + { + WriteEvent(40, typeName, methodName); + } + + [Event(41)] + public void MethodBase_Name(String typeName, String methodName) + { + WriteEvent(41, typeName, methodName); + } + + [Event(42)] + public void MethodBase_DeclaringType(String typeName, String methodName) + { + WriteEvent(42, typeName, methodName); + } + + [Event(43)] + public void MethodBase_GetParameters(String typeName, String methodName) + { + WriteEvent(43, typeName, methodName); + } + + [Event(44)] + public void MethodBase_Invoke(String typeName, String methodName) + { + WriteEvent(44, typeName, methodName); + } + + [Event(45)] + public void MethodInfo_ReturnParameter(String typeName, String methodName) + { + WriteEvent(45, typeName, methodName); + } + + [Event(46)] + public void MethodInfo_ReturnType(String typeName, String methodName) + { + WriteEvent(46, typeName, methodName); + } + + [Event(47)] + public void MethodInfo_MakeGenericMethod(String typeName, String methodName, String typeArguments) + { + WriteEvent(47, typeName, methodName, typeArguments); + } + + [Event(48)] + public void MethodInfo_CreateDelegate(String typeName, String methodName, String delegateTypeName) + { + WriteEvent(48, typeName, methodName, delegateTypeName); + } + + [Event(49)] + public void PropertyInfo_GetValue(String typeName, String propertyName) + { + WriteEvent(49, typeName, propertyName); + } + + [Event(50)] + public void PropertyInfo_SetValue(String typeName, String propertyName) + { + WriteEvent(50, typeName, propertyName); + } + + [Event(51)] + public void PropertyInfo_GetMethod(String typeName, String propertyName) + { + WriteEvent(51, typeName, propertyName); + } + + [Event(52)] + public void PropertyInfo_SetMethod(String typeName, String propertyName) + { + WriteEvent(52, typeName, propertyName); + } + + [Event(53)] + public void PropertyInfo_GetConstantValue(String typeName, String propertyName) + { + WriteEvent(53, typeName, propertyName); + } + + [Event(54)] + public void PropertyInfo_PropertyType(String typeName, String propertyName) + { + WriteEvent(54, typeName, propertyName); + } + + [Event(55)] + public void PropertyInfo_CustomAttributes(String typeName, String propertyName) + { + WriteEvent(55, typeName, propertyName); + } + + [Event(56)] + public void PropertyInfo_Name(String typeName, String propertyName) + { + WriteEvent(56, typeName, propertyName); + } + + [Event(57)] + public void PropertyInfo_DeclaringType(String typeName, String propertyName) + { + WriteEvent(57, typeName, propertyName); + } + + [Event(58)] + public void TypeInfo_AssemblyQualifiedName(String typeName) + { + WriteEvent(58, typeName); + } + #endregion + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs new file mode 100644 index 000000000..f132021d7 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs @@ -0,0 +1,317 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.MethodInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +using TargetException = System.ArgumentException; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // The runtime's implementation of TypeInfo's for array types. + // + + internal sealed partial class RuntimeArrayTypeInfo : RuntimeHasElementTypeInfo + { + private RuntimeArrayTypeInfo(RuntimeType hasElementType) + : base(hasElementType) + { + Debug.Assert(hasElementType.IsArray); + } + + public sealed override TypeAttributes Attributes + { + get + { + return TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Serializable; + } + } + + internal sealed override IEnumerable<RuntimeConstructorInfo> SyntheticConstructors + { + get + { + bool multiDim = this.RuntimeType.InternalIsMultiDimArray; + int rank = this.RuntimeType.GetArrayRank(); + + ReflectionDomain reflectionDomain = this.ReflectionDomain; + FoundationTypes foundationTypes = reflectionDomain.FoundationTypes; + RuntimeType arrayType = this.RuntimeType; + RuntimeType countType = foundationTypes.SystemInt32.AsConfirmedRuntimeType(); + RuntimeType voidType = foundationTypes.SystemVoid.AsConfirmedRuntimeType(); + + { + RuntimeType[] ctorParametersAndReturn = new RuntimeType[rank + 1]; + ctorParametersAndReturn[0] = voidType; + for (int i = 0; i < rank; i++) + ctorParametersAndReturn[i + 1] = countType; + yield return RuntimeSyntheticConstructorInfo.GetRuntimeSyntheticConstructorInfo( + SyntheticMethodId.ArrayCtor, + arrayType, + ctorParametersAndReturn, + InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, + delegate (Object _this, Object[] args) + { + if (rank == 1) + { + // Legacy: This seems really wrong in the rank1-multidim case (as it's a case of a synthetic constructor that's declared on T[*] returning an instance of T[]) + // This is how the desktop behaves, however. + + int count = (int)(args[0]); + + RuntimeType vectorType; + if (multiDim) + { + vectorType = ReflectionCoreNonPortable.GetArrayType(arrayType.InternalRuntimeElementType); + } + else + { + vectorType = arrayType; + } + + return ReflectionCoreExecution.ExecutionEnvironment.NewArray(vectorType.TypeHandle, count); + } + else + { + int[] lengths = new int[rank]; + for (int i = 0; i < rank; i++) + { + lengths[i] = (int)(args[i]); + } + return ReflectionCoreExecution.ExecutionEnvironment.NewMultiDimArray(arrayType.TypeHandle, lengths, null); + } + } + ); + } + + if (!multiDim) + { + // + // Jagged arrays also expose constructors that take multiple indices and construct a jagged matrix. For example, + // + // String[][][][] + // + // also exposes: + // + // .ctor(int32, int32) + // .ctor(int32, int32, int32) + // .ctor(int32, int32, int32, int32) + // + + int parameterCount = 2; + RuntimeType elementType = this.RuntimeType.InternalRuntimeElementType; + while (elementType.IsArray && elementType.GetArrayRank() == 1) + { + RuntimeType[] ctorParametersAndReturn = new RuntimeType[parameterCount + 1]; + ctorParametersAndReturn[0] = voidType; + for (int i = 0; i < parameterCount; i++) + ctorParametersAndReturn[i + 1] = countType; + yield return RuntimeSyntheticConstructorInfo.GetRuntimeSyntheticConstructorInfo( + SyntheticMethodId.ArrayCtorJagged + parameterCount, + arrayType, + ctorParametersAndReturn, + InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, + delegate (Object _this, Object[] args) + { + int[] lengths = new int[args.Length]; + for (int i = 0; i < args.Length; i++) + { + lengths[i] = (int)(args[i]); + } + Array jaggedArray = CreateJaggedArray(arrayType, lengths, 0); + return jaggedArray; + } + ); + parameterCount++; + elementType = elementType.InternalRuntimeElementType; + } + } + + if (multiDim) + { + RuntimeType[] ctorParametersAndReturn = new RuntimeType[rank * 2 + 1]; + ctorParametersAndReturn[0] = voidType; + for (int i = 0; i < rank * 2; i++) + ctorParametersAndReturn[i + 1] = countType; + yield return RuntimeSyntheticConstructorInfo.GetRuntimeSyntheticConstructorInfo( + SyntheticMethodId.ArrayMultiDimCtor, + arrayType, + ctorParametersAndReturn, + InvokerOptions.AllowNullThis | InvokerOptions.DontWrapException, + delegate (Object _this, Object[] args) + { + int[] lengths = new int[rank]; + int[] lowerBounds = new int[rank]; + for (int i = 0; i < rank; i++) + { + lowerBounds[i] = (int)(args[i * 2]); + lengths[i] = (int)(args[i * 2 + 1]); + } + return ReflectionCoreExecution.ExecutionEnvironment.NewMultiDimArray(arrayType.TypeHandle, lengths, lowerBounds); + } + ); + } + } + } + + internal sealed override IEnumerable<RuntimeMethodInfo> SyntheticMethods + { + get + { + int rank = this.RuntimeType.GetArrayRank(); + + ReflectionDomain reflectionDomain = this.ReflectionDomain; + FoundationTypes foundationTypes = reflectionDomain.FoundationTypes; + RuntimeType indexType = foundationTypes.SystemInt32.AsConfirmedRuntimeType(); + RuntimeType arrayType = this.RuntimeType; + RuntimeType elementType = arrayType.InternalRuntimeElementType; + RuntimeType voidType = foundationTypes.SystemVoid.AsConfirmedRuntimeType(); + + { + RuntimeType[] getParametersAndReturn = new RuntimeType[rank + 1]; + getParametersAndReturn[0] = elementType; + for (int i = 0; i < rank; i++) + getParametersAndReturn[i + 1] = indexType; + yield return RuntimeSyntheticMethodInfo.GetRuntimeSyntheticMethodInfo( + SyntheticMethodId.ArrayGet, + "Get", + arrayType, + getParametersAndReturn, + InvokerOptions.None, + delegate (Object _this, Object[] args) + { + Array array = (Array)_this; + int[] indices = new int[rank]; + for (int i = 0; i < rank; i++) + indices[i] = (int)(args[i]); + return array.GetValue(indices); + } + ); + } + + { + RuntimeType[] setParametersAndReturn = new RuntimeType[rank + 2]; + setParametersAndReturn[0] = voidType; + for (int i = 0; i < rank; i++) + setParametersAndReturn[i + 1] = indexType; + setParametersAndReturn[rank + 1] = elementType; + yield return RuntimeSyntheticMethodInfo.GetRuntimeSyntheticMethodInfo( + SyntheticMethodId.ArraySet, + "Set", + arrayType, + setParametersAndReturn, + InvokerOptions.None, + delegate (Object _this, Object[] args) + { + Array array = (Array)_this; + int[] indices = new int[rank]; + for (int i = 0; i < rank; i++) + indices[i] = (int)(args[i]); + Object value = args[rank]; + array.SetValue(value, indices); + return null; + } + ); + } + + { + RuntimeType[] addressParametersAndReturn = new RuntimeType[rank + 1]; + addressParametersAndReturn[0] = ReflectionCoreNonPortable.GetByRefType(elementType); + for (int i = 0; i < rank; i++) + addressParametersAndReturn[i + 1] = indexType; + yield return RuntimeSyntheticMethodInfo.GetRuntimeSyntheticMethodInfo( + SyntheticMethodId.ArrayAddress, + "Address", + arrayType, + addressParametersAndReturn, + InvokerOptions.None, + delegate (Object _this, Object[] args) + { + throw new NotSupportedException(); + } + ); + } + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + return TypeDefInfoProjectionForArrays.TypeRefDefOrSpecForBaseType; + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + if (this.RuntimeType.InternalIsMultiDimArray) + return Array.Empty<QTypeDefRefOrSpec>(); + else + return TypeDefInfoProjectionForArrays.TypeRefDefOrSpecsForDirectlyImplementedInterfaces; + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + return new TypeContext(new RuntimeType[] { this.RuntimeType.InternalRuntimeElementType }, null); + } + } + + // + // Arrays don't have a true typedef behind them but for the purpose of reporting base classes and interfaces, we can create a pretender. + // + private RuntimeNamedTypeInfo TypeDefInfoProjectionForArrays + { + get + { + Debug.Assert(this.ReflectionDomain == ReflectionCoreExecution.ExecutionDomain, "User Reflectable Domains not yet implemented."); + RuntimeTypeHandle projectionTypeHandleForArrays = ReflectionCoreExecution.ExecutionEnvironment.ProjectionTypeForArrays; + RuntimeType projectionRuntimeTypeForArrays = ReflectionCoreNonPortable.GetTypeForRuntimeTypeHandle(projectionTypeHandleForArrays); + return projectionRuntimeTypeForArrays.GetRuntimeTypeInfo<RuntimeNamedTypeInfo>(); + } + } + + // + // Helper for jagged array constructors. + // + private Array CreateJaggedArray(RuntimeType arrayType, int[] lengths, int index) + { + int length = lengths[index]; + Array jaggedArray = ReflectionCoreExecution.ExecutionEnvironment.NewArray(arrayType.TypeHandle, length); + if (index != lengths.Length - 1) + { + for (int i = 0; i < length; i++) + { + Array subArray = CreateJaggedArray(arrayType.InternalRuntimeElementType, lengths, index + 1); + jaggedArray.SetValue(subArray, i); + } + } + return jaggedArray; + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs new file mode 100644 index 000000000..169a88e8d --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // TypeInfos that represent type definitions (i.e. Foo or Foo<>) or constructed generic types (Foo<int>) + // that can never be reflection-enabled due to the framework Reflection block. + // + // These types differ from NoMetadata TypeInfos in that properties that inquire about members, + // custom attributes or interfaces return an empty list rather than throwing a MissingMetadataException. + // + // Since these represent "internal framework types", the app cannot prove we are lying. + // + internal sealed partial class RuntimeBlockedTypeInfo : RuntimeTypeInfo + { + private RuntimeBlockedTypeInfo(RuntimeType runtimeType) + { + _asType = runtimeType; + } + + public sealed override Assembly Assembly + { + get + { + return typeof(Object).GetTypeInfo().Assembly; + } + } + + public sealed override TypeAttributes Attributes + { + get + { + return TypeAttributes.Class | TypeAttributes.NotPublic; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override IEnumerable<TypeInfo> DeclaredNestedTypes + { + get + { + return Empty<TypeInfo>.Enumerable; + } + } + + public sealed override bool Equals(Object obj) + { + if (Object.ReferenceEquals(this, obj)) + return true; + + RuntimeBlockedTypeInfo other = obj as RuntimeBlockedTypeInfo; + if (other == null) + return false; + if (!(this._asType.Equals(other._asType))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _asType.GetHashCode(); + } + + public sealed override Guid GUID + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override bool IsGenericType + { + get + { + return _asType.IsConstructedGenericType || this.IsGenericTypeDefinition; + } + } + + public sealed override bool IsGenericTypeDefinition + { + get + { + return _asType.InternalIsGenericTypeDefinition; + } + } + + // + // Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties. + // The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this" + // and substituting the value of this.TypeContext into any generic parameters. + // + // Default implementation returns null which causes the Declared*** properties to return no members. + // + // Note that this does not apply to DeclaredNestedTypes. Nested types and their containers have completely separate generic instantiation environments + // (despite what C# might lead you to think.) Constructed generic types return the exact same same nested types that its generic type definition does + // - i.e. their DeclaringTypes refer back to the generic type definition, not the constructed generic type.) + // + // Note also that we cannot use this anchoring concept for base types because of generic parameters. Generic parameters return + // baseclass and interfaces based on its constraints. + // + internal sealed override RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers + { + get + { + return null; // this causes the type to report having no members. + } + } + + internal sealed override RuntimeType[] RuntimeGenericTypeParameters + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + internal sealed override RuntimeType RuntimeType + { + get + { + return _asType; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + private RuntimeType _asType; + } +} + + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs new file mode 100644 index 000000000..a0df40576 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs @@ -0,0 +1,172 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core.NonPortable; +using Internal.Reflection.Tracing; +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // TypeInfos that represent constructed generic types. + // + // + internal sealed partial class RuntimeConstructedGenericTypeInfo : RuntimeTypeInfo + { + private RuntimeConstructedGenericTypeInfo(RuntimeType genericConstructedGenericType) + : base() + { + Debug.Assert(genericConstructedGenericType.IsConstructedGenericType); + _asType = genericConstructedGenericType; + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_CustomAttributes(this); + + return GenericTypeDefinitionTypeInfo.CustomAttributes; + } + } + + public sealed override bool Equals(Object obj) + { + RuntimeConstructedGenericTypeInfo other = obj as RuntimeConstructedGenericTypeInfo; + if (other == null) + return false; + return _asType.Equals(other._asType); + } + + public sealed override int GetHashCode() + { + return _asType.GetHashCode(); + } + + public sealed override Guid GUID + { + get + { + return GenericTypeDefinitionTypeInfo.GUID; + } + } + + public sealed override bool IsGenericType + { + get + { + return true; + } + } + + public sealed override Assembly Assembly + { + get + { + return GenericTypeDefinitionTypeInfo.Assembly; + } + } + + public sealed override TypeAttributes Attributes + { + get + { + return GenericTypeDefinitionTypeInfo.Attributes; + } + } + + public sealed override IEnumerable<TypeInfo> DeclaredNestedTypes + { + get + { + return GenericTypeDefinitionTypeInfo.DeclaredNestedTypes; + } + } + + // + // Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties. + // The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this" + // and substituting the value of this.TypeContext into any generic parameters. + // + // Default implementation returns null which causes the Declared*** properties to return no members. + // + // Note that this does not apply to DeclaredNestedTypes. Nested types and their containers have completely separate generic instantiation environments + // (despite what C# might lead you to think.) Constructed generic types return the exact same same nested types that its generic type definition does + // - i.e. their DeclaringTypes refer back to the generic type definition, not the constructed generic type.) + // + // Note also that we cannot use this anchoring concept for base types because of generic parameters. Generic parameters return + // baseclass and interfaces based on its constraints. + // + internal sealed override RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers + { + get + { + RuntimeTypeInfo genericTypeDefinition = this.GenericTypeDefinitionTypeInfo; + RuntimeNamedTypeInfo genericTypeDefinitionNamedTypeInfo = genericTypeDefinition as RuntimeNamedTypeInfo; + if (genericTypeDefinitionNamedTypeInfo == null) + throw this.ReflectionDomain.CreateMissingMetadataException(genericTypeDefinition); + return genericTypeDefinitionNamedTypeInfo; + } + } + + internal sealed override RuntimeType RuntimeType + { + get + { + return _asType; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + return this.GenericTypeDefinitionTypeInfo.TypeRefDefOrSpecForBaseType; + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + return this.GenericTypeDefinitionTypeInfo.TypeRefDefOrSpecsForDirectlyImplementedInterfaces; + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + return new TypeContext(this.RuntimeType.InternalRuntimeGenericTypeArguments, null); + } + } + + private RuntimeTypeInfo GenericTypeDefinitionTypeInfo + { + get + { + return GetGenericTypeDefinition().GetRuntimeTypeInfo<RuntimeTypeInfo>(); + } + } + + private RuntimeType _asType; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs new file mode 100644 index 000000000..37d14337c --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.MethodInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + internal sealed partial class RuntimeGenericParameterTypeInfo : RuntimeTypeInfo + { + private RuntimeGenericParameterTypeInfo(RuntimeGenericParameterType asType) + { + _asType = asType; + } + + public sealed override Assembly Assembly + { + get + { + return DeclaringType.GetTypeInfo().Assembly; + } + } + + public sealed override TypeAttributes Attributes + { + get + { + return TypeAttributes.Public; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_CustomAttributes(this); + + return _asType.CustomAttributes; + } + } + + public sealed override MethodBase DeclaringMethod + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaringMethod(this); + + return _asType.DeclaringMethod; + } + } + + public sealed override GenericParameterAttributes GenericParameterAttributes + { + get + { + return _asType.GenericParameterAttributes; + } + } + + public sealed override Type[] GetGenericParameterConstraints() + { + TypeInfo[] constraintInfos = ConstraintInfos; + if (constraintInfos.Length == 0) + return Array.Empty<Type>(); + Type[] result = new Type[constraintInfos.Length]; + for (int i = 0; i < constraintInfos.Length; i++) + result[i] = constraintInfos[i].AsType(); + return result; + } + + public sealed override bool Equals(Object obj) + { + RuntimeGenericParameterTypeInfo other = obj as RuntimeGenericParameterTypeInfo; + if (other == null) + return false; + return this._asType.Equals(other._asType); + } + + public sealed override int GetHashCode() + { + return _asType.GetHashCode(); + } + + internal sealed override RuntimeType RuntimeType + { + get + { + return _asType; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + QTypeDefRefOrSpec[] constraints = Constraints; + TypeInfo[] constraintInfos = ConstraintInfos; + for (int i = 0; i < constraints.Length; i++) + { + TypeInfo constraintInfo = constraintInfos[i]; + if (constraintInfo.IsInterface) + continue; + return constraints[i]; + } + + RuntimeNamedTypeInfo objectTypeInfo = this.ReflectionDomain.FoundationTypes.SystemObject.GetRuntimeTypeInfo<RuntimeNamedTypeInfo>(); + return new QTypeDefRefOrSpec(objectTypeInfo.Reader, objectTypeInfo.TypeDefinitionHandle); + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + LowLevelList<QTypeDefRefOrSpec> result = new LowLevelList<QTypeDefRefOrSpec>(); + QTypeDefRefOrSpec[] constraints = Constraints; + TypeInfo[] constraintInfos = ConstraintInfos; + for (int i = 0; i < constraints.Length; i++) + { + if (constraintInfos[i].IsInterface) + result.Add(constraints[i]); + } + return result.ToArray(); + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + return _asType.TypeContext; + } + } + + private QTypeDefRefOrSpec[] Constraints + { + get + { + MetadataReader reader = _asType.Reader; + LowLevelList<QTypeDefRefOrSpec> constraints = new LowLevelList<QTypeDefRefOrSpec>(); + foreach (Handle constraintHandle in _asType.GenericParameterHandle.GetGenericParameter(_asType.Reader).Constraints) + { + constraints.Add(new QTypeDefRefOrSpec(reader, constraintHandle)); + } + return constraints.ToArray(); + } + } + + private TypeInfo[] ConstraintInfos + { + get + { + QTypeDefRefOrSpec[] constraints = Constraints; + if (constraints.Length == 0) + return Array.Empty<TypeInfo>(); + TypeInfo[] constraintInfos = new TypeInfo[constraints.Length]; + ReflectionDomain reflectionDomain = this.ReflectionDomain; + for (int i = 0; i < constraints.Length; i++) + { + constraintInfos[i] = reflectionDomain.Resolve(constraints[i].Reader, constraints[i].Handle, TypeContext).GetTypeInfo(); + } + return constraintInfos; + } + } + + private RuntimeGenericParameterType _asType; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs new file mode 100644 index 000000000..102d49008 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // The runtime's implementation of TypeInfo's for the "HasElement" subclass of types. + // + // For now, only Array has its own base class below this - that's the only with that implements anything differently. + // + internal partial class RuntimeHasElementTypeInfo : RuntimeTypeInfo + { + protected RuntimeHasElementTypeInfo(RuntimeType hasElementType) + : base() + { + Debug.Assert(hasElementType.HasElementType); + _asType = hasElementType; + } + + public sealed override bool Equals(Object obj) + { + RuntimeHasElementTypeInfo other = obj as RuntimeHasElementTypeInfo; + if (other == null) + return false; + return _asType.Equals(other._asType); + } + + public sealed override int GetHashCode() + { + return _asType.GetHashCode(); + } + + public sealed override Assembly Assembly + { + get + { + return ElementTypeInfo.Assembly; + } + } + + // + // Left unsealed because this implemention is correct for ByRefs and Pointers but not Arrays. + // + public override TypeAttributes Attributes + { + get + { + Debug.Assert(IsByRef || IsPointer); + return TypeAttributes.AnsiClass; + } + } + + internal sealed override RuntimeType RuntimeType + { + get + { + return _asType; + } + } + + private RuntimeType _asType; + + private RuntimeTypeInfo ElementTypeInfo + { + get + { + if (_elementTypeInfo == null) + { + _elementTypeInfo = _asType.InternalRuntimeElementType.GetRuntimeTypeInfo(); + } + return _elementTypeInfo; + } + } + + private volatile RuntimeTypeInfo _elementTypeInfo; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs new file mode 100644 index 000000000..db5caad62 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs @@ -0,0 +1,364 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Collections.Concurrent; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // TypeInfos that represent type definitions (i.e. Foo or Foo<>, but not Foo<int> or arrays/pointers/byrefs.) + // + // + internal sealed partial class RuntimeNamedTypeInfo : RuntimeTypeInfo, IEquatable<RuntimeNamedTypeInfo> + { + private RuntimeNamedTypeInfo(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle) + { + _reader = reader; + _typeDefinitionHandle = typeDefinitionHandle; + _typeDefinition = _typeDefinitionHandle.GetTypeDefinition(reader); + } + + public sealed override Assembly Assembly + { + get + { + // If an assembly is split across multiple metadata blobs then the defining scope may + // not be the canonical scope representing the assembly. We need to look up the assembly + // by name to ensure we get the right one. + + ScopeDefinitionHandle scopeDefinitionHandle = NamespaceChain.DefiningScope; + RuntimeAssemblyName runtimeAssemblyName = scopeDefinitionHandle.ToRuntimeAssemblyName(_reader); + + return RuntimeAssembly.GetRuntimeAssembly(this.ReflectionDomain, runtimeAssemblyName); + } + } + + public sealed override TypeAttributes Attributes + { + get + { + TypeAttributes attr = _typeDefinition.Flags; + return attr; + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_CustomAttributes(this); + + IEnumerable<CustomAttributeData> customAttributes = RuntimeCustomAttributeData.GetCustomAttributes(this.ReflectionDomain, _reader, _typeDefinition.CustomAttributes); + foreach (CustomAttributeData cad in customAttributes) + yield return cad; + ExecutionDomain executionDomain = this.ReflectionDomain as ExecutionDomain; + if (executionDomain != null) + { + foreach (CustomAttributeData cad in executionDomain.ExecutionEnvironment.GetPsuedoCustomAttributes(_reader, _typeDefinitionHandle)) + { + yield return cad; + } + } + } + } + + public sealed override IEnumerable<TypeInfo> DeclaredNestedTypes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredNestedTypes(this); + + foreach (TypeDefinitionHandle nestedTypeHandle in _typeDefinition.NestedTypes) + { + yield return RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(_reader, nestedTypeHandle); + } + } + } + + public sealed override bool Equals(Object obj) + { + if (Object.ReferenceEquals(this, obj)) + return true; + + RuntimeNamedTypeInfo other = obj as RuntimeNamedTypeInfo; + if (!Equals(other)) + return false; + return true; + } + + public bool Equals(RuntimeNamedTypeInfo other) + { + if (other == null) + return false; + if (this._reader != other._reader) + return false; + if (!(this._typeDefinitionHandle.Equals(other._typeDefinitionHandle))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _typeDefinitionHandle.GetHashCode(); + } + + public sealed override Guid GUID + { + get + { + // + // Look for a [Guid] attribute. If found, return that. + // + foreach (CustomAttributeHandle cah in _typeDefinition.CustomAttributes) + { + // We can't reference the GuidAttribute class directly as we don't have an official dependency on System.Runtime.InteropServices. + // Following age-old CLR tradition, we search for the custom attribute using a name-based search. Since this makes it harder + // to be sure we won't run into custom attribute constructors that comply with the GuidAttribute(String) signature, + // we'll check that it does and silently skip the CA if it doesn't match the expected pattern. + if (cah.IsCustomAttributeOfType(_reader, "System.Runtime.InteropServices", "GuidAttribute")) + { + CustomAttribute ca = cah.GetCustomAttribute(_reader); + IEnumerator<FixedArgumentHandle> fahEnumerator = ca.FixedArguments.GetEnumerator(); + if (!fahEnumerator.MoveNext()) + continue; + FixedArgumentHandle guidStringArgumentHandle = fahEnumerator.Current; + if (fahEnumerator.MoveNext()) + continue; + FixedArgument guidStringArgument = guidStringArgumentHandle.GetFixedArgument(_reader); + String guidString = guidStringArgument.Value.ParseConstantValue(this.ReflectionDomain, _reader) as String; + if (guidString == null) + continue; + return new Guid(guidString); + } + } + + // + // If we got here, there was no [Guid] attribute. + // + // Ideally, we'd now compute the same GUID the desktop returns - however, that algorithm is complex and has questionable dependencies + // (in particular, the GUID changes if the language compilers ever change the way it emits metadata tokens into certain unordered lists. + // We don't even retain that order across the Project N toolchain.) + // + // For now, this is a compromise that satisfies our app-compat goals. We ensure that each unique Type receives a different GUID (at least one app + // uses the GUID as a dictionary key to look up types.) It will not be the same GUID on multiple runs of the app but so far, there's + // no evidence that's needed. + // + return _namedTypeToGuidTable.GetOrAdd(this).Item1; + } + } + + public sealed override bool IsGenericTypeDefinition + { + get + { + return _typeDefinition.GenericParameters.GetEnumerator().MoveNext(); + } + } + + public sealed override bool IsGenericType + { + get + { + return _typeDefinition.GenericParameters.GetEnumerator().MoveNext(); + } + } + + // + // Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties. + // The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this" + // and substituting the value of this.TypeContext into any generic parameters. + // + // Default implementation returns null which causes the Declared*** properties to return no members. + // + // Note that this does not apply to DeclaredNestedTypes. Nested types and their containers have completely separate generic instantiation environments + // (despite what C# might lead you to think.) Constructed generic types return the exact same same nested types that its generic type definition does + // - i.e. their DeclaringTypes refer back to the generic type definition, not the constructed generic type.) + // + // Note also that we cannot use this anchoring concept for base types because of generic parameters. Generic parameters return + // baseclass and interfaces based on its constraints. + // + internal sealed override RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers + { + get + { + return this; + } + } + + internal sealed override RuntimeType[] RuntimeGenericTypeParameters + { + get + { + LowLevelList<RuntimeType> genericTypeParameters = new LowLevelList<RuntimeType>(); + + foreach (GenericParameterHandle genericParameterHandle in _typeDefinition.GenericParameters) + { + RuntimeType genericParameterType = RuntimeTypeUnifierEx.GetRuntimeGenericParameterTypeForTypes(this, genericParameterHandle); + genericTypeParameters.Add(genericParameterType); + } + + return genericTypeParameters.ToArray(); + } + } + + internal sealed override RuntimeType RuntimeType + { + get + { + if (_lazyType == null) + { + _lazyType = this.ReflectionDomain.ResolveTypeDefinition(_reader, _typeDefinitionHandle); + } + return _lazyType; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + Handle baseType = _typeDefinition.BaseType; + if (baseType.IsNull(_reader)) + return QTypeDefRefOrSpec.Null; + return new QTypeDefRefOrSpec(_reader, baseType); + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + LowLevelList<QTypeDefRefOrSpec> directlyImplementedInterfaces = new LowLevelList<QTypeDefRefOrSpec>(); + foreach (Handle ifcHandle in _typeDefinition.Interfaces) + directlyImplementedInterfaces.Add(new QTypeDefRefOrSpec(_reader, ifcHandle)); + return directlyImplementedInterfaces.ToArray(); + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + return new TypeContext(this.RuntimeGenericTypeParameters, null); + } + } + + internal MetadataReader Reader + { + get + { + return _reader; + } + } + + internal TypeDefinitionHandle TypeDefinitionHandle + { + get + { + return _typeDefinitionHandle; + } + } + + internal IEnumerable<MethodHandle> DeclaredConstructorHandles + { + get + { + foreach (MethodHandle methodHandle in _typeDefinition.Methods) + { + if (methodHandle.IsConstructor(_reader)) + yield return methodHandle; + } + } + } + + internal IEnumerable<EventHandle> DeclaredEventHandles + { + get + { + return _typeDefinition.Events; + } + } + + internal IEnumerable<FieldHandle> DeclaredFieldHandles + { + get + { + return _typeDefinition.Fields; + } + } + + internal IEnumerable<MethodHandle> DeclaredMethodAndConstructorHandles + { + get + { + return _typeDefinition.Methods; + } + } + + internal IEnumerable<PropertyHandle> DeclaredPropertyHandles + { + get + { + return _typeDefinition.Properties; + } + } + + private MetadataReader _reader; + private TypeDefinitionHandle _typeDefinitionHandle; + private TypeDefinition _typeDefinition; + + private NamespaceChain NamespaceChain + { + get + { + if (_lazyNamespaceChain == null) + _lazyNamespaceChain = new NamespaceChain(_reader, _typeDefinition.NamespaceDefinition); + return _lazyNamespaceChain; + } + } + + private volatile NamespaceChain _lazyNamespaceChain; + + private volatile RuntimeType _lazyType; + + private static NamedTypeToGuidTable _namedTypeToGuidTable = new NamedTypeToGuidTable(); + private sealed class NamedTypeToGuidTable : ConcurrentUnifier<RuntimeNamedTypeInfo, Tuple<Guid>> + { + protected sealed override Tuple<Guid> Factory(RuntimeNamedTypeInfo key) + { + return new Tuple<Guid>(Guid.NewGuid()); + } + } + } +} + + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs new file mode 100644 index 000000000..09258efd3 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Assemblies; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // TypeInfos that represent type definitions (i.e. Foo or Foo<>, but not Foo<int> or arrays/pointers/byrefs.) + // that not opted into pay-for-play metadata. + // + internal sealed partial class RuntimeNoMetadataNamedTypeInfo : RuntimeTypeInfo + { + private RuntimeNoMetadataNamedTypeInfo(RuntimeType runtimeType) + { + _asType = runtimeType; + } + + public sealed override Assembly Assembly + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override TypeAttributes Attributes + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override IEnumerable<TypeInfo> DeclaredNestedTypes + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override bool Equals(Object obj) + { + if (Object.ReferenceEquals(this, obj)) + return true; + + RuntimeNoMetadataNamedTypeInfo other = obj as RuntimeNoMetadataNamedTypeInfo; + if (other == null) + return false; + if (!(this._asType.Equals(other._asType))) + return false; + return true; + } + + public sealed override int GetHashCode() + { + return _asType.GetHashCode(); + } + + public sealed override Guid GUID + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + public sealed override bool IsGenericType + { + get + { + return _asType.IsConstructedGenericType || this.IsGenericTypeDefinition; + } + } + + public sealed override bool IsGenericTypeDefinition + { + get + { + return _asType.InternalIsGenericTypeDefinition; + } + } + + // + // Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties. + // The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this" + // and substituting the value of this.TypeContext into any generic parameters. + // + // Default implementation returns null which causes the Declared*** properties to return no members. + // + // Note that this does not apply to DeclaredNestedTypes. Nested types and their containers have completely separate generic instantiation environments + // (despite what C# might lead you to think.) Constructed generic types return the exact same same nested types that its generic type definition does + // - i.e. their DeclaringTypes refer back to the generic type definition, not the constructed generic type.) + // + // Note also that we cannot use this anchoring concept for base types because of generic parameters. Generic parameters return + // baseclass and interfaces based on its constraints. + // + internal sealed override RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + internal sealed override RuntimeType[] RuntimeGenericTypeParameters + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + internal sealed override RuntimeType RuntimeType + { + get + { + return _asType; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal sealed override QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal sealed override QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal sealed override TypeContext TypeContext + { + get + { + throw this.ReflectionDomain.CreateMissingMetadataException(this); + } + } + + private RuntimeType _asType; + } +} + + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs new file mode 100644 index 000000000..777987640 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -0,0 +1,1003 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.FieldInfos; +using global::System.Reflection.Runtime.PropertyInfos; +using global::System.Reflection.Runtime.EventInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using global::Internal.Reflection.Extensibility; +using global::Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + // + // Abstract base class for all TypeInfo's implemented by the runtime. + // + // This base class performs several services: + // + // - Provides default implementations that delegate to AsType() when possible and + // returns the "common" error result for narrowly applicable properties (such as those + // that apply only to generic parameters.) + // + // - Inverts the DeclaredMembers/DeclaredX relationship (DeclaredMembers is auto-implemented, others + // are overriden as abstract. This ordering makes more sense when reading from metadata.) + // + // - Overrides many "NotImplemented" members in TypeInfo with abstracts so failure to implement + // shows up as build error. + // + internal abstract partial class RuntimeTypeInfo : ExtensibleTypeInfo, ITraceableTypeMember + { + protected RuntimeTypeInfo() + { + } + + public sealed override String AssemblyQualifiedName + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_AssemblyQualifiedName(this); + + return AsType().AssemblyQualifiedName; + } + } + + public sealed override Type AsType() + { + return this.RuntimeType; + } + + public sealed override bool IsCOMObject + { + get + { + return ReflectionCoreExecution.ExecutionEnvironment.IsCOMObject(this.RuntimeType); + } + } + + public sealed override Type BaseType + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_BaseType(this); + + // If this has a RuntimeTypeHandle, let the underlying runtime engine have the first crack. If it refuses, fall back to metadata. + RuntimeTypeHandle typeHandle; + if (this.RuntimeType.InternalTryGetTypeHandle(out typeHandle)) + { + RuntimeTypeHandle baseTypeHandle; + if (ReflectionCoreExecution.ExecutionEnvironment.TryGetBaseType(typeHandle, out baseTypeHandle)) + return Type.GetTypeFromHandle(baseTypeHandle); + } + + Type baseType = BaseTypeWithoutTheGenericParameterQuirk; + if (baseType != null && baseType.IsGenericParameter) + { + // Desktop quirk: a generic parameter whose constraint is another generic parameter reports its BaseType as System.Object + // unless that other generic parameter has a "class" constraint. + GenericParameterAttributes genericParameterAttributes = baseType.GetTypeInfo().GenericParameterAttributes; + if (0 == (genericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint)) + baseType = this.ReflectionDomain.FoundationTypes.SystemObject; + } + return baseType; + } + } + + public sealed override bool ContainsGenericParameters + { + get + { + return this.RuntimeType.InternalIsOpen; + } + } + + // + // Left unsealed so that RuntimeNamedTypeInfo and RuntimeConstructedGenericTypeInfo and RuntimeGenericParameterTypeInfo can override. + // + public override IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_CustomAttributes(this); + + Debug.Assert(IsArray || IsByRef || IsPointer); + return Empty<CustomAttributeData>.Enumerable; + } + } + + public sealed override IEnumerable<ConstructorInfo> DeclaredConstructors + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredConstructors(this); + + return GetDeclaredConstructorsInternal(this.AnchoringTypeDefinitionForDeclaredMembers); + } + } + + public sealed override IEnumerable<EventInfo> DeclaredEvents + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredEvents(this); + + return GetDeclaredEventsInternal(this.AnchoringTypeDefinitionForDeclaredMembers, null); + } + } + + public sealed override IEnumerable<FieldInfo> DeclaredFields + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredFields(this); + + return GetDeclaredFieldsInternal(this.AnchoringTypeDefinitionForDeclaredMembers, null); + } + } + + public sealed override IEnumerable<MemberInfo> DeclaredMembers + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredMembers(this); + + return GetDeclaredMembersInternal( + this.DeclaredMethods, + this.DeclaredConstructors, + this.DeclaredProperties, + this.DeclaredEvents, + this.DeclaredFields, + this.DeclaredNestedTypes); + } + } + + public sealed override IEnumerable<MethodInfo> DeclaredMethods + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredMethods(this); + + return GetDeclaredMethodsInternal(this.AnchoringTypeDefinitionForDeclaredMembers, null); + } + } + + // + // Left unsealed as named types must override. + // + public override IEnumerable<TypeInfo> DeclaredNestedTypes + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredNestedTypes(this); + + Debug.Assert(!(this is RuntimeNamedTypeInfo)); + return Empty<TypeInfo>.Enumerable; + } + } + + public sealed override IEnumerable<PropertyInfo> DeclaredProperties + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_DeclaredProperties(this); + + return GetDeclaredPropertiesInternal(this.AnchoringTypeDefinitionForDeclaredMembers, null); + } + } + + // + // Left unsealed as generic parameter types must override. + // + public override MethodBase DeclaringMethod + { + get + { + Debug.Assert(!IsGenericParameter); + throw new InvalidOperationException(SR.Arg_NotGenericParameter); + } + } + + public abstract override bool Equals(Object obj); + public abstract override int GetHashCode(); + + public sealed override String FullName + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_FullName(this); + + return AsType().FullName; + } + } + + // + // Left unsealed as generic parameter types must override. + // + public override GenericParameterAttributes GenericParameterAttributes + { + get + { + Debug.Assert(!IsGenericParameter); + throw new InvalidOperationException(SR.Arg_NotGenericParameter); + } + } + + public sealed override int GenericParameterPosition + { + get + { + return AsType().GenericParameterPosition; + } + } + + public sealed override Type[] GenericTypeArguments + { + get + { + return AsType().GenericTypeArguments; + } + } + + public sealed override EventInfo GetDeclaredEvent(String name) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_GetDeclaredEvent(this, name); + + if (name == null) + throw new ArgumentNullException("name"); + + TypeInfoCachedData cachedData = this.TypeInfoCachedData; + return cachedData.GetDeclaredEvent(name); + } + + public sealed override FieldInfo GetDeclaredField(String name) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_GetDeclaredField(this, name); + + if (name == null) + throw new ArgumentNullException("name"); + + TypeInfoCachedData cachedData = this.TypeInfoCachedData; + return cachedData.GetDeclaredField(name); + } + + public sealed override MethodInfo GetDeclaredMethod(String name) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_GetDeclaredMethod(this, name); + + if (name == null) + throw new ArgumentNullException("name"); + + TypeInfoCachedData cachedData = this.TypeInfoCachedData; + return cachedData.GetDeclaredMethod(name); + } + + public sealed override PropertyInfo GetDeclaredProperty(String name) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_GetDeclaredProperty(this, name); + + if (name == null) + throw new ArgumentNullException("name"); + + TypeInfoCachedData cachedData = this.TypeInfoCachedData; + return cachedData.GetDeclaredProperty(name); + } + + // + // Implements the correct GUID behavior for all "constructed" types (i.e. returning an all-zero GUID.) Left unsealed + // so that RuntimeNamedTypeInfo can override. + // + public override Guid GUID + { + get + { + return Guid.Empty; + } + } + + public sealed override IEnumerable<Type> ImplementedInterfaces + { + get + { + LowLevelListWithIList<Type> result = new LowLevelListWithIList<Type>(); + + bool done = false; + + // If this has a RuntimeTypeHandle, let the underlying runtime engine have the first crack. If it refuses, fall back to metadata. + RuntimeTypeHandle typeHandle; + + if (this.RuntimeType.InternalTryGetTypeHandle(out typeHandle)) + { + IEnumerable<RuntimeTypeHandle> implementedInterfaces = ReflectionCoreExecution.ExecutionEnvironment.TryGetImplementedInterfaces(typeHandle); + if (implementedInterfaces != null) + { + done = true; + + foreach (RuntimeTypeHandle th in implementedInterfaces) + { + result.Add(Type.GetTypeFromHandle(th)); + } + } + } + + if (!done) + { + TypeContext typeContext = this.TypeContext; + Type baseType = this.BaseTypeWithoutTheGenericParameterQuirk; + if (baseType != null) + result.AddRange(baseType.GetTypeInfo().ImplementedInterfaces); + ReflectionDomain reflectionDomain = this.ReflectionDomain; + foreach (QTypeDefRefOrSpec directlyImplementedInterface in this.TypeRefDefOrSpecsForDirectlyImplementedInterfaces) + { + Type ifc = reflectionDomain.Resolve(directlyImplementedInterface.Reader, directlyImplementedInterface.Handle, typeContext); + if (result.Contains(ifc)) + continue; + result.Add(ifc); + foreach (Type indirectIfc in ifc.GetTypeInfo().ImplementedInterfaces) + { + if (result.Contains(indirectIfc)) + continue; + result.Add(indirectIfc); + } + } + } + + return result.AsNothingButIEnumerable(); + } + } + + public sealed override bool IsAssignableFrom(TypeInfo typeInfo) + { + RuntimeTypeInfo toTypeInfo = this; + RuntimeTypeInfo fromTypeInfo = typeInfo as RuntimeTypeInfo; + + if (fromTypeInfo == null) + return false; // Desktop compat: If typeInfo is null, or implemented by a different Reflection implementation, return "false." + + if (toTypeInfo.ReflectionDomain != fromTypeInfo.ReflectionDomain) + return false; + + if (toTypeInfo.Equals(fromTypeInfo)) + return true; + + RuntimeTypeHandle toTypeHandle = default(RuntimeTypeHandle); + RuntimeTypeHandle fromTypeHandle = default(RuntimeTypeHandle); + bool haveTypeHandles = toTypeInfo.RuntimeType.InternalTryGetTypeHandle(out toTypeHandle) && fromTypeInfo.RuntimeType.InternalTryGetTypeHandle(out fromTypeHandle); + if (haveTypeHandles) + { + // If both types have type handles, let MRT handle this. It's not dependent on metadata. + if (ReflectionCoreExecution.ExecutionEnvironment.IsAssignableFrom(toTypeHandle, fromTypeHandle)) + return true; + + // Runtime IsAssignableFrom does not handle casts from generic type definitions: always returns false. For those, we fall through to the + // managed implementation. For everyone else, return "false". + // + // Runtime IsAssignableFrom does not handle pointer -> UIntPtr cast. + if (!(fromTypeInfo.IsGenericTypeDefinition || fromTypeInfo.IsPointer)) + return false; + } + + // If we got here, the types are open, or reduced away, or otherwise lacking in type handles. Perform the IsAssignability check in managed code. + return Assignability.IsAssignableFrom(this, typeInfo, fromTypeInfo.ReflectionDomain.FoundationTypes); + } + + public sealed override bool IsEnum + { + get + { + return 0 != (Classification & TypeClassification.IsEnum); + } + } + + public sealed override bool IsGenericParameter + { + get + { + return AsType().IsGenericParameter; + } + } + + // + // Left unsealed as generic type definitions and constructed generic types must override. + // + public override bool IsGenericType + { + get + { + return false; + } + } + + // + // Left unsealed as generic type definitions must override. + // + public override bool IsGenericTypeDefinition + { + get + { + return false; + } + } + + public sealed override bool IsPrimitive + { + get + { + return 0 != (Classification & TypeClassification.IsPrimitive); + } + } + + public sealed override bool IsSerializable + { + get + { + return 0 != (this.Attributes & TypeAttributes.Serializable); + } + } + + public sealed override bool IsValueType + { + get + { + return 0 != (Classification & TypeClassification.IsValueType); + } + } + + public sealed override Module Module + { + get + { + return Assembly.ManifestModule; + } + } + + public sealed override String Namespace + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_Namespace(this); + + return AsType().Namespace; + } + } + + public sealed override Type[] GenericTypeParameters + { + get + { + RuntimeType[] genericTypeParameters = RuntimeGenericTypeParameters; + if (genericTypeParameters.Length == 0) + return Array.Empty<Type>(); + Type[] result = new Type[genericTypeParameters.Length]; + for (int i = 0; i < genericTypeParameters.Length; i++) + result[i] = genericTypeParameters[i]; + return result; + } + } + + public sealed override int GetArrayRank() + { + return AsType().GetArrayRank(); + } + + public sealed override Type GetElementType() + { + return AsType().GetElementType(); + } + + // + // Left unsealed as generic parameter types must override. + // + public override Type[] GetGenericParameterConstraints() + { + Debug.Assert(!IsGenericParameter); + throw new InvalidOperationException(SR.Arg_NotGenericParameter); + } + + public sealed override Type GetGenericTypeDefinition() + { + return AsType().GetGenericTypeDefinition(); + } + + public sealed override Type MakeArrayType() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_MakeArrayType(this); + + return AsType().MakeArrayType(); + } + + public sealed override Type MakeArrayType(int rank) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_MakeArrayType(this, rank); + + return AsType().MakeArrayType(rank); + } + + public sealed override Type MakeByRefType() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_MakeByRefType(this); + + return AsType().MakeByRefType(); + } + + public sealed override Type MakeGenericType(params Type[] typeArguments) + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_MakeGenericType(this, typeArguments); + + return AsType().MakeGenericType(typeArguments); + } + + public sealed override Type MakePointerType() + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_MakePointerType(this); + + return AsType().MakePointerType(); + } + + public sealed override Type DeclaringType + { + get + { + return this.InternalDeclaringType; + } + } + + public sealed override String Name + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.TypeInfo_Name(this); + + return this.InternalName; + } + } + + public sealed override String ToString() + { + return AsType().ToString(); + } + + + String ITraceableTypeMember.MemberName + { + get + { + return this.InternalName; + } + } + + Type ITraceableTypeMember.ContainingType + { + get + { + return this.InternalDeclaringType; + } + } + + // + // The non-public version of AsType(). + // + internal abstract RuntimeType RuntimeType { get; } + + internal ReflectionDomain ReflectionDomain + { + get + { + return ReflectionCoreExecution.ExecutionDomain; //@todo: User Reflection Domains not yet supported. + } + } + + // + // Returns the anchoring typedef that declares the members that this type wants returned by the Declared*** properties. + // The Declared*** properties will project the anchoring typedef's members by overriding their DeclaringType property with "this" + // and substituting the value of this.TypeContext into any generic parameters. + // + // Default implementation returns null which causes the Declared*** properties to return no members. + // + // Note that this does not apply to DeclaredNestedTypes. Nested types and their containers have completely separate generic instantiation environments + // (despite what C# might lead you to think.) Constructed generic types return the exact same same nested types that its generic type definition does + // - i.e. their DeclaringTypes refer back to the generic type definition, not the constructed generic type.) + // + // Note also that we cannot use this anchoring concept for base types because of generic parameters. Generic parameters return + // a base class and interface list based on its constraints. + // + internal virtual RuntimeNamedTypeInfo AnchoringTypeDefinitionForDeclaredMembers + { + get + { + return null; + } + } + + // + // Return all declared events whose name matches "optionalNameFilter". If optionalNameFilter is null, return them all. + // + internal IEnumerable<RuntimeEventInfo> GetDeclaredEventsInternal(RuntimeNamedTypeInfo definingType, String optionalNameFilter) + { + if (definingType != null) + { + // We require the caller to pass a value that we could calculate ourselves because we're an iterator and we + // don't want any MissingMetadataException that AnchoringType throws to be deferred. + Debug.Assert(definingType.Equals(this.AnchoringTypeDefinitionForDeclaredMembers)); + + MetadataReader reader = definingType.Reader; + foreach (EventHandle eventHandle in definingType.DeclaredEventHandles) + { + if (optionalNameFilter == null || eventHandle.GetEvent(reader).Name.StringEquals(optionalNameFilter, reader)) + yield return RuntimeEventInfo.GetRuntimeEventInfo(eventHandle, definingType, this); + } + } + } + + // + // Return all declared fields whose name matches "optionalNameFilter". If optionalNameFilter is null, return them all. + // + internal IEnumerable<RuntimeFieldInfo> GetDeclaredFieldsInternal(RuntimeNamedTypeInfo definingType, String optionalNameFilter) + { + if (definingType != null) + { + // We require the caller to pass a value that we could calculate ourselves because we're an iterator and we + // don't want any MissingMetadataException that AnchoringType throws to be deferred. + Debug.Assert(definingType.Equals(this.AnchoringTypeDefinitionForDeclaredMembers)); + + MetadataReader reader = definingType.Reader; + foreach (FieldHandle fieldHandle in definingType.DeclaredFieldHandles) + { + if (optionalNameFilter == null || fieldHandle.GetField(reader).Name.StringEquals(optionalNameFilter, reader)) + yield return RuntimeFieldInfo.GetRuntimeFieldInfo(fieldHandle, definingType, this); + } + } + } + + // + // Return all declared methods whose name matches "optionalNameFilter". If optionalNameFilter is null, return them all. + // + internal IEnumerable<RuntimeMethodInfo> GetDeclaredMethodsInternal(RuntimeNamedTypeInfo definingType, String optionalNameFilter) + { + if (definingType != null) + { + // We require the caller to pass a value that we could calculate ourselves because we're an iterator and we + // don't want any MissingMetadataException that AnchoringType throws to be deferred. + Debug.Assert(definingType.Equals(this.AnchoringTypeDefinitionForDeclaredMembers)); + + MetadataReader reader = definingType.Reader; + foreach (MethodHandle methodHandle in definingType.DeclaredMethodAndConstructorHandles) + { + Method method = methodHandle.GetMethod(reader); + + if ((optionalNameFilter != null) && !method.Name.StringEquals(optionalNameFilter, reader)) + continue; + + if (MetadataReaderExtensions.IsConstructor(ref method, reader)) + continue; + yield return RuntimeNamedMethodInfo.GetRuntimeNamedMethodInfo(methodHandle, definingType, this); + } + } + + foreach (RuntimeMethodInfo syntheticMethod in SyntheticMethods) + { + if (optionalNameFilter == null || optionalNameFilter == syntheticMethod.Name) + { + yield return syntheticMethod; + } + } + } + + // + // Return all declared properties whose name matches "optionalNameFilter". If optionalNameFilter is null, return them all. + // + internal IEnumerable<RuntimePropertyInfo> GetDeclaredPropertiesInternal(RuntimeNamedTypeInfo definingType, String optionalNameFilter) + { + if (definingType != null) + { + // We require the caller to pass a value that we could calculate ourselves because we're an iterator and we + // don't want any MissingMetadataException that AnchoringType throws to be deferred. + Debug.Assert(definingType.Equals(this.AnchoringTypeDefinitionForDeclaredMembers)); + + MetadataReader reader = definingType.Reader; + foreach (PropertyHandle propertyHandle in definingType.DeclaredPropertyHandles) + { + if (optionalNameFilter == null || propertyHandle.GetProperty(reader).Name.StringEquals(optionalNameFilter, reader)) + yield return RuntimePropertyInfo.GetRuntimePropertyInfo(propertyHandle, definingType, this); + } + } + } + + + // + // The non-public version of TypeInfo.GenericTypeParameters (does not array-copy.) + // + internal virtual RuntimeType[] RuntimeGenericTypeParameters + { + get + { + Debug.Assert(!(this is RuntimeNamedTypeInfo)); + return Array.Empty<RuntimeType>(); + } + } + + // + // Normally returns empty: Overridden by array types to return constructors. + // + internal virtual IEnumerable<RuntimeConstructorInfo> SyntheticConstructors + { + get + { + return Empty<RuntimeConstructorInfo>.Enumerable; + } + } + + // + // Normally returns empty: Overridden by array types to return the "Get" and "Set" methods. + // + internal virtual IEnumerable<RuntimeMethodInfo> SyntheticMethods + { + get + { + return Empty<RuntimeMethodInfo>.Enumerable; + } + } + + // + // Returns the base type as a typeDef, Ref, or Spec. Default behavior is to QTypeDefRefOrSpec.Null, which causes BaseType to return null. + // + internal virtual QTypeDefRefOrSpec TypeRefDefOrSpecForBaseType + { + get + { + return QTypeDefRefOrSpec.Null; + } + } + + // + // Returns the *directly implemented* interfaces as typedefs, specs or refs. ImplementedInterfaces will take care of the transitive closure and + // insertion of the TypeContext. + // + internal virtual QTypeDefRefOrSpec[] TypeRefDefOrSpecsForDirectlyImplementedInterfaces + { + get + { + return Array.Empty<QTypeDefRefOrSpec>(); + } + } + + // + // Returns the generic parameter substitutions to use when enumerating declared members, base class and implemented interfaces. + // + internal virtual TypeContext TypeContext + { + get + { + return new TypeContext(null, null); + } + } + + // + // Note: This can be (and is) called multiple times. We do not do this work in the constructor as calling ToString() + // in the constructor causes some serious recursion issues. + // + internal void EstablishDebugName() + { +#if DEBUG + if (_debugName == null) + { + _debugName = "Constructing..."; // Protect against any inadvertent reentrancy. + String debugName; + if (ReflectionTrace.Enabled) + debugName = this.GetTraceString(); // If tracing on, call this.GetTraceString() which only gives you useful strings when metadata is available but doesn't pollute the ETW trace. + else + debugName = this.ToString(); + if (debugName == null) + debugName = ""; + _debugName = debugName; + } +#endif + return; + } + + + private String InternalName + { + get + { + return this.RuntimeType.Name; + } + } + + private Type InternalDeclaringType + { + get + { + return this.RuntimeType.DeclaringType; + } + } + + // + // This internal method implements BaseType without the following desktop quirk: + // + // class Foo<X,Y> + // where X:Y + // where Y:MyReferenceClass + // + // The desktop reports "X"'s base type as "System.Object" rather than "Y", even though it does + // report any interfaces that are in MyReferenceClass's interface list. + // + // This seriously messes up the implementation of RuntimeTypeInfo.ImplementedInterfaces which assumes + // that it can recover the transitive interface closure by combining the directly mentioned interfaces and + // the BaseType's own interface closure. + // + // To implement this with the least amount of code smell, we'll implement the idealized version of BaseType here + // and make the special-case adjustment in the public version of BaseType. + // + private RuntimeType BaseTypeWithoutTheGenericParameterQuirk + { + get + { + QTypeDefRefOrSpec baseTypeDefRefOrSpec = TypeRefDefOrSpecForBaseType; + MetadataReader reader = baseTypeDefRefOrSpec.Reader; + RuntimeType baseType = null; + ReflectionDomain reflectionDomain = this.ReflectionDomain; + if (reader != null) + { + Handle typeDefRefOrSpec = baseTypeDefRefOrSpec.Handle; + baseType = reflectionDomain.Resolve(reader, typeDefRefOrSpec, this.TypeContext); + } + return baseType; + } + } + + // + // Returns a latched set of flags indicating the value of IsValueType, IsEnum, etc. + // + private TypeClassification Classification + { + get + { + if (_lazyClassification == 0) + { + TypeClassification classification = TypeClassification.Computed; + Type baseType = this.BaseType; + if (baseType != null) + { + FoundationTypes foundationTypes = this.ReflectionDomain.FoundationTypes; + Type enumType = foundationTypes.SystemEnum; + Type valueType = foundationTypes.SystemValueType; + + if (baseType.Equals(enumType)) + classification |= TypeClassification.IsEnum | TypeClassification.IsValueType; + if (baseType.Equals(valueType) && !(this.AsType().Equals(enumType))) + { + classification |= TypeClassification.IsValueType; + Type thisType = this.AsType(); + foreach (Type primitiveType in this.ReflectionDomain.PrimitiveTypes) + { + if (thisType.Equals(primitiveType)) + { + classification |= TypeClassification.IsPrimitive; + break; + } + } + } + } + _lazyClassification = classification; + } + return _lazyClassification; + } + } + + [Flags] + private enum TypeClassification + { + Computed = 0x00000001, // Always set (to indicate that the lazy evaluation has occurred) + IsValueType = 0x00000002, + IsEnum = 0x00000004, + IsPrimitive = 0x00000008, + } + + // + // Return all declared members. This may look like a silly code sequence to wrap inside a helper but we want to separate the iterator from + // the actual calls to get the sub-enumerations as we want any MissingMetadataException thrown by those + // calls to happen at the time DeclaredMembers is called. + // + private IEnumerable<MemberInfo> GetDeclaredMembersInternal( + IEnumerable<MethodInfo> methods, + IEnumerable<ConstructorInfo> constructors, + IEnumerable<PropertyInfo> properties, + IEnumerable<EventInfo> events, + IEnumerable<FieldInfo> fields, + IEnumerable<TypeInfo> nestedTypes + ) + { + foreach (MemberInfo member in methods) + yield return member; + foreach (MemberInfo member in constructors) + yield return member; + foreach (MemberInfo member in properties) + yield return member; + foreach (MemberInfo member in events) + yield return member; + foreach (MemberInfo member in fields) + yield return member; + foreach (MemberInfo member in nestedTypes) + yield return member; + } + + // + // Return all declared constructors. + // + private IEnumerable<RuntimeConstructorInfo> GetDeclaredConstructorsInternal(RuntimeNamedTypeInfo definingType) + { + if (definingType != null) + { + // We require the caller to pass a value that we could calculate ourselves because we're an iterator and we + // don't want any MissingMetadataException that AnchoringType throws to be deferred. + Debug.Assert(definingType.Equals(this.AnchoringTypeDefinitionForDeclaredMembers)); + + RuntimeTypeInfo contextType = this; + foreach (MethodHandle methodHandle in definingType.DeclaredConstructorHandles) + { + yield return RuntimePlainConstructorInfo.GetRuntimePlainConstructorInfo(methodHandle, definingType, contextType); + } + } + + foreach (RuntimeConstructorInfo syntheticConstructor in SyntheticConstructors) + { + yield return syntheticConstructor; + } + } + + private volatile TypeClassification _lazyClassification; + + private TypeInfoCachedData TypeInfoCachedData + { + get + { + TypeInfoCachedData cachedData = _lazyTypeInfoCachedData; + if (cachedData != null) + return cachedData; + _lazyTypeInfoCachedData = cachedData = new TypeInfoCachedData(this); + return cachedData; + } + } + + private volatile TypeInfoCachedData _lazyTypeInfoCachedData; + +#if DEBUG + private String _debugName; +#endif // DEBUG + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/TypeInfoCachedData.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/TypeInfoCachedData.cs new file mode 100644 index 000000000..0ac493414 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/TypeInfoCachedData.cs @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Types; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.Dispensers; +using global::System.Reflection.Runtime.FieldInfos; +using global::System.Reflection.Runtime.EventInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.PropertyInfos; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.TypeInfos +{ + //================================================================================================================ + // TypeInfoCachedData objects are allocated on-demand on a per-TypeInfo basis to cache hot data for key scenarios. + // To maximize throughput once the cache is created, the object creates all of its internal caches up front + // and holds entries strongly (and relying on the fact that TypeInfos themselves are held weakly to avoid immortality.) + // + // Note that it is possible that two threads racing to query the same TypeInfo may allocate and query two different + // CachedData objecs. Thus, this object must not be relied upon to preserve object identity. + //================================================================================================================ + internal sealed class TypeInfoCachedData + { + public TypeInfoCachedData(RuntimeTypeInfo runtimeTypeInfo) + { + _runtimeTypeInfo = runtimeTypeInfo; + _methodLookupDispenser = new DispenserThatAlwaysReuses<String, RuntimeMethodInfo>(LookupDeclaredMethodByName); + _fieldLookupDispenser = new DispenserThatAlwaysReuses<String, RuntimeFieldInfo>(LookupDeclaredFieldByName); + _propertyLookupDispenser = new DispenserThatAlwaysReuses<String, RuntimePropertyInfo>(LookupDeclaredPropertyByName); + _eventLookupDispenser = new DispenserThatAlwaysReuses<String, RuntimeEventInfo>(LookupDeclaredEventByName); + } + + public RuntimeMethodInfo GetDeclaredMethod(String name) + { + return _methodLookupDispenser.GetOrAdd(name); + } + + public RuntimeFieldInfo GetDeclaredField(String name) + { + return _fieldLookupDispenser.GetOrAdd(name); + } + + public RuntimePropertyInfo GetDeclaredProperty(String name) + { + return _propertyLookupDispenser.GetOrAdd(name); + } + + public RuntimeEventInfo GetDeclaredEvent(String name) + { + return _eventLookupDispenser.GetOrAdd(name); + } + + + private Dispenser<String, RuntimeMethodInfo> _methodLookupDispenser; + + private RuntimeMethodInfo LookupDeclaredMethodByName(String name) + { + RuntimeNamedTypeInfo definingType = _runtimeTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + IEnumerator<RuntimeMethodInfo> matches = _runtimeTypeInfo.GetDeclaredMethodsInternal(definingType, name).GetEnumerator(); + if (!matches.MoveNext()) + return null; + RuntimeMethodInfo result = matches.Current; + if (matches.MoveNext()) + throw new AmbiguousMatchException(); + return result; + } + + private Dispenser<String, RuntimeFieldInfo> _fieldLookupDispenser; + + private RuntimeFieldInfo LookupDeclaredFieldByName(String name) + { + RuntimeNamedTypeInfo definingType = _runtimeTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + IEnumerator<RuntimeFieldInfo> matches = _runtimeTypeInfo.GetDeclaredFieldsInternal(definingType, name).GetEnumerator(); + if (!matches.MoveNext()) + return null; + RuntimeFieldInfo result = matches.Current; + if (matches.MoveNext()) + throw new AmbiguousMatchException(); + return result; + } + + private Dispenser<String, RuntimePropertyInfo> _propertyLookupDispenser; + + private RuntimePropertyInfo LookupDeclaredPropertyByName(String name) + { + RuntimeNamedTypeInfo definingType = _runtimeTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + IEnumerator<RuntimePropertyInfo> matches = _runtimeTypeInfo.GetDeclaredPropertiesInternal(definingType, name).GetEnumerator(); + if (!matches.MoveNext()) + return null; + RuntimePropertyInfo result = matches.Current; + if (matches.MoveNext()) + throw new AmbiguousMatchException(); + return result; + } + + + private Dispenser<String, RuntimeEventInfo> _eventLookupDispenser; + + private RuntimeEventInfo LookupDeclaredEventByName(String name) + { + RuntimeNamedTypeInfo definingType = _runtimeTypeInfo.AnchoringTypeDefinitionForDeclaredMembers; + IEnumerator<RuntimeEventInfo> matches = _runtimeTypeInfo.GetDeclaredEventsInternal(definingType, name).GetEnumerator(); + if (!matches.MoveNext()) + return null; + RuntimeEventInfo result = matches.Current; + if (matches.MoveNext()) + throw new AmbiguousMatchException(); + return result; + } + + private RuntimeTypeInfo _runtimeTypeInfo; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs new file mode 100644 index 000000000..610c4f5b9 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeLexer.cs @@ -0,0 +1,242 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Collections; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Assemblies; + +namespace System.Reflection.Runtime.TypeParsing +{ + // + // String tokenizer for typenames passed to the GetType() api's. + // + internal sealed class TypeLexer + { + public TypeLexer(String s) + { + // Turn the string into a char array with a NUL terminator. + char[] chars = new char[s.Length + 1]; + s.CopyTo(0, chars, 0, s.Length); + _chars = chars; + _index = 0; + } + + public TokenType Peek + { + get + { + SkipWhiteSpace(); + char c = _chars[_index]; + return CharToToken(c); + } + } + + public TokenType PeekSecond + { + get + { + SkipWhiteSpace(); + int index = _index + 1; + while (Char.IsWhiteSpace(_chars[index])) + index++; + char c = _chars[index]; + return CharToToken(c); + } + } + + + public void Skip() + { + Debug.Assert(_index != _chars.Length); + SkipWhiteSpace(); + _index++; + } + + // Return the next token and skip index past it unless already at end of string + // or the token is not a reserved token. + public TokenType GetNextToken() + { + TokenType tokenType = Peek; + if (tokenType == TokenType.End || tokenType == TokenType.Other) + return tokenType; + Skip(); + return tokenType; + } + + // + // Lex the next segment as part of a type name. (Do not use for assembly names.) + // + // Note that unescaped "."'s do NOT terminate the identifier, but unescaped "+"'s do. + // + // Terminated by the first non-escaped reserved character ('[', ']', '+', '&', '*' or ',') + // + public String GetNextIdentifier() + { + SkipWhiteSpace(); + + int src = _index; + char[] buffer = new char[_chars.Length]; + int dst = 0; + for (; ;) + { + char c = _chars[src]; + TokenType token = CharToToken(c); + if (token != TokenType.Other) + break; + src++; + if (c == '\\') + { + c = _chars[src]; + if (c != NUL) + src++; + if (c == NUL || CharToToken(c) == TokenType.Other) + { + // If we got here, a backslash was used to escape a character that is not legal to escape inside a type name. + // + // Common sense would dictate throwing an ArgumentException but that's not what the desktop CLR does. + // The desktop CLR treats this case by returning FALSE from TypeName::TypeNameParser::GetIdentifier(). + // Unfortunately, no one checks this return result. Instead, the CLR keeps parsing (unfortunately, the lexer + // was left in some strange state by the previous failure but typically, this goes unnoticed) and eventually, tries to resolve + // a Type whose name is the empty string. When it can't resolve that type, the CLR throws a TypeLoadException() + // complaining about be unable to find a type with the empty name. + // + // To emulate this accidental behavior, we'll throw a special exception that's caught by the TypeParser. + // + throw new IllegalEscapeSequenceException(); + } + } + buffer[dst++] = c; + } + + _index = src; + return new String(buffer, 0, dst); + } + + // + // Lex the next segment as the assembly name at the end of an assembly-qualified type name. (Do not use for + // assembly names embedded inside generic type arguments.) + // + // Terminated by NUL. There are no escape characters defined by the typename lexer (however, AssemblyName + // does have its own escape rules.) + // + public RuntimeAssemblyName GetNextAssemblyName() + { + SkipWhiteSpace(); + + int src = _index; + char[] buffer = new char[_chars.Length]; + int dst = 0; + for (; ;) + { + char c = _chars[src]; + if (c == NUL) + break; + src++; + buffer[dst++] = c; + } + _index = src; + String fullName = new String(buffer, 0, dst); + return AssemblyNameParser.Parse(fullName); + } + + // + // Lex the next segment as an assembly name embedded inside a generic argument type. + // + // Terminated by an unescaped ']'. + // + public RuntimeAssemblyName GetNextEmbeddedAssemblyName() + { + SkipWhiteSpace(); + + int src = _index; + char[] buffer = new char[_chars.Length]; + int dst = 0; + for (; ;) + { + char c = _chars[src]; + if (c == NUL) + throw new ArgumentException(); + if (c == ']') + break; + src++; + + // Backslash can be used to escape a ']' - any other backslash character is left alone (along with the backslash) + // for the AssemblyName parser to handle. + if (c == '\\' && _chars[src] == ']') + { + c = _chars[src++]; + } + buffer[dst++] = c; + } + _index = src; + String fullName = new String(buffer, 0, dst); + return AssemblyNameParser.Parse(fullName); + } + + // + // Classify a character as a TokenType. (Fortunately, all tokens in typename strings other than identifiers are single-character tokens.) + // + private static TokenType CharToToken(char c) + { + switch (c) + { + case NUL: + return TokenType.End; + case '[': + return TokenType.OpenSqBracket; + case ']': + return TokenType.CloseSqBracket; + case ',': + return TokenType.Comma; + case '+': + return TokenType.Plus; + case '*': + return TokenType.Asterisk; + case '&': + return TokenType.Ampersand; + default: + return TokenType.Other; + } + } + + // + // The desktop typename parser has a strange attitude towards whitespace. It throws away whitespace between punctuation tokens and whitespace + // preceeding identifiers or assembly names (and this cannot be escaped away). But whitespace between the end of an identifier + // and the punctuation that ends it is *not* ignored. + // + // In other words, GetType(" Foo") searches for "Foo" but GetType("Foo ") searches for "Foo ". + // + // Whitespace between the end of an assembly name and the punction mark that ends it is also not ignored by this parser, + // but this is irrelevant since the assembly name is then turned over to AssemblyName for parsing, which *does* ignore trailing whitespace. + // + private void SkipWhiteSpace() + { + while (Char.IsWhiteSpace(_chars[_index])) + _index++; + } + + + private int _index; + private char[] _chars; + private const char NUL = (char)0; + + + public sealed class IllegalEscapeSequenceException : Exception + { + } + } + + internal enum TokenType + { + End = 0, //At end of string + OpenSqBracket = 1, //'[' + CloseSqBracket = 2, //']' + Comma = 3, //',' + Plus = 4, //'+' + Asterisk = 5, //'*' + Ampersand = 6, //'&' + Other = 7, //Type identifier, AssemblyName or embedded AssemblyName. + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs new file mode 100644 index 000000000..72918dc47 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeName.cs @@ -0,0 +1,535 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Collections; +using global::System.Reflection; +using global::System.Collections.Generic; + +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.Assemblies; + +using global::Internal.Metadata.NativeFormat; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.NonPortable; + +namespace System.Reflection.Runtime.TypeParsing +{ + // + // The TypeName class is the base class for a family of types that represent the nodes in a parse tree for + // assembly-qualified type names. + // + internal abstract class TypeName + { + public abstract Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result); + public abstract override String ToString(); + } + + + // + // Represents a parse of a type name OPTIONALLY qualified by an assembly name. If present, the assembly name follows + // a comma following the type name. + // + // Note that unlike the reflection model, the assembly qualification is a property of a typename string as a whole + // rather than the property of the single namespace type that "represents" the type. This model is simply a better match to + // how type names passed to GetType() are constructed and parsed. + // + internal sealed class AssemblyQualifiedTypeName : TypeName + { + public AssemblyQualifiedTypeName(NonQualifiedTypeName typeName, RuntimeAssemblyName assemblyName) + { + Debug.Assert(typeName != null); + TypeName = typeName; + AssemblyName = assemblyName; + } + + public NonQualifiedTypeName TypeName { get; private set; } + public RuntimeAssemblyName AssemblyName { get; private set; } // This can return null if the type name was not actually qualified. + + public sealed override String ToString() + { + return TypeName.ToString() + ((AssemblyName == null) ? "" : ", " + AssemblyName.FullName); + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + if (AssemblyName == null) + { + return TypeName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out result); + } + else + { + RuntimeAssembly newAssembly; + Exception assemblyLoadException = RuntimeAssembly.TryGetRuntimeAssembly(reflectionDomain, AssemblyName, out newAssembly); + if (assemblyLoadException != null) + return assemblyLoadException; + return TypeName.TryResolve(reflectionDomain, newAssembly, ignoreCase, out result); + } + } + } + + // + // Base class for all non-assembly-qualified type names. + // + internal abstract class NonQualifiedTypeName : TypeName + { + } + + // + // Base class for namespace or nested type. + // + internal abstract class NamedTypeName : NonQualifiedTypeName + { + } + + // + // Non-nested named type. The full name is the namespace-qualified name. For example, the FullName for + // System.Collections.Generic.IList<> is "System.Collections.Generic.IList`1". + // + internal sealed partial class NamespaceTypeName : NamedTypeName + { + public NamespaceTypeName(String[] namespaceParts, String name) + { + Debug.Assert(namespaceParts != null); + Debug.Assert(name != null); + + _name = name; + _namespaceParts = namespaceParts; + } + + public sealed override String ToString() + { + String fullName = ""; + for (int i = 0; i < _namespaceParts.Length; i++) + { + fullName += _namespaceParts[_namespaceParts.Length - i - 1]; + fullName += "."; + } + fullName += _name; + return fullName; + } + + private bool TryResolveNamespaceDefinitionCaseSensitive(MetadataReader reader, ScopeDefinitionHandle scopeDefinitionHandle, out NamespaceDefinition namespaceDefinition) + { + namespaceDefinition = scopeDefinitionHandle.GetScopeDefinition(reader).RootNamespaceDefinition.GetNamespaceDefinition(reader); + IEnumerable<NamespaceDefinitionHandle> candidates = namespaceDefinition.NamespaceDefinitions; + int idx = _namespaceParts.Length; + while (idx-- != 0) + { + // Each iteration finds a match for one segment of the namespace chain. + String expected = _namespaceParts[idx]; + bool foundMatch = false; + foreach (NamespaceDefinitionHandle candidate in candidates) + { + namespaceDefinition = candidate.GetNamespaceDefinition(reader); + if (namespaceDefinition.Name.StringOrNullEquals(expected, reader)) + { + // Found a match for this segment of the namespace chain. Move on to the next level. + foundMatch = true; + candidates = namespaceDefinition.NamespaceDefinitions; + break; + } + } + + if (!foundMatch) + { + return false; + } + } + + return true; + } + + private Exception UncachedTryResolveCaseSensitive(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, out RuntimeType result) + { + result = null; + + foreach (QScopeDefinition scopeDefinition in currentAssembly.AllScopes) + { + MetadataReader reader = scopeDefinition.Reader; + ScopeDefinitionHandle scopeDefinitionHandle = scopeDefinition.Handle; + + NamespaceDefinition namespaceDefinition; + if (!TryResolveNamespaceDefinitionCaseSensitive(reader, scopeDefinitionHandle, out namespaceDefinition)) + { + continue; + } + + // We've successfully drilled down the namespace chain. Now look for a top-level type matching the type name. + IEnumerable<TypeDefinitionHandle> candidateTypes = namespaceDefinition.TypeDefinitions; + foreach (TypeDefinitionHandle candidateType in candidateTypes) + { + TypeDefinition typeDefinition = candidateType.GetTypeDefinition(reader); + if (typeDefinition.Name.StringEquals(_name, reader)) + { + result = reflectionDomain.ResolveTypeDefinition(reader, candidateType); + return null; + } + } + + // No match found in this assembly - see if there's a matching type forwarder. + IEnumerable<TypeForwarderHandle> candidateTypeForwarders = namespaceDefinition.TypeForwarders; + foreach (TypeForwarderHandle typeForwarderHandle in candidateTypeForwarders) + { + TypeForwarder typeForwarder = typeForwarderHandle.GetTypeForwarder(reader); + if (typeForwarder.Name.StringEquals(_name, reader)) + { + RuntimeAssemblyName redirectedAssemblyName = typeForwarder.Scope.ToRuntimeAssemblyName(reader); + AssemblyQualifiedTypeName redirectedTypeName = new AssemblyQualifiedTypeName(this, redirectedAssemblyName); + return redirectedTypeName.TryResolve(reflectionDomain, null, /*ignoreCase: */false, out result); + } + } + } + + { + String typeName = this.ToString(); + String message = SR.Format(SR.TypeLoad_TypeNotFound, typeName, currentAssembly.FullName); + return ReflectionCoreNonPortable.CreateTypeLoadException(message, typeName); + } + } + + private Exception TryResolveCaseInsensitive(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, out RuntimeType result) + { + String fullName = this.ToString().ToLower(); + + LowLevelDictionary<String, QHandle> dict = GetCaseInsensitiveTypeDictionary(currentAssembly); + QHandle qualifiedHandle; + if (!dict.TryGetValue(fullName, out qualifiedHandle)) + { + result = null; + return new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFound, this.ToString(), currentAssembly.FullName)); + } + + MetadataReader reader = qualifiedHandle.Reader; + Handle typeDefOrForwarderHandle = qualifiedHandle.Handle; + + HandleType handleType = typeDefOrForwarderHandle.HandleType; + switch (handleType) + { + case HandleType.TypeDefinition: + { + TypeDefinitionHandle typeDefinitionHandle = typeDefOrForwarderHandle.ToTypeDefinitionHandle(reader); + result = reflectionDomain.ResolveTypeDefinition(reader, typeDefinitionHandle); + return null; + } + case HandleType.TypeForwarder: + { + TypeForwarder typeForwarder = typeDefOrForwarderHandle.ToTypeForwarderHandle(reader).GetTypeForwarder(reader); + ScopeReferenceHandle destinationScope = typeForwarder.Scope; + RuntimeAssemblyName destinationAssemblyName = destinationScope.ToRuntimeAssemblyName(reader); + RuntimeAssembly destinationAssembly; + Exception exception = RuntimeAssembly.TryGetRuntimeAssembly(reflectionDomain, destinationAssemblyName, out destinationAssembly); + if (exception != null) + { + result = null; + return exception; + } + return TryResolveCaseInsensitive(reflectionDomain, destinationAssembly, out result); + } + default: + throw new InvalidOperationException(); + } + } + + private static LowLevelDictionary<String, QHandle> CreateCaseInsensitiveTypeDictionary(RuntimeAssembly assembly) + { + // + // Collect all of the *non-nested* types and type-forwards. + // + // The keys are full typenames in lower-cased form. + // The value is a tuple containing either a TypeDefinitionHandle or TypeForwarderHandle and the associated Reader + // for that handle. + // + // We do not store nested types here. The container type is resolved and chosen first, then the nested type chosen from + // that. If we chose the wrong container type and fail the match as a result, that's too bad. (The desktop CLR has the + // same issue.) + // + ReflectionDomain reflectionDomain = assembly.ReflectionDomain; + LowLevelDictionary<String, QHandle> dict = new LowLevelDictionary<string, QHandle>(); + + foreach (QScopeDefinition scope in assembly.AllScopes) + { + MetadataReader reader = scope.Reader; + ScopeDefinition scopeDefinition = scope.ScopeDefinition; + IEnumerable<NamespaceDefinitionHandle> topLevelNamespaceHandles = new NamespaceDefinitionHandle[] { scopeDefinition.RootNamespaceDefinition }; + IEnumerable<NamespaceDefinitionHandle> allNamespaceHandles = reader.GetTransitiveNamespaces(topLevelNamespaceHandles); + foreach (NamespaceDefinitionHandle namespaceHandle in allNamespaceHandles) + { + String ns = namespaceHandle.ToNamespaceName(reader); + if (ns.Length != 0) + ns = ns + "."; + ns = ns.ToLower(); + + NamespaceDefinition namespaceDefinition = namespaceHandle.GetNamespaceDefinition(reader); + foreach (TypeDefinitionHandle typeDefinitionHandle in namespaceDefinition.TypeDefinitions) + { + String fullName = ns + typeDefinitionHandle.GetTypeDefinition(reader).Name.GetString(reader).ToLower(); + QHandle existingValue; + if (!dict.TryGetValue(fullName, out existingValue)) + { + dict.Add(fullName, new QHandle(reader, typeDefinitionHandle)); + } + } + + foreach (TypeForwarderHandle typeForwarderHandle in namespaceDefinition.TypeForwarders) + { + String fullName = ns + typeForwarderHandle.GetTypeForwarder(reader).Name.GetString(reader).ToLower(); + QHandle existingValue; + if (!dict.TryGetValue(fullName, out existingValue)) + { + dict.Add(fullName, new QHandle(reader, typeForwarderHandle)); + } + } + } + } + + return dict; + } + + private String _name; + private String[] _namespaceParts; + } + + // + // A nested type. The Name is the simple name of the type (not including any portion of its declaring type name. + // + internal sealed class NestedTypeName : NamedTypeName + { + public NestedTypeName(String name, NamedTypeName declaringType) + { + Name = name; + DeclaringType = declaringType; + } + + public String Name { get; private set; } + public NamedTypeName DeclaringType { get; private set; } + + public sealed override String ToString() + { + return DeclaringType + "+" + Name; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType declaringType; + Exception typeLoadException = DeclaringType.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out declaringType); + if (typeLoadException != null) + return typeLoadException; + TypeInfo nestedTypeInfo = FindDeclaredNestedType(declaringType.GetTypeInfo(), Name, ignoreCase); + if (nestedTypeInfo == null) + return new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFound, declaringType.FullName + "+" + Name, currentAssembly.FullName)); + result = (RuntimeType)(nestedTypeInfo.AsType()); + return null; + } + + private TypeInfo FindDeclaredNestedType(TypeInfo declaringTypeInfo, String name, bool ignoreCase) + { + TypeInfo nestedType = declaringTypeInfo.GetDeclaredNestedType(name); + if (nestedType != null) + return nestedType; + if (!ignoreCase) + return null; + + // + // Desktop compat note: If there is more than one nested type that matches the name in a case-blind match, + // we might not return the same one that the desktop returns. The actual selection method is influenced both by the type's + // placement in the IL and the implementation details of the CLR's internal hashtables so it would be very + // hard to replicate here. + // + // Desktop compat note #2: Case-insensitive lookups: If we don't find a match, we do *not* go back and search + // other declaring types that might match the case-insensitive search and contain the nested type being sought. + // Though this is somewhat unsatisfactory, the desktop CLR has the same limitation. + // + foreach (TypeInfo candidate in declaringTypeInfo.DeclaredNestedTypes) + { + String candidateName = candidate.Name; + if (name.Equals(candidateName, StringComparison.OrdinalIgnoreCase)) + return candidate; + } + return null; + } + } + + // + // Abstract base for array, byref and pointer type names. + // + internal abstract class HasElementTypeName : NonQualifiedTypeName + { + public HasElementTypeName(TypeName elementTypeName) + { + ElementTypeName = elementTypeName; + } + + public TypeName ElementTypeName { get; private set; } + } + + // + // A single-dimensional zero-lower-bound array type name. + // + internal sealed class ArrayTypeName : HasElementTypeName + { + public ArrayTypeName(TypeName elementTypeName) + : base(elementTypeName) + { + } + + public sealed override String ToString() + { + return ElementTypeName + "[]"; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType elementType; + Exception typeLoadException = ElementTypeName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out elementType); + if (typeLoadException != null) + return typeLoadException; + result = ReflectionCoreNonPortable.GetArrayType(elementType); + return null; + } + } + + // + // A multidim array type name. + // + internal sealed class MultiDimArrayTypeName : HasElementTypeName + { + public MultiDimArrayTypeName(TypeName elementTypeName, int rank) + : base(elementTypeName) + { + _rank = rank; + } + + public sealed override String ToString() + { + return ElementTypeName + "[" + (_rank == 1 ? "*" : new String(',', _rank - 1)) + "]"; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType elementType; + Exception typeLoadException = ElementTypeName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out elementType); + if (typeLoadException != null) + return typeLoadException; + result = ReflectionCoreNonPortable.GetMultiDimArrayType(elementType, _rank); + return null; + } + + private int _rank; + } + + // + // A byref type. + // + internal sealed class ByRefTypeName : HasElementTypeName + { + public ByRefTypeName(TypeName elementTypeName) + : base(elementTypeName) + { + } + + public sealed override String ToString() + { + return ElementTypeName + "&"; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType elementType; + Exception typeLoadException = ElementTypeName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out elementType); + if (typeLoadException != null) + return typeLoadException; + result = ReflectionCoreNonPortable.GetByRefType(elementType); + return null; + } + } + + // + // A pointer type. + // + internal sealed class PointerTypeName : HasElementTypeName + { + public PointerTypeName(TypeName elementTypeName) + : base(elementTypeName) + { + } + + public sealed override String ToString() + { + return ElementTypeName + "*"; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType elementType; + Exception typeLoadException = ElementTypeName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out elementType); + if (typeLoadException != null) + return typeLoadException; + result = ReflectionCoreNonPortable.GetPointerType(elementType); + return null; + } + } + + // + // A constructed generic type. + // + internal sealed class ConstructedGenericTypeName : NonQualifiedTypeName + { + public ConstructedGenericTypeName(NamedTypeName genericType, IEnumerable<TypeName> genericArguments) + { + GenericType = genericType; + GenericArguments = genericArguments; + } + + public NamedTypeName GenericType { get; private set; } + public IEnumerable<TypeName> GenericArguments { get; private set; } + + public sealed override String ToString() + { + String s = GenericType.ToString(); + s += "["; + String sep = ""; + foreach (TypeName genericTypeArgument in GenericArguments) + { + s += sep; + sep = ","; + AssemblyQualifiedTypeName assemblyQualifiedTypeArgument = genericTypeArgument as AssemblyQualifiedTypeName; + if (assemblyQualifiedTypeArgument == null || assemblyQualifiedTypeArgument.AssemblyName == null) + s += genericTypeArgument.ToString(); + else + s += "[" + genericTypeArgument.ToString() + "]"; + } + s += "]"; + return s; + } + + public sealed override Exception TryResolve(ReflectionDomain reflectionDomain, RuntimeAssembly currentAssembly, bool ignoreCase, out RuntimeType result) + { + result = null; + RuntimeType genericType; + Exception typeLoadException = GenericType.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out genericType); + if (typeLoadException != null) + return typeLoadException; + LowLevelList<RuntimeType> genericTypeArguments = new LowLevelList<RuntimeType>(); + foreach (TypeName genericTypeArgumentName in GenericArguments) + { + RuntimeType genericTypeArgument; + typeLoadException = genericTypeArgumentName.TryResolve(reflectionDomain, currentAssembly, ignoreCase, out genericTypeArgument); + if (typeLoadException != null) + return typeLoadException; + genericTypeArguments.Add(genericTypeArgument); + } + result = ReflectionCoreNonPortable.GetConstructedGenericType(genericType, genericTypeArguments.ToArray()); + return null; + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs new file mode 100644 index 000000000..e1ab5e4af --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeParsing/TypeParser.cs @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Diagnostics; +using global::System.Collections; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.Assemblies; + +namespace System.Reflection.Runtime.TypeParsing +{ + // + // Parser for type names passed to GetType() apis. + // + internal sealed class TypeParser + { + // + // Parses a typename. The typename may be optionally postpended with a "," followed by a legal assembly name. + // + public static AssemblyQualifiedTypeName ParseAssemblyQualifiedTypeName(String s) + { + // Desktop compat: a whitespace-only "typename" qualified by an assembly name throws an ArgumentException rather than + // a TypeLoadException. + int idx = 0; + while (idx < s.Length && Char.IsWhiteSpace(s[idx])) + { + idx++; + } + if (idx < s.Length && s[idx] == ',') + throw new ArgumentException(SR.Arg_TypeLoadNullStr); + + try + { + TypeParser parser = new TypeParser(s); + NonQualifiedTypeName typeName = parser.ParseNonQualifiedTypeName(); + TokenType token = parser._lexer.GetNextToken(); + if (token == TokenType.End) + return new AssemblyQualifiedTypeName(typeName, null); + if (token == TokenType.Comma) + { + RuntimeAssemblyName assemblyName = parser._lexer.GetNextAssemblyName(); + token = parser._lexer.Peek; + if (token != TokenType.End) + throw new ArgumentException(); + return new AssemblyQualifiedTypeName(typeName, assemblyName); + } + throw new ArgumentException(); + } + catch (TypeLexer.IllegalEscapeSequenceException) + { + // Emulates a CLR4.5 bug that causes any string that contains an illegal escape sequence to be parsed as the empty string. + return ParseAssemblyQualifiedTypeName(String.Empty); + } + } + + private TypeParser(String s) + { + _lexer = new TypeLexer(s); + } + + + // + // Parses a type name without any assembly name qualification. + // + private NonQualifiedTypeName ParseNonQualifiedTypeName() + { + // Parse the named type or constructed generic type part first. + NonQualifiedTypeName typeName = ParseNamedOrConstructedGenericTypeName(); + + // Iterate through any "has-element" qualifiers ([], &, *). + for (; ;) + { + TokenType token = _lexer.Peek; + if (token == TokenType.End) + break; + if (token == TokenType.Asterisk) + { + _lexer.Skip(); + typeName = new PointerTypeName(typeName); + } + else if (token == TokenType.Ampersand) + { + _lexer.Skip(); + typeName = new ByRefTypeName(typeName); + } + else if (token == TokenType.OpenSqBracket) + { + _lexer.Skip(); + token = _lexer.GetNextToken(); + if (token == TokenType.Asterisk) + { + typeName = new MultiDimArrayTypeName(typeName, 1); + token = _lexer.GetNextToken(); + } + else + { + int rank = 1; + while (token == TokenType.Comma) + { + token = _lexer.GetNextToken(); + rank++; + } + if (rank == 1) + typeName = new ArrayTypeName(typeName); + else + typeName = new MultiDimArrayTypeName(typeName, rank); + } + if (token != TokenType.CloseSqBracket) + throw new ArgumentException(); + } + else + { + break; + } + } + return typeName; + } + + // + // Foo or Foo+Inner or Foo[String] or Foo+Inner[String] + // + private NonQualifiedTypeName ParseNamedOrConstructedGenericTypeName() + { + NamedTypeName namedType = ParseNamedTypeName(); + // Because "[" is used both for generic arguments and array indexes, we must peek two characters deep. + if (!(_lexer.Peek == TokenType.OpenSqBracket && (_lexer.PeekSecond == TokenType.Other || _lexer.PeekSecond == TokenType.OpenSqBracket))) + return namedType; + else + { + _lexer.Skip(); + LowLevelListWithIList<TypeName> genericTypeArguments = new LowLevelListWithIList<TypeName>(); + for (; ;) + { + TypeName genericTypeArgument = ParseGenericTypeArgument(); + genericTypeArguments.Add(genericTypeArgument); + TokenType token = _lexer.GetNextToken(); + if (token == TokenType.CloseSqBracket) + break; + if (token != TokenType.Comma) + throw new ArgumentException(); + } + + return new ConstructedGenericTypeName(namedType, genericTypeArguments); + } + } + + // + // Foo or Foo+Inner + // + private NamedTypeName ParseNamedTypeName() + { + NamedTypeName namedType = ParseNamespaceTypeName(); + while (_lexer.Peek == TokenType.Plus) + { + _lexer.Skip(); + String nestedTypeName = _lexer.GetNextIdentifier(); + namedType = new NestedTypeName(nestedTypeName, namedType); + } + return namedType; + } + + // + // Non-nested named type. + // + private NamespaceTypeName ParseNamespaceTypeName() + { + String fullName = _lexer.GetNextIdentifier(); + String[] parts = fullName.Split('.'); + int numNamespaceParts = parts.Length - 1; + String[] namespaceParts = new String[numNamespaceParts]; + for (int i = 0; i < numNamespaceParts; i++) + namespaceParts[numNamespaceParts - i - 1] = parts[i]; + String name = parts[numNamespaceParts]; + return new NamespaceTypeName(namespaceParts, name); + } + + // + // Parse a generic argument. In particular, generic arguments can take the special form [<typename>,<assemblyname>]. + // + private TypeName ParseGenericTypeArgument() + { + TokenType token = _lexer.GetNextToken(); + if (token == TokenType.Other) + { + NonQualifiedTypeName nonQualifiedTypeName = ParseNonQualifiedTypeName(); + return new AssemblyQualifiedTypeName(nonQualifiedTypeName, null); + } + else if (token == TokenType.OpenSqBracket) + { + RuntimeAssemblyName assemblyName = null; + NonQualifiedTypeName typeName = ParseNonQualifiedTypeName(); + token = _lexer.GetNextToken(); + if (token == TokenType.Comma) + { + assemblyName = _lexer.GetNextEmbeddedAssemblyName(); + token = _lexer.GetNextToken(); + } + if (token != TokenType.CloseSqBracket) + throw new ArgumentException(); + return new AssemblyQualifiedTypeName(typeName, assemblyName); + } + else + throw new ArgumentException(); + } + + + private TypeLexer _lexer; + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterType.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterType.cs new file mode 100644 index 000000000..3693ceec3 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterType.cs @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Types +{ + // + // Abstract base class for the runtime's implementation of System.Type for generic parameters (both type variables and method variables.) + // + // - Generic parameters never have EETypes so this is the only class that implements them. + // + internal abstract class RuntimeGenericParameterType : RuntimeType + { + internal RuntimeGenericParameterType(MetadataReader reader, GenericParameterHandle genericParameterHandle) + { + _reader = reader; + _genericParameterHandle = genericParameterHandle; + _genericParameter = _genericParameterHandle.GetGenericParameter(_reader); + _position = _genericParameter.Number; + } + + public sealed override bool Equals(Object obj) + { + return InternalIsEqual(obj); // Do not change this - see comments in RuntimeType.cs regarding Equals() + } + + public sealed override int GetHashCode() + { + return _genericParameterHandle.GetHashCode(); + } + + public abstract override Type DeclaringType { get; } + + public sealed override String FullName + { + get + { + return null; + } + } + + public sealed override int GenericParameterPosition + { + get + { + return _position; + } + } + + public sealed override bool IsGenericParameter + { + get + { + return true; + } + } + + public sealed override String Namespace + { + get + { + return DeclaringType.Namespace; + } + } + + public sealed override String ToString() + { + return Name; + } + + public sealed override String InternalGetNameIfAvailable(ref RuntimeType rootCauseForFailure) + { + if (_genericParameter.Name.IsNull(_reader)) + return String.Empty; + return _genericParameter.Name.GetString(_reader); + } + + public sealed override String InternalFullNameOfAssembly + { + get + { + Debug.Assert(false, "Why are you bothering to call me when my FullName is null?"); + return null; + } + } + + // + // Pay-for-play safe implementation of TypeInfo.ContainsGenericParameters() + // + public sealed override bool InternalIsOpen + { + get + { + return true; + } + } + + internal GenericParameterAttributes GenericParameterAttributes + { + get + { + return _genericParameter.Flags; + } + } + + internal MetadataReader Reader + { + get + { + return _reader; + } + } + + internal GenericParameterHandle GenericParameterHandle + { + get + { + return _genericParameterHandle; + } + } + + internal abstract RuntimeMethodInfo DeclaringMethod { get; } + + internal abstract TypeContext TypeContext { get; } + + internal IEnumerable<CustomAttributeData> CustomAttributes + { + get + { + return RuntimeCustomAttributeData.GetCustomAttributes(this.GetReflectionDomain(), _reader, _genericParameter.CustomAttributes); + } + } + + private MetadataReader _reader; + private GenericParameterHandle _genericParameterHandle; + private GenericParameter _genericParameter; + + private int _position; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForMethods.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForMethods.cs new file mode 100644 index 000000000..337481217 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForMethods.cs @@ -0,0 +1,156 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Collections.Concurrent; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Types +{ + // + // The runtime's implementation of System.Type for generic parameters for methods. + // + + internal sealed class RuntimeGenericParameterTypeForMethods : RuntimeGenericParameterType, IKeyedItem<RuntimeGenericParameterTypeForMethods.UnificationKey> + { + internal RuntimeGenericParameterTypeForMethods(MetadataReader reader, GenericParameterHandle genericParameterHandle, RuntimeNamedMethodInfo declaringRuntimeNamedMethodInfo) + : base(reader, genericParameterHandle) + { + _declaringRuntimeNamedMethodInfo = declaringRuntimeNamedMethodInfo; + } + + public sealed override Type DeclaringType + { + get + { + return _declaringRuntimeNamedMethodInfo.DeclaringType; + } + } + + + + // + // Implements IKeyedItem.PrepareKey. + // + // This method is the keyed item's chance to do any lazy evaluation needed to produce the key quickly. + // Concurrent unifiers are guaranteed to invoke this method at least once and wait for it + // to complete before invoking the Key property. The unifier lock is NOT held across the call. + // + // PrepareKey() must be idempodent and thread-safe. It may be invoked multiple times and concurrently. + // + public void PrepareKey() + { + } + + // + // Implements IKeyedItem.Key. + // + // Produce the key. This is a high-traffic property and is called while the hash table's lock is held. Thus, it should + // return a precomputed stored value and refrain from invoking other methods. If the keyed item wishes to + // do lazy evaluation of the key, it should do so in the PrepareKey() method. + // + public RuntimeGenericParameterTypeForMethods.UnificationKey Key + { + get + { + return new UnificationKey(_declaringRuntimeNamedMethodInfo, this.Reader, this.GenericParameterHandle); + } + } + + internal sealed override RuntimeMethodInfo DeclaringMethod + { + get + { + return _declaringRuntimeNamedMethodInfo; + } + } + + internal sealed override TypeContext TypeContext + { + get + { + TypeContext typeContext = this.DeclaringType.GetRuntimeTypeInfo<RuntimeTypeInfo>().TypeContext; + return new TypeContext(typeContext.GenericTypeArguments, _declaringRuntimeNamedMethodInfo.RuntimeGenericArgumentsOrParameters); + } + } + + private RuntimeNamedMethodInfo _declaringRuntimeNamedMethodInfo; + + + // + // Key for unification. + // + internal struct UnificationKey : IEquatable<UnificationKey> + { + public UnificationKey(RuntimeNamedMethodInfo methodOwner, MetadataReader reader, GenericParameterHandle genericParameterHandle) + { + _methodOwner = methodOwner; + _genericParameterHandle = genericParameterHandle; + _reader = reader; + } + + public RuntimeNamedMethodInfo MethodOwner + { + get + { + return _methodOwner; + } + } + + public MetadataReader Reader + { + get + { + return _reader; + } + } + + public GenericParameterHandle GenericParameterHandle + { + get + { + return _genericParameterHandle; + } + } + + public override bool Equals(Object obj) + { + if (!(obj is UnificationKey)) + return false; + return Equals((UnificationKey)obj); + } + + public bool Equals(UnificationKey other) + { + if (!(this._genericParameterHandle.Equals(other._genericParameterHandle))) + return false; + if (!(this._reader == other._reader)) + return false; + if (!this._methodOwner.Equals(other._methodOwner)) + return false; + return true; + } + + public override int GetHashCode() + { + return this._genericParameterHandle.GetHashCode(); + } + + private RuntimeNamedMethodInfo _methodOwner; + private MetadataReader _reader; + private GenericParameterHandle _genericParameterHandle; + } + } +} + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForTypes.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForTypes.cs new file mode 100644 index 000000000..8cf63cb14 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeGenericParameterTypeForTypes.cs @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; +using global::System.Reflection.Runtime.MethodInfos; +using global::System.Reflection.Runtime.CustomAttributes; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Types +{ + // + // The runtime's implementation of System.Type for generic parameters for types (not methods.) + // + + internal sealed class RuntimeGenericParameterTypeForTypes : RuntimeGenericParameterType + { + internal RuntimeGenericParameterTypeForTypes(MetadataReader reader, GenericParameterHandle genericParameterHandle, RuntimeNamedTypeInfo declaringRuntimeNamedTypeInfo) + : base(reader, genericParameterHandle) + { + _declaringRuntimeNamedTypeInfo = declaringRuntimeNamedTypeInfo; + } + + public sealed override Type DeclaringType + { + get + { + return _declaringRuntimeNamedTypeInfo.AsType(); + } + } + + internal sealed override RuntimeMethodInfo DeclaringMethod + { + get + { + return null; + } + } + + internal sealed override TypeContext TypeContext + { + get + { + return new TypeContext(_declaringRuntimeNamedTypeInfo.RuntimeGenericTypeParameters, null); + } + } + + private RuntimeNamedTypeInfo _declaringRuntimeNamedTypeInfo; + + + // + // Key for unification. + // + internal struct UnificationKey : IEquatable<UnificationKey> + { + public UnificationKey(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle, GenericParameterHandle genericParameterHandle) + { + _reader = reader; + _typeDefinitionHandle = typeDefinitionHandle; + _genericParameterHandle = genericParameterHandle; + } + + public MetadataReader Reader + { + get + { + return _reader; + } + } + + public TypeDefinitionHandle TypeDefinitionHandle + { + get + { + return _typeDefinitionHandle; + } + } + + public GenericParameterHandle GenericParameterHandle + { + get + { + return _genericParameterHandle; + } + } + + public override bool Equals(Object obj) + { + if (!(obj is UnificationKey)) + return false; + return Equals((UnificationKey)obj); + } + + public bool Equals(UnificationKey other) + { + if (!this._typeDefinitionHandle.Equals(other._typeDefinitionHandle)) + return false; + if (!(this._reader == other._reader)) + return false; + if (!(this._genericParameterHandle.Equals(other._genericParameterHandle))) + return false; + return true; + } + + public override int GetHashCode() + { + return this._typeDefinitionHandle.GetHashCode(); + } + + private MetadataReader _reader; + private TypeDefinitionHandle _typeDefinitionHandle; + private GenericParameterHandle _genericParameterHandle; + } + } +} + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeInspectionOnlyNamedType.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeInspectionOnlyNamedType.cs new file mode 100644 index 000000000..b6b8a8293 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/RuntimeInspectionOnlyNamedType.cs @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Linq; +using global::System.Text; +using global::System.Threading; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; +using global::System.Reflection.Runtime.TypeInfos; + +using global::Internal.Reflection.Core; +using global::Internal.Reflection.Core.Execution; +using global::Internal.Reflection.Core.NonPortable; +using Internal.Reflection.Tracing; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Types +{ + // + // The runtime's implementation of Types for named types (i.e. types with a TypeDefinitionHandle.) + // + internal partial class RuntimeInspectionOnlyNamedType : RuntimeType + { + protected RuntimeInspectionOnlyNamedType(MetadataReader reader, TypeDefinitionHandle typeDefinitionHandle) + : base() + { +#if DEBUG + if (!(this.InternalViolatesTypeIdentityRules)) + { + RuntimeTypeHandle runtimeTypeHandle; + if (ReflectionCoreExecution.ExecutionEnvironment.TryGetNamedTypeForMetadata(reader, typeDefinitionHandle, out runtimeTypeHandle)) + Debug.Assert(false, "Type identity violation: You must use a RuntimeEENamedType to represent this type as RH has generated an EEType for it."); + } +#endif + _reader = reader; + _typeDefinitionHandle = typeDefinitionHandle; + _typeDefinition = _typeDefinitionHandle.GetTypeDefinition(_reader); + } + + public sealed override bool Equals(Object obj) + { + return InternalIsEqual(obj); // Do not change this - see comments in RuntimeType.cs regarding Equals() + } + + public sealed override int GetHashCode() + { + return _typeDefinitionHandle.GetHashCode(); + } + + public sealed override Type DeclaringType + { + get + { + RuntimeType declaringType = null; + TypeDefinitionHandle enclosingTypeDefHandle = _typeDefinition.EnclosingType; + if (!enclosingTypeDefHandle.IsNull(_reader)) + { + declaringType = this.GetReflectionDomain().ResolveTypeDefinition(_reader, enclosingTypeDefHandle); + } + return declaringType; + } + } + + public sealed override Type GetGenericTypeDefinition() + { + if (_typeDefinition.GenericParameters.GetEnumerator().MoveNext()) + return this; + return base.GetGenericTypeDefinition(); + } + + public sealed override String Namespace + { + get + { + if (ReflectionTrace.Enabled) + ReflectionTrace.Type_Namespace(this); + + return EscapeIdentifier(NamespaceChain.NameSpace); + } + } + + public sealed override String ToString() + { + StringBuilder sb = null; + + foreach (GenericParameterHandle genericParameterHandle in _typeDefinition.GenericParameters) + { + if (sb == null) + { + sb = new StringBuilder(this.FullName); + sb.Append('['); + } + else + { + sb.Append(','); + } + + sb.Append(genericParameterHandle.GetGenericParameter(_reader).Name.GetString(_reader)); + } + + if (sb == null) + { + return this.FullName; + } + else + { + return sb.Append(']').ToString(); + } + } + + public sealed override String InternalGetNameIfAvailable(ref RuntimeType rootCauseForFailure) + { + ConstantStringValueHandle nameHandle = _typeDefinition.Name; + String name = nameHandle.GetString(_reader); + + return EscapeIdentifier(name); + } + + public sealed override String InternalFullNameOfAssembly + { + get + { + NamespaceChain namespaceChain = this.NamespaceChain; + ScopeDefinitionHandle scopeDefinitionHandle = namespaceChain.DefiningScope; + return scopeDefinitionHandle.ToRuntimeAssemblyName(_reader).FullName; + } + } + + public sealed override bool InternalIsGenericTypeDefinition + { + get + { + return _typeDefinition.GenericParameters.GetEnumerator().MoveNext(); + } + } + + // + // Pay-for-play safe implementation of TypeInfo.ContainsGenericParameters() + // + public sealed override bool InternalIsOpen + { + get + { + return this.InternalIsGenericTypeDefinition; + } + } + + internal RuntimeTypeInfo GetInspectionOnlyNamedRuntimeTypeInfo() + { + return RuntimeNamedTypeInfo.GetRuntimeNamedTypeInfo(_reader, _typeDefinitionHandle); + } + + private MetadataReader _reader; + private TypeDefinitionHandle _typeDefinitionHandle; + private TypeDefinition _typeDefinition; + + private NamespaceChain NamespaceChain + { + get + { + if (_lazyNamespaceChain == null) + _lazyNamespaceChain = new NamespaceChain(_reader, _typeDefinition.NamespaceDefinition); + return _lazyNamespaceChain; + } + } + + private volatile NamespaceChain _lazyNamespaceChain; + + private static char[] charsToEscape = new char[] { '\\', '[', ']', '+', '*', '&', ',' }; + // Escape identifiers as described in "Specifying Fully Qualified Type Names" on msdn. + // Current link is http://msdn.microsoft.com/en-us/library/yfsftwz6(v=vs.110).aspx + private static string EscapeIdentifier(string identifier) + { + // Some characters in a type name need to be escaped + if (identifier != null && identifier.IndexOfAny(charsToEscape) != -1) + { + StringBuilder sbEscapedName = new StringBuilder(identifier); + sbEscapedName.Replace("\\", "\\\\"); + sbEscapedName.Replace("+", "\\+"); + sbEscapedName.Replace("[", "\\["); + sbEscapedName.Replace("]", "\\]"); + sbEscapedName.Replace("*", "\\*"); + sbEscapedName.Replace("&", "\\&"); + sbEscapedName.Replace(",", "\\,"); + identifier = sbEscapedName.ToString(); + } + return identifier; + } + } +} + + + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/ShadowRuntimeInspectionOnlyNamedType.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/ShadowRuntimeInspectionOnlyNamedType.cs new file mode 100644 index 000000000..125152b26 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/Types/ShadowRuntimeInspectionOnlyNamedType.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using global::System; +using global::System.Reflection; +using global::System.Diagnostics; +using global::System.Collections.Generic; +using global::System.Reflection.Runtime.General; + +using global::Internal.Reflection.Core.NonPortable; + +using global::Internal.Metadata.NativeFormat; + +namespace System.Reflection.Runtime.Types +{ + // + // This is a RuntimeInspectionOnlyNamedType type that's created "behind the scenes" for types that also have EETypes. + // The type unification rules dictate that types that have both metadata and EEType be created as RuntimeEENamedTypes + // as the public-facing "identity." However, if S.R.R. is loaded and metadata is present, the developer naturally expects the + // Type object to be "fully functional." We accomplish this by creating this shadow type on-demand when + // a RuntimeEENamedType cannot get what it needs from the raw EEType. In such cases, RuntimeEENamedType delegates + // calls to this object. + // + // ! By necessity, shadow types break the type identity rules - thus, they must NEVER escape out into the wild. + // + internal sealed class ShadowRuntimeInspectionOnlyNamedType : RuntimeInspectionOnlyNamedType + { + internal ShadowRuntimeInspectionOnlyNamedType(MetadataReader metadataReader, TypeDefinitionHandle typeDefinitionHandle) + : base(metadataReader, typeDefinitionHandle) + { + } + + + public sealed override bool InternalViolatesTypeIdentityRules + { + get + { + return true; + } + } + } +} + |