From e30c38dff20cf61838b3a45756383ca10a89b261 Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Tue, 29 Sep 2015 14:12:32 -0700 Subject: [PATCH] Add type system source files All files have been copied from TFS at changeset 1530967. --- src/TypeSystem/src/Common/AlignmentHelper.cs | 22 + src/TypeSystem/src/Common/ArrayType.cs | 282 +++++++++ src/TypeSystem/src/Common/ByRefType.cs | 56 ++ src/TypeSystem/src/Common/FieldDesc.cs | 74 +++ .../src/Common/FieldForInstantiatedType.cs | 72 +++ src/TypeSystem/src/Common/FieldLayout.cs | 570 ++++++++++++++++++ .../src/Common/InstantiatedMethod.cs | 98 +++ src/TypeSystem/src/Common/InstantiatedType.cs | 207 +++++++ src/TypeSystem/src/Common/MetadataType.cs | 36 ++ src/TypeSystem/src/Common/MethodDesc.cs | 339 +++++++++++ .../src/Common/MethodForInstantiatedType.cs | 90 +++ .../src/Common/ParameterizedType.cs | 33 + src/TypeSystem/src/Common/PointerType.cs | 56 ++ .../src/Common/SignatureVariable.cs | 77 +++ src/TypeSystem/src/Common/TargetDetails.cs | 92 +++ src/TypeSystem/src/Common/TypeCast.cs | 27 + src/TypeSystem/src/Common/TypeDesc.cs | 393 ++++++++++++ src/TypeSystem/src/Common/TypeFlags.cs | 49 ++ .../src/Common/TypeHashingAlgorithms.cs | 148 +++++ src/TypeSystem/src/Common/TypeSystem.csproj | 93 +++ .../src/Common/TypeSystemContext.cs | 486 +++++++++++++++ .../src/Common/TypeSystemHelpers.cs | 23 + src/TypeSystem/src/Common/WellKnownType.cs | 44 ++ src/TypeSystem/src/Common/packages.config | 4 + src/TypeSystem/src/Ecma/EcmaField.cs | 177 ++++++ .../src/Ecma/EcmaGenericParameter.cs | 69 +++ src/TypeSystem/src/Ecma/EcmaMethod.cs | 244 ++++++++ src/TypeSystem/src/Ecma/EcmaModule.cs | 435 +++++++++++++ .../src/Ecma/EcmaSignatureParser.cs | 233 +++++++ src/TypeSystem/src/Ecma/EcmaType.cs | 403 +++++++++++++ .../Ecma/IMetadataStringDecoderProvider.cs | 13 + .../src/Ecma/TypeSystem.Ecma.csproj | 88 +++ src/TypeSystem/src/Ecma/packages.config | 5 + 33 files changed, 5038 insertions(+) create mode 100644 src/TypeSystem/src/Common/AlignmentHelper.cs create mode 100644 src/TypeSystem/src/Common/ArrayType.cs create mode 100644 src/TypeSystem/src/Common/ByRefType.cs create mode 100644 src/TypeSystem/src/Common/FieldDesc.cs create mode 100644 src/TypeSystem/src/Common/FieldForInstantiatedType.cs create mode 100644 src/TypeSystem/src/Common/FieldLayout.cs create mode 100644 src/TypeSystem/src/Common/InstantiatedMethod.cs create mode 100644 src/TypeSystem/src/Common/InstantiatedType.cs create mode 100644 src/TypeSystem/src/Common/MetadataType.cs create mode 100644 src/TypeSystem/src/Common/MethodDesc.cs create mode 100644 src/TypeSystem/src/Common/MethodForInstantiatedType.cs create mode 100644 src/TypeSystem/src/Common/ParameterizedType.cs create mode 100644 src/TypeSystem/src/Common/PointerType.cs create mode 100644 src/TypeSystem/src/Common/SignatureVariable.cs create mode 100644 src/TypeSystem/src/Common/TargetDetails.cs create mode 100644 src/TypeSystem/src/Common/TypeCast.cs create mode 100644 src/TypeSystem/src/Common/TypeDesc.cs create mode 100644 src/TypeSystem/src/Common/TypeFlags.cs create mode 100644 src/TypeSystem/src/Common/TypeHashingAlgorithms.cs create mode 100644 src/TypeSystem/src/Common/TypeSystem.csproj create mode 100644 src/TypeSystem/src/Common/TypeSystemContext.cs create mode 100644 src/TypeSystem/src/Common/TypeSystemHelpers.cs create mode 100644 src/TypeSystem/src/Common/WellKnownType.cs create mode 100644 src/TypeSystem/src/Common/packages.config create mode 100644 src/TypeSystem/src/Ecma/EcmaField.cs create mode 100644 src/TypeSystem/src/Ecma/EcmaGenericParameter.cs create mode 100644 src/TypeSystem/src/Ecma/EcmaMethod.cs create mode 100644 src/TypeSystem/src/Ecma/EcmaModule.cs create mode 100644 src/TypeSystem/src/Ecma/EcmaSignatureParser.cs create mode 100644 src/TypeSystem/src/Ecma/EcmaType.cs create mode 100644 src/TypeSystem/src/Ecma/IMetadataStringDecoderProvider.cs create mode 100644 src/TypeSystem/src/Ecma/TypeSystem.Ecma.csproj create mode 100644 src/TypeSystem/src/Ecma/packages.config diff --git a/src/TypeSystem/src/Common/AlignmentHelper.cs b/src/TypeSystem/src/Common/AlignmentHelper.cs new file mode 100644 index 00000000000..e35ebd59dd2 --- /dev/null +++ b/src/TypeSystem/src/Common/AlignmentHelper.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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public static class AlignmentHelper + { + public static int AlignUp(int val, int alignment) + { + Debug.Assert(val >= 0 && alignment >= 0); + + // alignment must be a power of 2 for this implementation to work (need modulo otherwise) + Debug.Assert(0 == (alignment & (alignment - 1))); + int result = (val + (alignment - 1)) & ~(alignment - 1); + Debug.Assert(result >= val); // check for overflow + + return result; + } + } +} diff --git a/src/TypeSystem/src/Common/ArrayType.cs b/src/TypeSystem/src/Common/ArrayType.cs new file mode 100644 index 00000000000..ff5347b3cc6 --- /dev/null +++ b/src/TypeSystem/src/Common/ArrayType.cs @@ -0,0 +1,282 @@ +// 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.Collections.Generic; +using System.Threading; + +namespace Internal.TypeSystem +{ + public sealed class ArrayType : ParameterizedType + { + int _rank; // -1 for regular single dimensional arrays, > 0 for multidimensional arrays + + internal ArrayType(TypeDesc elementType, int rank) + : base(elementType) + { + _rank = rank; + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeArrayTypeHashCode(this.ElementType.GetHashCode(), _rank); + } + + public override MetadataType BaseType + { + get + { + return this.Context.GetWellKnownType(WellKnownType.Array); + } + } + + // TODO: Implement + // public override TypeDesc[] ImplementedInterfaces + // { + // get + // { + // ... + // } + // } + + public TypeDesc ElementType + { + get + { + return this.ParameterType; + } + } + + internal MethodDesc[] _methods; + + public new bool IsSzArray + { + get + { + return _rank < 0; + } + } + + public int Rank + { + get + { + return (_rank < 0) ? 1 : _rank; + } + } + + public override IEnumerable GetMethods() + { + if (_methods == null) + { + int numCtors; + + if (IsSzArray) + { + numCtors = 1; + + var t = this.ElementType; + while (t.IsSzArray) + { + t = ((ArrayType)t).ElementType; + numCtors++; + } + } + else + { + // ELEMENT_TYPE_ARRAY has two ctor functions, one with and one without lower bounds + numCtors = 2; + } + + MethodDesc[] methods = new MethodDesc[(int)ArrayMethodKind.Ctor + numCtors]; + + for (int i = 0; i < methods.Length; i++) + methods[i] = new ArrayMethod(this, (ArrayMethodKind)i); + + Interlocked.CompareExchange(ref _methods, methods, null); + } + return _methods; + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc instantiatedElementType = this.ElementType.InstantiateSignature(typeInstantiation, methodInstantiation); + return instantiatedElementType.Context.GetArrayType(instantiatedElementType); + } + + public override TypeDesc GetTypeDefinition() + { + TypeDesc result = this; + + TypeDesc elementDef = this.ElementType.GetTypeDefinition(); + if (elementDef != this.ElementType) + result = elementDef.Context.GetArrayType(elementDef); + + return result; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.Array; + + if ((mask & TypeFlags.ContainsGenericVariablesComputed) != 0) + { + flags |= TypeFlags.ContainsGenericVariablesComputed; + if (this.ParameterType.ContainsGenericVariables) + flags |= TypeFlags.ContainsGenericVariables; + } + + return flags; + } + + public override string ToString() + { + return this.ElementType.ToString() + "[" + new String(',', Rank - 1) + "]"; + } + } + + public enum ArrayMethodKind + { + Get, + Set, + Address, + Ctor + } + + public class ArrayMethod : MethodDesc + { + ArrayType _owningType; + ArrayMethodKind _kind; + + internal ArrayMethod(ArrayType owningType, ArrayMethodKind kind) + { + _owningType = owningType; + _kind = kind; + } + + public override TypeSystemContext Context + { + get + { + return _owningType.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _owningType; + } + } + + public ArrayMethodKind Kind + { + get + { + return _kind; + } + } + + MethodSignature _signature; + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + switch (_kind) + { + case ArrayMethodKind.Get: + { + var parameters = new TypeDesc[_owningType.Rank]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, _owningType.ElementType, parameters); + break; + } + case ArrayMethodKind.Set: + { + var parameters = new TypeDesc[_owningType.Rank + 1]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + parameters[_owningType.Rank] = _owningType.ElementType; + _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), parameters); + break; + } + case ArrayMethodKind.Address: + { + var parameters = new TypeDesc[_owningType.Rank]; + for (int i = 0; i < _owningType.Rank; i++) + parameters[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, _owningType.ElementType.MakeByRefType(), parameters); + } + break; + default: + { + int numArgs; + if (_owningType.IsSzArray) + { + numArgs = 1 + (int)_kind - (int)ArrayMethodKind.Ctor; + } + else + { + numArgs = (_kind == ArrayMethodKind.Ctor) ? _owningType.Rank : 2 * _owningType.Rank; + } + + var argTypes = new TypeDesc[numArgs]; + for (int i = 0; i < argTypes.Length; i++) + argTypes[i] = _owningType.Context.GetWellKnownType(WellKnownType.Int32); + _signature = new MethodSignature(0, 0, this.Context.GetWellKnownType(WellKnownType.Void), argTypes); + + } + break; + } + } + return _signature; + } + } + + public override string Name + { + get + { + switch (_kind) + { + case ArrayMethodKind.Get: + return "Get"; + case ArrayMethodKind.Set: + return "Set"; + case ArrayMethodKind.Address: + return "Address"; + default: + return ".ctor"; + } + } + } + + // Strips method instantiation. E.g C.m -> C.m + public override MethodDesc GetMethodDefinition() + { + return this; + } + + // Strips both type and method instantiation. E.g C.m -> C.m + public override MethodDesc GetTypicalMethodDefinition() + { + return this; + } + + public override MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc owningType = this.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + + if (owningType != instantiatedOwningType) + return ((ArrayMethod[])instantiatedOwningType.GetMethods())[(int)this._kind]; + else + return this; + } + } +} diff --git a/src/TypeSystem/src/Common/ByRefType.cs b/src/TypeSystem/src/Common/ByRefType.cs new file mode 100644 index 00000000000..8975d79db68 --- /dev/null +++ b/src/TypeSystem/src/Common/ByRefType.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + public sealed class ByRefType : ParameterizedType + { + internal ByRefType(TypeDesc parameter) + : base(parameter) + { + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeByrefTypeHashCode(this.ParameterType.GetHashCode()); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc instantiatedParameterType = this.ParameterType.InstantiateSignature(typeInstantiation, methodInstantiation); + return instantiatedParameterType.MakeByRefType(); + } + + public override TypeDesc GetTypeDefinition() + { + TypeDesc result = this; + + TypeDesc parameterDef = this.ParameterType.GetTypeDefinition(); + if (parameterDef != this.ParameterType) + result = parameterDef.MakeByRefType(); + + return result; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.ByRef; + + if ((mask & TypeFlags.ContainsGenericVariablesComputed) != 0) + { + flags |= TypeFlags.ContainsGenericVariablesComputed; + if (this.ParameterType.ContainsGenericVariables) + flags |= TypeFlags.ContainsGenericVariables; + } + + return flags; + } + + public override string ToString() + { + return this.ParameterType.ToString() + "&"; + } + } +} diff --git a/src/TypeSystem/src/Common/FieldDesc.cs b/src/TypeSystem/src/Common/FieldDesc.cs new file mode 100644 index 00000000000..49abcd383b7 --- /dev/null +++ b/src/TypeSystem/src/Common/FieldDesc.cs @@ -0,0 +1,74 @@ +// 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.Runtime.CompilerServices; + +namespace Internal.TypeSystem +{ + public abstract partial class FieldDesc + { + public readonly static FieldDesc[] EmptyFields = new FieldDesc[0]; + + public override int GetHashCode() + { + // Inherited types are expected to override + return RuntimeHelpers.GetHashCode(this); + } + + public override bool Equals(Object o) + { + return Object.ReferenceEquals(this, o); + } + + public virtual string Name + { + get + { + return null; + } + } + + public abstract TypeSystemContext Context + { + get; + } + + public abstract MetadataType OwningType + { + get; + } + + public abstract TypeDesc FieldType + { + get; + } + + public abstract bool IsStatic + { + get; + } + + public abstract bool IsInitOnly + { + get; + } + + public virtual FieldDesc GetTypicalFieldDefinition() + { + return this; + } + + public virtual FieldDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + FieldDesc field = this; + + TypeDesc owningType = field.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (owningType != instantiatedOwningType) + field = instantiatedOwningType.Context.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)instantiatedOwningType); + + return field; + } + } +} diff --git a/src/TypeSystem/src/Common/FieldForInstantiatedType.cs b/src/TypeSystem/src/Common/FieldForInstantiatedType.cs new file mode 100644 index 00000000000..dde3df0bccb --- /dev/null +++ b/src/TypeSystem/src/Common/FieldForInstantiatedType.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 System; + +namespace Internal.TypeSystem +{ + public sealed class FieldForInstantiatedType : FieldDesc + { + FieldDesc _fieldDef; + InstantiatedType _instantiatedType; + + internal FieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + _fieldDef = fieldDef; + _instantiatedType = instantiatedType; + } + + public override TypeSystemContext Context + { + get + { + return _fieldDef.Context; + } + } + + public override MetadataType OwningType + { + get + { + return _instantiatedType; + } + } + + public override string Name + { + get + { + return _fieldDef.Name; + } + } + + public override TypeDesc FieldType + { + get + { + return _fieldDef.FieldType.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); + } + } + + public override bool IsStatic + { + get + { + return _fieldDef.IsStatic; + } + } + + public override bool IsInitOnly + { + get + { + return _fieldDef.IsInitOnly; + } + } + + public override FieldDesc GetTypicalFieldDefinition() + { + return _fieldDef; + } + } +} diff --git a/src/TypeSystem/src/Common/FieldLayout.cs b/src/TypeSystem/src/Common/FieldLayout.cs new file mode 100644 index 00000000000..9d87f6b681a --- /dev/null +++ b/src/TypeSystem/src/Common/FieldLayout.cs @@ -0,0 +1,570 @@ +// 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.Linq; +using Debug = System.Diagnostics.Debug; +using Interlocked = System.Threading.Interlocked; + +namespace Internal.TypeSystem +{ + public struct InstanceFieldMason + { + private MetadataType _type; + private int _numInstanceFields; + + private ComputedInstanceFieldLayout _computedLayout; + + private InstanceFieldMason(MetadataType type, int numInstanceFields) + { + _type = type; + _computedLayout = new ComputedInstanceFieldLayout(); + _numInstanceFields = numInstanceFields; + } + + public static ComputedInstanceFieldLayout ComputeFieldLayout(MetadataType type) + { + // CLI - Partition 1, section 9.5 - Generic types shall not be marked explicitlayout. + if (type.HasInstantiation && type.IsExplicitLayout) + { + throw new TypeLoadException(); + } + + // Count the number of instance fields in advance for convenience + int numInstanceFields = 0; + foreach (var field in type.GetFields()) + if (!field.IsStatic) + numInstanceFields++; + + if (type.IsModuleType) + { + // This is a global type, it must not have instance fields. + if (numInstanceFields > 0) + { + throw new TypeLoadException(); + } + + // Global types do not do the rest of instance field layout. + ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout(); + result.PackValue = type.Context.Target.DefaultPackingSize; + return result; + } + + // CLI - Partition 2, section 22.8 + // A type has layout if it is marked SequentialLayout or ExplicitLayout. If any type within an inheritance chain has layout, + // then so shall all its base classes, up to the one that descends immediately from System.ValueType (if it exists in the type’s + // hierarchy); otherwise, from System.Object + // Note: While the CLI isn't clearly worded, the layout needs to be the same for the entire chain. + // If the current type isn't ValueType or System.Object and has a layout and the parent type isn't + // ValueType or System.Object then the layout type attributes need to match + if ((!type.IsValueType && !type.IsObject) && + (type.IsSequentialLayout || type.IsExplicitLayout) && + (!type.BaseType.IsValueType && !type.BaseType.IsObject)) + { + MetadataType baseType = type.BaseType; + + if (type.IsSequentialLayout != baseType.IsSequentialLayout || + type.IsExplicitLayout != baseType.IsExplicitLayout) + { + throw new TypeLoadException(); + } + } + + // Enum types must have a single instance field + if (type.IsEnum && numInstanceFields != 1) + { + throw new TypeLoadException(); + } + + if (type.IsPrimitive) + { + // Primitive types are special - they may have a single field of the same type + // as the type itself. They do not do the rest of instance field layout. + if (numInstanceFields > 1) + { + throw new TypeLoadException(); + } + + int byteCount; + var sizeAndAlignment = ComputeInstanceSize( + type, + type.Context.Target.GetWellKnownTypeSize(type), + type.Context.Target.GetWellKnownTypeAlignment(type), + out byteCount + ); + + ComputedInstanceFieldLayout result = new ComputedInstanceFieldLayout + { + ByteCount = byteCount, + FieldAlignment = sizeAndAlignment.Alignment, + FieldSize = sizeAndAlignment.Size, + PackValue = type.Context.Target.DefaultPackingSize + }; + + if (numInstanceFields > 0) + { + result.Offsets = new FieldAndOffset[] { + new FieldAndOffset(type.GetFields().Single(f => !f.IsStatic), 0) + }; + } + + return result; + } + + // Verify that no ByRef types present in this type's fields + foreach (var field in type.GetFields()) + if (field.FieldType is ByRefType) + throw new TypeLoadException(); + + // If the type has layout, read its packing and size info + // If the type has explicit layout, also read the field offset info + if (type.IsExplicitLayout || type.IsSequentialLayout) + { + if (type.IsEnum) + { + throw new TypeLoadException(); + } + + var layoutMetadata = type.GetClassLayout(); + + // If packing is out of range or not a power of two, throw that the size is invalid + int packing = layoutMetadata.PackingSize; + if (packing < 0 || packing > 128 || ((packing & (packing - 1)) != 0)) + { + throw new TypeLoadException(); + } + + Debug.Assert(layoutMetadata.Offsets == null || layoutMetadata.Offsets.Length == numInstanceFields); + } + + // At this point all special cases are handled and all inputs validated + + InstanceFieldMason mason = new InstanceFieldMason(type, numInstanceFields); + + if (type.IsExplicitLayout) + { + mason.ComputeExplicitFieldLayout(); + } + else + { + // Treat auto layout as sequential for now + mason.ComputeSequentialFieldLayout(); + } + + return mason._computedLayout; + } + + private void ComputeExplicitFieldLayout() + { + // Instance slice size is the total size of instance not including the base type. + // It is calculated as the field whose offset and size add to the greatest value. + int cumulativeInstanceFieldPos = + _type.HasBaseType && !_type.IsValueType ? _type.BaseType.InstanceByteCount : 0; + int instanceSize = cumulativeInstanceFieldPos; + + var layoutMetadata = _type.GetClassLayout(); + + int packingSize = ComputePackingSize(_type); + int largestAlignmentRequired = 1; + + var offsets = new FieldAndOffset[_numInstanceFields]; + int fieldOrdinal = 0; + + foreach (var fieldAndOffset in layoutMetadata.Offsets) + { + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldAndOffset.Field.FieldType, packingSize); + + if (fieldSizeAndAlignment.Alignment > largestAlignmentRequired) + largestAlignmentRequired = fieldSizeAndAlignment.Alignment; + + if (fieldAndOffset.Offset == FieldAndOffset.InvalidOffset) + throw new TypeLoadException(); + + int computedOffset = checked(fieldAndOffset.Offset + cumulativeInstanceFieldPos); + + switch (fieldAndOffset.Field.FieldType.Category) + { + case TypeFlags.Array: + case TypeFlags.Class: + { + int offsetModulo = computedOffset % _type.Context.Target.PointerSize; + if (offsetModulo != 0) + { + // GC pointers MUST be aligned. + if (offsetModulo == 4) + { + // We must be attempting to compile a 32bit app targeting a 64 bit platform. + throw new TypeLoadException(); + } + else + { + // Its just wrong + throw new TypeLoadException(); + } + } + break; + } + } + + offsets[fieldOrdinal] = new FieldAndOffset(fieldAndOffset.Field, computedOffset); + + int fieldExtent = checked(computedOffset + fieldSizeAndAlignment.Size); + if (fieldExtent > instanceSize) + { + instanceSize = fieldExtent; + } + + fieldOrdinal++; + } + + if (_type.IsValueType && layoutMetadata.Size > instanceSize) + { + instanceSize = layoutMetadata.Size; + } + + int instanceByteCount; + var instanceSizeAndAlignment = ComputeInstanceSize(_type, instanceSize, largestAlignmentRequired, out instanceByteCount); + + _computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; + _computedLayout.FieldSize = instanceSizeAndAlignment.Size; + _computedLayout.ByteCount = instanceByteCount; + _computedLayout.Offsets = offsets; + } + + private void ComputeSequentialFieldLayout() + { + var offsets = new FieldAndOffset[_numInstanceFields]; + + // For types inheriting from another type, field offsets continue on from where they left off + int cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(_type); + + int largestAlignmentRequirement = 1; + int fieldOrdinal = 0; + int packingSize = ComputePackingSize(_type); + + foreach (var field in _type.GetFields()) + { + if (field.IsStatic) + continue; + + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, packingSize); + + if (fieldSizeAndAlignment.Alignment > largestAlignmentRequirement) + largestAlignmentRequirement = fieldSizeAndAlignment.Alignment; + + cumulativeInstanceFieldPos = AlignmentHelper.AlignUp(cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment); + offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos); + cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size); + + fieldOrdinal++; + } + + if (_type.IsValueType) + { + var layoutMetadata = _type.GetClassLayout(); + cumulativeInstanceFieldPos = Math.Max(cumulativeInstanceFieldPos, layoutMetadata.Size); + } + + int instanceByteCount; + var instanceSizeAndAlignment = ComputeInstanceSize(_type, cumulativeInstanceFieldPos, largestAlignmentRequirement, out instanceByteCount); + + _computedLayout.FieldAlignment = instanceSizeAndAlignment.Alignment; + _computedLayout.FieldSize = instanceSizeAndAlignment.Size; + _computedLayout.ByteCount = instanceByteCount; + _computedLayout.Offsets = offsets; + } + + private static int ComputeBytesUsedInParentType(MetadataType type) + { + int cumulativeInstanceFieldPos = 0; + + if (!type.IsValueType && type.HasBaseType) + { + cumulativeInstanceFieldPos = ComputeBytesUsedInParentType(type.BaseType); + + foreach (var field in type.BaseType.GetFields()) + { + if (field.IsStatic) + continue; + + // We can pass zero as packing size because we don't care about the alignment part + SizeAndAlignment sizeAndAlignment = ComputeFieldSizeAndAlignment(field.FieldType, 0); + int fieldEnd = checked(field.Offset + sizeAndAlignment.Size); + + if (fieldEnd > cumulativeInstanceFieldPos) + cumulativeInstanceFieldPos = fieldEnd; + } + } + + return cumulativeInstanceFieldPos; + } + + private static SizeAndAlignment ComputeFieldSizeAndAlignment(TypeDesc fieldType, int packingSize) + { + SizeAndAlignment result; + + if (fieldType is MetadataType) + { + if (fieldType.IsValueType) + { + MetadataType metadataType = (MetadataType)fieldType; + result.Size = metadataType.InstanceFieldSize; + result.Alignment = metadataType.InstanceFieldAlignment; + } + else + { + result.Size = fieldType.Context.Target.PointerSize; + result.Alignment = fieldType.Context.Target.PointerSize; + } + } + else if (fieldType is ByRefType || fieldType is ArrayType) + { + result.Size = fieldType.Context.Target.PointerSize; + result.Alignment = fieldType.Context.Target.PointerSize; + } + else if (fieldType is PointerType) + { + result.Size = fieldType.Context.Target.PointerSize; + result.Alignment = fieldType.Context.Target.PointerSize; + } + else + throw new NotImplementedException(); + + result.Alignment = Math.Min(result.Alignment, packingSize); + + return result; + } + + private static int ComputePackingSize(MetadataType type) + { + var layoutMetadata = type.GetClassLayout(); + + // If a type contains pointers then the metadata specified packing size is ignored (On desktop this is disqualification from ManagedSequential) + if (layoutMetadata.PackingSize == 0 || type.ContainsPointers) + return type.Context.Target.DefaultPackingSize; + else + return layoutMetadata.PackingSize; + } + + private static SizeAndAlignment ComputeInstanceSize(MetadataType type, int count, int alignment, out int byteCount) + { + SizeAndAlignment result; + + count = AlignmentHelper.AlignUp(count, alignment); + + int targetPointerSize = type.Context.Target.PointerSize; + + // Pad the length of structs to be 1 if they are empty so we have no zero-length structures + if (type.IsValueType && count == 0) + { + count = 1; + } + + if (type.IsValueType) + { + result.Size = count; + result.Alignment = alignment; + } + else + { + result.Size = targetPointerSize; + result.Alignment = targetPointerSize; + } + + // Size all objects on pointer boundaries because the GC requires it if any fields are object refs + count = AlignmentHelper.AlignUp(count, targetPointerSize); + byteCount = count; + + return result; + } + + private struct SizeAndAlignment + { + public int Size; + public int Alignment; + } + } + + public partial class MetadataType + { + private class FieldLayoutFlags + { + public const int HasContainsPointers = 1; + public const int ContainsPointers = 2; + public const int HasInstanceFieldLayout = 4; + } + + volatile int _fieldLayoutFlags; + + int _instanceFieldSize; + int _instanceByteCount; + int _instanceFieldAlignment; + + public bool ContainsPointers + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasContainsPointers) == 0) + { + var flagsToAdd = FieldLayoutFlags.HasContainsPointers; + + if (ComputeTypeContainsPointers()) + flagsToAdd |= FieldLayoutFlags.ContainsPointers; + + EnableFieldLayoutFlags(flagsToAdd); + } + return (_fieldLayoutFlags & FieldLayoutFlags.ContainsPointers) != 0; + } + } + + public int InstanceFieldSize + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasInstanceFieldLayout) == 0) + { + ComputeInstanceFieldLayout(); + } + return _instanceFieldSize; + } + } + + public int InstanceFieldAlignment + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasInstanceFieldLayout) == 0) + { + ComputeInstanceFieldLayout(); + } + return _instanceFieldAlignment; + } + } + + public int InstanceByteCount + { + get + { + if ((_fieldLayoutFlags & FieldLayoutFlags.HasInstanceFieldLayout) == 0) + { + ComputeInstanceFieldLayout(); + } + return _instanceByteCount; + } + } + + internal void ComputeInstanceFieldLayout() + { + var computedLayout = InstanceFieldMason.ComputeFieldLayout(this); + + _instanceFieldSize = computedLayout.FieldSize; + _instanceFieldAlignment = computedLayout.FieldAlignment; + _instanceByteCount = computedLayout.ByteCount; + + foreach (var fieldAndOffset in computedLayout.Offsets) + { + Debug.Assert(fieldAndOffset.Field.OwningType == this); + fieldAndOffset.Field.InitializeOffset(fieldAndOffset.Offset); + } + + EnableFieldLayoutFlags(FieldLayoutFlags.HasInstanceFieldLayout); + } + + private bool ComputeTypeContainsPointers() + { + if (!IsValueType && HasBaseType && BaseType.ContainsPointers) + return true; + + foreach (var field in GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + switch (fieldType.Category) + { + // case TypeFlags.SzArray? + case TypeFlags.Array: + case TypeFlags.Class: + // case TypeFlags.MethodGenericParameter? + case TypeFlags.GenericParameter: + case TypeFlags.ByRef: + return true; + case TypeFlags.ValueType: + if (((MetadataType)fieldType).ContainsPointers) + return true; + break; + } + } + + return false; + } + + private void EnableFieldLayoutFlags(int flagsToAdd) + { + var originalFlags = _fieldLayoutFlags; + while (Interlocked.CompareExchange(ref _fieldLayoutFlags, originalFlags | flagsToAdd, originalFlags) != originalFlags) + { + originalFlags = _fieldLayoutFlags; + } + } + } + + public partial class InstantiatedType + { + public override ClassLayoutMetadata GetClassLayout() + { + return _typeDef.GetClassLayout(); + } + + public override bool IsExplicitLayout + { + get + { + return _typeDef.IsExplicitLayout; + } + } + + public override bool IsSequentialLayout + { + get + { + return _typeDef.IsSequentialLayout; + } + } + + public override bool IsModuleType { get { return false; } } + } + + public partial class FieldDesc + { + private int _offset = FieldAndOffset.InvalidOffset; + + public int Offset + { + get + { + if (_offset == FieldAndOffset.InvalidOffset) + { + OwningType.ComputeInstanceFieldLayout(); + } + return _offset; + } + } + + internal void InitializeOffset(int offset) + { + Debug.Assert(_offset == FieldAndOffset.InvalidOffset || _offset == offset); + _offset = offset; + } + } + + public struct ComputedInstanceFieldLayout + { + public int PackValue; + public int FieldSize; + public int FieldAlignment; + public int ByteCount; + public FieldAndOffset[] Offsets; + } +} diff --git a/src/TypeSystem/src/Common/InstantiatedMethod.cs b/src/TypeSystem/src/Common/InstantiatedMethod.cs new file mode 100644 index 00000000000..03d1940d5b8 --- /dev/null +++ b/src/TypeSystem/src/Common/InstantiatedMethod.cs @@ -0,0 +1,98 @@ +// 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; + +namespace Internal.TypeSystem +{ + public sealed class InstantiatedMethod : MethodDesc + { + MethodDesc _methodDef; + Instantiation _instantiation; + + MethodSignature _signature; + + internal InstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) + { + Debug.Assert(!(methodDef is InstantiatedMethod)); + _methodDef = methodDef; + + Debug.Assert(instantiation.Length > 0); + _instantiation = instantiation; + } + + public override TypeSystemContext Context + { + get + { + return _methodDef.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _methodDef.OwningType; + } + } + + TypeDesc Instantiate(TypeDesc type) + { + return type.InstantiateSignature(new Instantiation(), _instantiation); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + MethodSignature template = _methodDef.Signature; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.ReturnType = Instantiate(template.ReturnType); + for (int i = 0; i < template.Length; i++) + builder[i] = Instantiate(template[i]); + + _signature = builder.ToSignature(); + } + + return _signature; + } + } + + public override Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + public override MethodDesc GetMethodDefinition() + { + return _methodDef; + } + + public override MethodDesc GetTypicalMethodDefinition() + { + return _methodDef.GetTypicalMethodDefinition(); + } + + public override string Name + { + get + { + return _methodDef.Name; + } + } + + public override string ToString() + { + // TODO: Append instantiation + return _methodDef.ToString(); + } + } +} diff --git a/src/TypeSystem/src/Common/InstantiatedType.cs b/src/TypeSystem/src/Common/InstantiatedType.cs new file mode 100644 index 00000000000..557cb95e0ce --- /dev/null +++ b/src/TypeSystem/src/Common/InstantiatedType.cs @@ -0,0 +1,207 @@ +// 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.Collections.Generic; +using System.Diagnostics; + +namespace Internal.TypeSystem +{ + public sealed partial class InstantiatedType : MetadataType + { + MetadataType _typeDef; + Instantiation _instantiation; + + internal InstantiatedType(MetadataType typeDef, Instantiation instantiation) + { + Debug.Assert(!(typeDef is InstantiatedType)); + _typeDef = typeDef; + + Debug.Assert(instantiation.Length > 0); + _instantiation = instantiation; + + _baseType = this; // Not yet initialized flag + } + + int _hashCode; + + public override int GetHashCode() + { + if (_hashCode == 0) + _hashCode = Internal.NativeFormat.TypeHashingAlgorithms.ComputeGenericInstanceHashCode(_typeDef.GetHashCode(), _instantiation); + return _hashCode; + } + + public override TypeSystemContext Context + { + get + { + return _typeDef.Context; + } + } + + public override Instantiation Instantiation + { + get + { + return _instantiation; + } + } + + MetadataType _baseType /* = this */; + + MetadataType InitializeBaseType() + { + var uninst = _typeDef.BaseType; + + return (_baseType = (uninst != null) ? (MetadataType)uninst.InstantiateSignature(_instantiation, new Instantiation()) : null); + } + + public override MetadataType BaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + TypeDesc[] _implementedInterfaces = null; + + TypeDesc[] InitializeImplementedInterfaces() + { + TypeDesc[] uninstInterfaces = _typeDef.ImplementedInterfaces; + TypeDesc[] instInterfaces = null; + + for (int i = 0; i GetMethods() + { + foreach (var typicalMethodDef in _typeDef.GetMethods()) + { + yield return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); + } + } + + // TODO: Substitutions, generics, modopts, ... + public override MethodDesc GetMethod(string name, MethodSignature signature) + { + MethodDesc typicalMethodDef = _typeDef.GetMethod(name, signature); + if (typicalMethodDef == null) + return null; + return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this); + } + + public override IEnumerable GetFields() + { + foreach (var fieldDef in _typeDef.GetFields()) + { + yield return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); + } + } + + // TODO: Substitutions, generics, modopts, ... + public override FieldDesc GetField(string name) + { + FieldDesc fieldDef = _typeDef.GetField(name); + if (fieldDef == null) + return null; + return _typeDef.Context.GetFieldForInstantiatedType(fieldDef, this); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc[] clone = null; + + for (int i = 0; i < _instantiation.Length; i++) + { + TypeDesc uninst = _instantiation[i]; + TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[_instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = _instantiation[j]; + } + } + clone[i] = inst; + } + } + + return (clone == null) ? this : _typeDef.Context.GetInstantiatedType(_typeDef, new Instantiation(clone)); + } + + // Strips instantiation. E.g C -> C + public override TypeDesc GetTypeDefinition() + { + return _typeDef; + } + } +} diff --git a/src/TypeSystem/src/Common/MetadataType.cs b/src/TypeSystem/src/Common/MetadataType.cs new file mode 100644 index 00000000000..6a4f65cd9e0 --- /dev/null +++ b/src/TypeSystem/src/Common/MetadataType.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. + +namespace Internal.TypeSystem +{ + public abstract partial class MetadataType : TypeDesc + { + public abstract ClassLayoutMetadata GetClassLayout(); + + public abstract bool IsExplicitLayout { get; } + + public abstract bool IsSequentialLayout { get; } + + public abstract bool IsModuleType { get; } + } + + public struct ClassLayoutMetadata + { + public int PackingSize; + public int Size; + public FieldAndOffset[] Offsets; + } + + public struct FieldAndOffset + { + public const int InvalidOffset = -1; + + public readonly FieldDesc Field; + public readonly int Offset; + public FieldAndOffset(FieldDesc field, int offset) + { + Field = field; + Offset = offset; + } + } +} diff --git a/src/TypeSystem/src/Common/MethodDesc.cs b/src/TypeSystem/src/Common/MethodDesc.cs new file mode 100644 index 00000000000..c81ac53f409 --- /dev/null +++ b/src/TypeSystem/src/Common/MethodDesc.cs @@ -0,0 +1,339 @@ +// 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.Runtime.CompilerServices; + +namespace Internal.TypeSystem +{ + [Flags] + public enum MethodSignatureFlags + { + Static = 0x0001, + // TODO: Generic, etc. + } + + public sealed class MethodSignature + { + internal MethodSignatureFlags _flags; + internal int _genericParameterCount; + internal TypeDesc _returnType; + internal TypeDesc[] _parameters; + + public MethodSignature(MethodSignatureFlags flags, int genericParameterCount, TypeDesc returnType, TypeDesc[] parameters) + { + _flags = flags; + _genericParameterCount = genericParameterCount; + _returnType = returnType; + _parameters = parameters; + } + + public MethodSignatureFlags Flags + { + get + { + return _flags; + } + } + + public bool IsStatic + { + get + { + return (_flags & MethodSignatureFlags.Static) != 0; + } + } + + public int GenericParameterCount + { + get + { + return _genericParameterCount; + } + } + + public TypeDesc ReturnType + { + get + { + return _returnType; + } + } + + [System.Runtime.CompilerServices.IndexerName("Parameter")] + public TypeDesc this[int index] + { + get + { + return _parameters[index]; + } + } + + public int Length + { + get + { + return _parameters.Length; + } + } + + public bool Equals(MethodSignature otherSignature) + { + // TODO: Generics, etc. + if (this._flags != otherSignature._flags) + return false; + + if (this._genericParameterCount != otherSignature._genericParameterCount) + return false; + + if (this._returnType != otherSignature._returnType) + return false; + + if (this._parameters.Length != otherSignature._parameters.Length) + return false; + + for (int i = 0; i < this._parameters.Length; i++) + { + if (this._parameters[i] != otherSignature._parameters[i]) + return false; + } + + return true; + } + } + + public struct MethodSignatureBuilder + { + MethodSignature _template; + MethodSignatureFlags _flags; + int _genericParameterCount; + TypeDesc _returnType; + TypeDesc[] _parameters; + + public MethodSignatureBuilder(MethodSignature template) + { + _template = template; + + _flags = template._flags; + _genericParameterCount = template._genericParameterCount; + _returnType = template._returnType; + _parameters = template._parameters; + } + + public MethodSignatureFlags Flags + { + set + { + _flags = value; + } + } + + public TypeDesc ReturnType + { + set + { + _returnType = value; + } + } + + [System.Runtime.CompilerServices.IndexerName("Parameter")] + public TypeDesc this[int index] + { + set + { + if (_parameters[index] == value) + return; + + if (_template != null && _parameters == _template._parameters) + { + TypeDesc[] parameters = new TypeDesc[_parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + parameters[i] = _parameters[i]; + _parameters = parameters; + } + _parameters[index] = value; + } + } + + public int Length + { + set + { + _parameters = new TypeDesc[value]; + _template = null; + } + } + + public MethodSignature ToSignature() + { + if (_template == null || + _flags != _template._flags || + _genericParameterCount != _template._genericParameterCount || + _returnType != _template._returnType || + _parameters != _template._parameters) + { + _template = new MethodSignature(_flags, _genericParameterCount, _returnType, _parameters); + } + + return _template; + } + } + + public abstract partial class MethodDesc + { + public readonly static MethodDesc[] EmptyMethods = new MethodDesc[0]; + + public override int GetHashCode() + { + // Inherited types are expected to override + return RuntimeHelpers.GetHashCode(this); + } + + public override bool Equals(Object o) + { + return Object.ReferenceEquals(this, o); + } + + public abstract TypeSystemContext Context + { + get; + } + + public abstract TypeDesc OwningType + { + get; + } + + public abstract MethodSignature Signature + { + get; + } + + public virtual Instantiation Instantiation + { + get + { + return Instantiation.Empty; + } + } + + public bool HasInstantiation + { + get + { + return this.Instantiation.Length != 0; + } + } + + public bool ContainsGenericVariables + { + get + { + // TODO: Cache? + + Instantiation instantiation = this.Instantiation; + for (int i = 0; i < instantiation.Length; i++) + { + if (instantiation[i].ContainsGenericVariables) + return true; + } + return false; + } + } + + public bool IsConstructor + { + get + { + // TODO: Precise check + // TODO: Cache? + return this.Name == ".ctor"; + } + } + + public virtual string Name + { + get + { + return null; + } + } + + public virtual bool IsVirtual + { + get + { + return false; + } + } + + public virtual bool IsNewSlot + { + get + { + return false; + } + } + + // Strips method instantiation. E.g C.m -> C.m + public virtual MethodDesc GetMethodDefinition() + { + return this; + } + + public bool IsMethodDefinition + { + get + { + return GetMethodDefinition() == this; + } + } + + // Strips both type and method instantiation. E.g C.m -> C.m + public virtual MethodDesc GetTypicalMethodDefinition() + { + return this; + } + + public bool IsTypicalMethodDefinition + { + get + { + return GetTypicalMethodDefinition() == this; + } + } + + public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + MethodDesc method = this; + + TypeDesc owningType = method.OwningType; + TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); + if (owningType != instantiatedOwningType) + method = instantiatedOwningType.Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); + + Instantiation instantiation = method.Instantiation; + TypeDesc[] clone = null; + + for (int i = 0; i < instantiation.Length; i++) + { + TypeDesc uninst = instantiation[i]; + TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); + if (inst != uninst) + { + if (clone == null) + { + clone = new TypeDesc[instantiation.Length]; + for (int j = 0; j < clone.Length; j++) + { + clone[j] = instantiation[j]; + } + } + clone[i] = inst; + } + } + + return (clone == null) ? method : method.Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); + } + } +} diff --git a/src/TypeSystem/src/Common/MethodForInstantiatedType.cs b/src/TypeSystem/src/Common/MethodForInstantiatedType.cs new file mode 100644 index 00000000000..e230f153b61 --- /dev/null +++ b/src/TypeSystem/src/Common/MethodForInstantiatedType.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + public sealed class MethodForInstantiatedType : MethodDesc + { + MethodDesc _typicalMethodDef; + InstantiatedType _instantiatedType; + + MethodSignature _signature; + + internal MethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + _typicalMethodDef = typicalMethodDef; + _instantiatedType = instantiatedType; + } + + public override TypeSystemContext Context + { + get + { + return _typicalMethodDef.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _instantiatedType; + } + } + + TypeDesc Instantiate(TypeDesc type) + { + return type.InstantiateSignature(_instantiatedType.Instantiation, new Instantiation()); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + { + MethodSignature template = _typicalMethodDef.Signature; + MethodSignatureBuilder builder = new MethodSignatureBuilder(template); + + builder.ReturnType = Instantiate(template.ReturnType); + for (int i = 0; i < template.Length; i++) + builder[i] = Instantiate(template[i]); + + _signature = builder.ToSignature(); + } + + return _signature; + } + } + + public override Instantiation Instantiation + { + get + { + return _typicalMethodDef.Instantiation; + } + } + + public override MethodDesc GetTypicalMethodDefinition() + { + return _typicalMethodDef; + } + + public override string Name + { + get + { + return _typicalMethodDef.Name; + } + } + + public override string ToString() + { + // TODO: Append instantiation + return _typicalMethodDef.ToString(); + } + + } +} diff --git a/src/TypeSystem/src/Common/ParameterizedType.cs b/src/TypeSystem/src/Common/ParameterizedType.cs new file mode 100644 index 00000000000..c4e9a89f3af --- /dev/null +++ b/src/TypeSystem/src/Common/ParameterizedType.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 System; + +namespace Internal.TypeSystem +{ + public abstract class ParameterizedType : TypeDesc + { + TypeDesc _parameterType; + + internal ParameterizedType(TypeDesc parameterType) + { + _parameterType = parameterType; + } + + public TypeDesc ParameterType + { + get + { + return _parameterType; + } + } + + public override TypeSystemContext Context + { + get + { + return _parameterType.Context; + } + } + } +} diff --git a/src/TypeSystem/src/Common/PointerType.cs b/src/TypeSystem/src/Common/PointerType.cs new file mode 100644 index 00000000000..9ab85950cac --- /dev/null +++ b/src/TypeSystem/src/Common/PointerType.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + public sealed class PointerType : ParameterizedType + { + internal PointerType(TypeDesc parameterType) + : base(parameterType) + { + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputePointerTypeHashCode(this.ParameterType.GetHashCode()); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + TypeDesc instantiatedParameterType = this.ParameterType.InstantiateSignature(typeInstantiation, methodInstantiation); + return instantiatedParameterType.Context.GetPointerType(instantiatedParameterType); + } + + public override TypeDesc GetTypeDefinition() + { + TypeDesc result = this; + + TypeDesc parameterDef = this.ParameterType.GetTypeDefinition(); + if (parameterDef != this.ParameterType) + result = parameterDef.Context.GetPointerType(parameterDef); + + return result; + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = TypeFlags.Pointer; + + if ((mask & TypeFlags.ContainsGenericVariablesComputed) != 0) + { + flags |= TypeFlags.ContainsGenericVariablesComputed; + if (this.ParameterType.ContainsGenericVariables) + flags |= TypeFlags.ContainsGenericVariables; + } + + return flags; + } + + public override string ToString() + { + return this.ParameterType.ToString() + "*"; + } + } +} diff --git a/src/TypeSystem/src/Common/SignatureVariable.cs b/src/TypeSystem/src/Common/SignatureVariable.cs new file mode 100644 index 00000000000..8619461ebfb --- /dev/null +++ b/src/TypeSystem/src/Common/SignatureVariable.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + public sealed class SignatureTypeVariable : TypeDesc + { + TypeSystemContext _context; + int _index; + + internal SignatureTypeVariable(TypeSystemContext context, int index) + { + _context = context; + _index = index; + } + + public override int GetHashCode() + { + return _index * 0x5498341 + 0x832424; + } + + public override TypeSystemContext Context + { + get + { + return _context; + } + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + throw new NotImplementedException(); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return typeInstantiation.IsNull ? this : typeInstantiation[_index]; + } + } + + public sealed class SignatureMethodVariable : TypeDesc + { + TypeSystemContext _context; + int _index; + + internal SignatureMethodVariable(TypeSystemContext context, int index) + { + _context = context; + _index = index; + } + + public override int GetHashCode() + { + return _index * 0x7822381 + 0x54872645; + } + + public override TypeSystemContext Context + { + get + { + return _context; + } + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + throw new NotImplementedException(); + } + + public override TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return methodInstantiation.IsNull ? this : methodInstantiation[_index]; + } + } +} diff --git a/src/TypeSystem/src/Common/TargetDetails.cs b/src/TypeSystem/src/Common/TargetDetails.cs new file mode 100644 index 00000000000..15c2f6c7c3c --- /dev/null +++ b/src/TypeSystem/src/Common/TargetDetails.cs @@ -0,0 +1,92 @@ +// 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 Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + public enum TargetArchitecture + { + Unknown, + X64, + } + + public class TargetDetails + { + public TargetArchitecture Architecture + { + get; private set; + } + + public int PointerSize + { + get + { + switch (Architecture) + { + case TargetArchitecture.X64: + return 8; + default: + throw new NotImplementedException(); + } + } + } + + public int DefaultPackingSize + { + get + { + // We use default packing size of 8 irrespective of the platform. + return 8; + } + } + + public TargetDetails(TargetArchitecture architecture) + { + Architecture = architecture; + } + + public int GetWellKnownTypeSize(MetadataType type) + { + switch (type.Category) + { + case TypeFlags.Void: + return PointerSize; + case TypeFlags.Boolean: + return 1; + case TypeFlags.Char: + return 2; + case TypeFlags.Byte: + case TypeFlags.SByte: + return 1; + case TypeFlags.UInt16: + case TypeFlags.Int16: + return 2; + case TypeFlags.UInt32: + case TypeFlags.Int32: + return 4; + case TypeFlags.UInt64: + case TypeFlags.Int64: + return 8; + case TypeFlags.Single: + return 4; + case TypeFlags.Double: + return 8; + case TypeFlags.UIntPtr: + case TypeFlags.IntPtr: + return PointerSize; + } + + // Add new well known types if necessary + + throw new InvalidOperationException(); + } + + public int GetWellKnownTypeAlignment(MetadataType type) + { + // Size == Alignment for all platforms. + return GetWellKnownTypeSize(type); + } + } +} diff --git a/src/TypeSystem/src/Common/TypeCast.cs b/src/TypeSystem/src/Common/TypeCast.cs new file mode 100644 index 00000000000..13df8057743 --- /dev/null +++ b/src/TypeSystem/src/Common/TypeCast.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + static public class TypeCast + { + // + // Is the source type derived from the target type? + // + static public bool IsDerived(TypeDesc derivedType, TypeDesc baseType) + { + for (;;) + { + if (derivedType == baseType) + return true; + + derivedType = derivedType.BaseType; + if (derivedType == null) + return false; + } + } + + } +} diff --git a/src/TypeSystem/src/Common/TypeDesc.cs b/src/TypeSystem/src/Common/TypeDesc.cs new file mode 100644 index 00000000000..0636c4695be --- /dev/null +++ b/src/TypeSystem/src/Common/TypeDesc.cs @@ -0,0 +1,393 @@ +// 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; +using System.Collections.Generic; + +using System.Runtime.CompilerServices; + +namespace Internal.TypeSystem +{ + public struct Instantiation + { + TypeDesc[] _genericParameters; + + public Instantiation(TypeDesc[] genericParameters) + { + _genericParameters = genericParameters; + } + + [System.Runtime.CompilerServices.IndexerName("GenericParameters")] + public TypeDesc this[int index] + { + get + { + return _genericParameters[index]; + } + } + + public int Length + { + get + { + return _genericParameters.Length; + } + } + + public bool IsNull + { + get + { + return _genericParameters == null; + } + } + + public IEnumerable GetEnumerator() + { + return _genericParameters; + } + + public static readonly Instantiation Empty = new Instantiation(TypeDesc.EmptyTypes); + } + + public abstract partial class TypeDesc + { + public static readonly TypeDesc[] EmptyTypes = new TypeDesc[0]; + + public override int GetHashCode() + { + // Inherited types are expected to override + return RuntimeHelpers.GetHashCode(this); + } + + public override bool Equals(Object o) + { + return Object.ReferenceEquals(this, o); + } + + // The most frequently used type properties are cached here to avoid excesive virtual calls + TypeFlags _typeFlags; + + public abstract TypeSystemContext Context + { + get; + } + + public virtual Instantiation Instantiation + { + get + { + return Instantiation.Empty; + } + } + + public bool HasInstantiation + { + get + { + return this.Instantiation.Length != 0; + } + } + + public void SetWellKnownType(WellKnownType wellKnownType) + { + TypeFlags flags; + + switch (wellKnownType) + { + case WellKnownType.Void: + case WellKnownType.Boolean: + case WellKnownType.Char: + case WellKnownType.SByte: + case WellKnownType.Byte: + case WellKnownType.Int16: + case WellKnownType.UInt16: + case WellKnownType.Int32: + case WellKnownType.UInt32: + case WellKnownType.Int64: + case WellKnownType.UInt64: + case WellKnownType.IntPtr: + case WellKnownType.UIntPtr: + case WellKnownType.Single: + case WellKnownType.Double: + flags = (TypeFlags)wellKnownType; + break; + + case WellKnownType.ValueType: + case WellKnownType.Enum: + flags = TypeFlags.Class; + break; + + case WellKnownType.Nullable: + flags = TypeFlags.Nullable; + break; + + case WellKnownType.Object: + case WellKnownType.String: + case WellKnownType.Array: + case WellKnownType.MulticastDelegate: + case WellKnownType.Exception: + flags = TypeFlags.Class; + break; + + case WellKnownType.RuntimeTypeHandle: + case WellKnownType.RuntimeMethodHandle: + case WellKnownType.RuntimeFieldHandle: + flags = TypeFlags.ValueType; + break; + + default: + throw new ArgumentException(); + } + + _typeFlags = flags; + } + + protected abstract TypeFlags ComputeTypeFlags(TypeFlags mask); + + [MethodImpl(MethodImplOptions.NoInlining)] + TypeFlags InitializeTypeFlags(TypeFlags mask) + { + TypeFlags flags = ComputeTypeFlags(mask); + + Debug.Assert((flags & mask) != 0); + _typeFlags |= flags; + + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected TypeFlags GetTypeFlags(TypeFlags mask) + { + TypeFlags flags = _typeFlags & mask; + if (flags != 0) + return flags; + return InitializeTypeFlags(mask); + } + + public TypeFlags Category + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask); + } + } + + public bool IsInterface + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Interface; + } + } + + public bool IsValueType + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.Class; + } + } + + public bool IsPrimitive + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) < TypeFlags.ValueType; + } + } + + public bool IsEnum + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Enum; + } + } + + public bool IsDelegate + { + get + { + return this.Context.IsWellKnownType(this.BaseType, WellKnownType.MulticastDelegate); + } + } + + public bool IsVoid + { + get + { + return GetTypeFlags(TypeFlags.CategoryMask) == TypeFlags.Void; + } + } + + public bool IsString + { + get + { + return this.Context.IsWellKnownType(this, WellKnownType.String); + } + } + + public bool IsObject + { + get + { + return this.Context.IsWellKnownType(this, WellKnownType.Object); + } + } + + public bool IsNullable + { + get + { + return this.Context.IsWellKnownType(this, WellKnownType.Nullable); + } + } + + public bool IsArray + { + get + { + return this.GetType() == typeof(ArrayType); + } + } + + public bool IsSzArray + { + get + { + return this.IsArray && ((ArrayType)this).IsSzArray; + } + } + + public bool IsByRef + { + get + { + return this.GetType() == typeof(ByRefType); + } + } + + public bool IsPointer + { + get + { + return this.GetType() == typeof(PointerType); + } + } + + public bool ContainsGenericVariables + { + get + { + return (GetTypeFlags(TypeFlags.ContainsGenericVariables | TypeFlags.ContainsGenericVariablesComputed) & TypeFlags.ContainsGenericVariables) != 0; + } + } + + public virtual MetadataType BaseType + { + get + { + return null; + } + } + + public bool HasBaseType + { + get + { + return BaseType != null; + } + } + + public virtual TypeDesc[] ImplementedInterfaces + { + get + { + return TypeDesc.EmptyTypes; + } + } + + public virtual TypeDesc UnderlyingType // For enums + { + get + { + if (!this.IsEnum) + return this; + + // TODO: Cache the result? + foreach (var field in this.GetFields()) + { + if (!field.IsStatic) + return field.FieldType; + } + + throw new BadImageFormatException(); + } + } + + public virtual string Name + { + get + { + return null; + } + } + + public virtual IEnumerable GetMethods() + { + return MethodDesc.EmptyMethods; + } + + // TODO: Substitutions, generics, modopts, ... + public virtual MethodDesc GetMethod(string name, MethodSignature signature) + { + foreach (var method in GetMethods()) + { + if (method.Name == name) + { + if (signature == null || signature.Equals(method.Signature)) + return method; + } + } + return null; + } + + public virtual IEnumerable GetFields() + { + return FieldDesc.EmptyFields; + } + + // TODO: Substitutions, generics, modopts, ... + public virtual FieldDesc GetField(string name) + { + foreach (var field in GetFields()) + { + if (field.Name == name) + return field; + } + return null; + } + + public virtual TypeDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) + { + return this; + } + + // Strips instantiation. E.g C -> C + public virtual TypeDesc GetTypeDefinition() + { + return this; + } + + public bool IsTypeDefinition + { + get + { + return GetTypeDefinition() == this; + } + } + } +} diff --git a/src/TypeSystem/src/Common/TypeFlags.cs b/src/TypeSystem/src/Common/TypeFlags.cs new file mode 100644 index 00000000000..47c2062a180 --- /dev/null +++ b/src/TypeSystem/src/Common/TypeFlags.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + [Flags] + public enum TypeFlags + { + CategoryMask = 0x3F, + + // Primitive + Unknown = 0x00, + Void = 0x01, + Boolean = 0x02, + Char = 0x03, + SByte = 0x04, + Byte = 0x05, + Int16 = 0x06, + UInt16 = 0x07, + Int32 = 0x08, + UInt32 = 0x09, + Int64 = 0x0A, + UInt64 = 0x0B, + IntPtr = 0x0C, + UIntPtr = 0x0D, + Single = 0x0E, + Double = 0x0F, + + ValueType = 0x10, + Enum = 0x11, // Parent is enum + Nullable = 0x12, // Nullable instantiation + // Unused 0x13 + + Class = 0x14, + Interface = 0x15, + // Unused 0x16 + + Array = 0x17, + ByRef = 0x18, + Pointer = 0x19, + + GenericParameter = 0x1C, + + ContainsGenericVariables = 0x100, + ContainsGenericVariablesComputed = 0x200, + } +} diff --git a/src/TypeSystem/src/Common/TypeHashingAlgorithms.cs b/src/TypeSystem/src/Common/TypeHashingAlgorithms.cs new file mode 100644 index 00000000000..63c0a2cab7c --- /dev/null +++ b/src/TypeSystem/src/Common/TypeHashingAlgorithms.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. + +// --------------------------------------------------------------------------- +// TypeHashingAlgorithms.cs +// +// Generic functions to compute the hashcode value of types +// --------------------------------------------------------------------------- + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Internal.NativeFormat +{ + static public class TypeHashingAlgorithms + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _rotl(int value, int shift) + { + return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); + } + + // + // Returns the hashcode value of the 'src' string + // + public static int ComputeNameHashCode(string src) + { + int hash1 = 0x6DA3B944; + int hash2 = 0; + + for (int i = 0; i < src.Length; i += 2) + { + hash1 = (hash1 + _rotl(hash1, 5)) ^ src[i]; + if ((i + 1) < src.Length) + hash2 = (hash2 + _rotl(hash2, 5)) ^ src[i + 1]; + } + + hash1 += _rotl(hash1, 8); + hash2 += _rotl(hash2, 8); + + return hash1 ^ hash2; + } + + public static unsafe int ComputeASCIINameHashCode(byte* data, int length, out bool isAscii) + { + int hash1 = 0x6DA3B944; + int hash2 = 0; + int asciiMask = 0; + + for (int i = 0; i < length; i += 2) + { + int b1 = data[i]; + asciiMask |= b1; + hash1 = (hash1 + _rotl(hash1, 5)) ^ b1; + if ((i + 1) < length) + { + int b2 = data[i]; + asciiMask |= b2; + hash2 = (hash2 + _rotl(hash2, 5)) ^ b2; + } + } + + hash1 += _rotl(hash1, 8); + hash2 += _rotl(hash2, 8); + + isAscii = (asciiMask & 0x80) == 0; + + return hash1 ^ hash2; + } + + public static int ComputeArrayTypeHashCode(int elementTypeHashcode, int rank) + { + // Arrays are treated as generic types in some parts of our system. The array hashcodes are + // carefully crafted to be the same as the hashcodes of their implementation generic types. + + int hashCode; + if (rank == 1) + { + hashCode = unchecked((int)0xd5313557u); + Debug.Assert(hashCode == ComputeNameHashCode("System.Array`1")); + } + else + { + hashCode = ComputeNameHashCode("System.MDArrayRank" + rank.ToString() + "`1"); + } + + hashCode = (hashCode + _rotl(hashCode, 13)) ^ elementTypeHashcode; + return (hashCode + _rotl(hashCode, 15)); + } + + public static int ComputeArrayTypeHashCode(T elementType, int rank) + { + return ComputeArrayTypeHashCode(elementType.GetHashCode(), rank); + } + + + public static int ComputePointerTypeHashCode(int pointeeTypeHashcode) + { + return (pointeeTypeHashcode + _rotl(pointeeTypeHashcode, 5)) ^ 0x12D0; + } + + public static int ComputePointerTypeHashCode(T pointeeType) + { + return ComputePointerTypeHashCode(pointeeType.GetHashCode()); + } + + + public static int ComputeByrefTypeHashCode(int parameterTypeHashcode) + { + return (parameterTypeHashcode + _rotl(parameterTypeHashcode, 7)) ^ 0x4C85; + } + + public static int ComputeByrefTypeHashCode(T parameterType) + { + return ComputeByrefTypeHashCode(parameterType.GetHashCode()); + } + + + public static int ComputeNestedTypeHashCode(int enclosingTypeHashcode, int nestedTypeNameHash) + { + return (enclosingTypeHashcode + _rotl(enclosingTypeHashcode, 11)) ^ nestedTypeNameHash; + } + + + public static int ComputeGenericInstanceHashCode(int genericDefinitionHashCode, ARG[] genericTypeArguments) + { + int hashcode = genericDefinitionHashCode; + for (int i = 0; i < genericTypeArguments.Length; i++) + { + int argumentHashCode = genericTypeArguments[i].GetHashCode(); + hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode; + } + return (hashcode + _rotl(hashcode, 15)); + } + + public static int ComputeGenericInstanceHashCode(int genericDefinitionHashCode, Internal.TypeSystem.Instantiation genericTypeArguments) + { + int hashcode = genericDefinitionHashCode; + for (int i = 0; i < genericTypeArguments.Length; i++) + { + int argumentHashCode = genericTypeArguments[i].GetHashCode(); + hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode; + } + return (hashcode + _rotl(hashcode, 15)); + } + } +} diff --git a/src/TypeSystem/src/Common/TypeSystem.csproj b/src/TypeSystem/src/Common/TypeSystem.csproj new file mode 100644 index 00000000000..fd7f94c293a --- /dev/null +++ b/src/TypeSystem/src/Common/TypeSystem.csproj @@ -0,0 +1,93 @@ + + + + + 12.0 + Debug + AnyCPU + {DD5B6BAA-D41A-4A6E-9E7D-83060F394B10} + Library + Properties + Internal.TypeSystem + TypeSystem + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile44 + v4.6 + ..\ + true + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/TypeSystem/src/Common/TypeSystemContext.cs b/src/TypeSystem/src/Common/TypeSystemContext.cs new file mode 100644 index 00000000000..d53c3ad8277 --- /dev/null +++ b/src/TypeSystem/src/Common/TypeSystemContext.cs @@ -0,0 +1,486 @@ +// 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.Collections.Immutable; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Internal.TypeSystem +{ + public abstract class TypeSystemContext + { + public TypeSystemContext() + { + Target = new TargetDetails(TargetArchitecture.Unknown); + } + + public TypeSystemContext(TargetDetails target) + { + Target = target; + } + + public TargetDetails Target + { + get; private set; + } + + public abstract MetadataType GetWellKnownType(WellKnownType wellKnownType); + + // TODO: Optional interface instead? Return ModuleDesc instead? + public virtual Object ResolveAssembly(AssemblyName name) + { + return null; + } + + public virtual bool IsWellKnownType(TypeDesc type, WellKnownType wellKnownType) + { + return type == GetWellKnownType(wellKnownType); + } + + // + // Array types + // + + ImmutableDictionary _arrayTypes = ImmutableDictionary.Empty; + + public TypeDesc GetArrayType(TypeDesc elementType) + { + ArrayType existingArrayType; + if (_arrayTypes.TryGetValue(elementType, out existingArrayType)) + return existingArrayType; + + return CreateArrayType(elementType); + } + + TypeDesc CreateArrayType(TypeDesc elementType) + { + ArrayType arrayType = new ArrayType(elementType, -1); + + lock (this) + { + ArrayType existingArrayType; + if (_arrayTypes.TryGetValue(elementType, out existingArrayType)) + return existingArrayType; + _arrayTypes = _arrayTypes.Add(elementType, arrayType); + } + + return arrayType; + } + + // + // MDArray types + // + + struct ArrayTypeKey : IEquatable + { + TypeDesc _elementType; + int _rank; + + public ArrayTypeKey(TypeDesc elementType, int rank) + { + _elementType = elementType; + _rank = rank; + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeArrayTypeHashCode(_elementType, _rank); + } + + public bool Equals(ArrayTypeKey other) + { + if (_elementType != other._elementType) + return false; + + if (_rank != other._rank) + return false; + + return true; + } + } + + ImmutableDictionary _ArrayTypes = ImmutableDictionary.Empty; + + public TypeDesc GetArrayType(TypeDesc elementType, int rank) + { + ArrayType existingArrayType; + if (_ArrayTypes.TryGetValue(new ArrayTypeKey(elementType, rank), out existingArrayType)) + return existingArrayType; + + return CreateArrayType(elementType, rank); + } + + TypeDesc CreateArrayType(TypeDesc elementType, int rank) + { + ArrayType arrayType = new ArrayType(elementType, rank); + + lock (this) + { + ArrayType existingArrayType; + if (_ArrayTypes.TryGetValue(new ArrayTypeKey(elementType, rank), out existingArrayType)) + return existingArrayType; + _ArrayTypes = _ArrayTypes.Add(new ArrayTypeKey(elementType, rank), arrayType); + } + + return arrayType; + } + + // + // ByRef types + // + + ImmutableDictionary _byRefTypes = ImmutableDictionary.Empty; + + public TypeDesc GetByRefType(TypeDesc parameterType) + { + ByRefType existingByRefType; + if (_byRefTypes.TryGetValue(parameterType, out existingByRefType)) + return existingByRefType; + + return CreateByRefType(parameterType); + } + + TypeDesc CreateByRefType(TypeDesc parameterType) + { + ByRefType byRefType = new ByRefType(parameterType); + + lock (this) + { + ByRefType existingByRefType; + if (_byRefTypes.TryGetValue(parameterType, out existingByRefType)) + return existingByRefType; + _byRefTypes = _byRefTypes.Add(parameterType, byRefType); + } + + return byRefType; + } + + // + // Pointer types + // + + ImmutableDictionary _pointerTypes = ImmutableDictionary.Empty; + + public TypeDesc GetPointerType(TypeDesc parameterType) + { + PointerType existingPointerType; + if (_pointerTypes.TryGetValue(parameterType, out existingPointerType)) + return existingPointerType; + + return CreatePointerType(parameterType); + } + + TypeDesc CreatePointerType(TypeDesc parameterType) + { + PointerType pointerType = new PointerType(parameterType); + + lock (this) + { + PointerType existingPointerType; + if (_pointerTypes.TryGetValue(parameterType, out existingPointerType)) + return existingPointerType; + _pointerTypes = _pointerTypes.Add(parameterType, pointerType); + } + + return pointerType; + } + + // + // Instantiated types + // + + struct InstantiatedTypeKey : IEquatable + { + TypeDesc _typeDef; + Instantiation _instantiation; + + public InstantiatedTypeKey(TypeDesc typeDef, Instantiation instantiation) + { + _typeDef = typeDef; + _instantiation = instantiation; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _rotl(int value, int shift) + { + return (int)(((uint)value << shift) | ((uint)value >> (32 - shift))); + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeGenericInstanceHashCode(_typeDef.GetHashCode(), _instantiation); + } + + public bool Equals(InstantiatedTypeKey other) + { + if (_typeDef != other._typeDef) + return false; + + if (_instantiation.Length != other._instantiation.Length) + return false; + + for (int i = 0; i < _instantiation.Length; i++) + { + if (_instantiation[i] != other._instantiation[i]) + return false; + } + + return true; + } + } + + ImmutableDictionary _instantiatedTypes = ImmutableDictionary.Empty; + + public InstantiatedType GetInstantiatedType(MetadataType typeDef, Instantiation instantiation) + { + InstantiatedType existingInstantiatedType; + if (_instantiatedTypes.TryGetValue(new InstantiatedTypeKey(typeDef, instantiation), out existingInstantiatedType)) + return existingInstantiatedType; + + return CreateInstantiatedType(typeDef, instantiation); + } + + InstantiatedType CreateInstantiatedType(MetadataType typeDef, Instantiation instantiation) + { + InstantiatedType instantiatedType = new InstantiatedType(typeDef, instantiation); + + lock (this) + { + InstantiatedType existingInstantiatedType; + if (_instantiatedTypes.TryGetValue(new InstantiatedTypeKey(typeDef, instantiation), out existingInstantiatedType)) + return existingInstantiatedType; + _instantiatedTypes = _instantiatedTypes.Add(new InstantiatedTypeKey(typeDef, instantiation), instantiatedType); + } + + return instantiatedType; + } + + // + // Instantiated methods + // + + struct InstantiatedMethodKey : IEquatable + { + MethodDesc _methodDef; + Instantiation _instantiation; + + public InstantiatedMethodKey(MethodDesc methodDef, Instantiation instantiation) + { + _methodDef = methodDef; + _instantiation = instantiation; + } + + public override int GetHashCode() + { + return Internal.NativeFormat.TypeHashingAlgorithms.ComputeGenericInstanceHashCode(_methodDef.GetHashCode(), _instantiation); + } + + public bool Equals(InstantiatedMethodKey other) + { + if (_methodDef != other._methodDef) + return false; + + if (_instantiation.Length != other._instantiation.Length) + return false; + + for (int i = 0; i < _instantiation.Length; i++) + { + if (_instantiation[i] != other._instantiation[i]) + return false; + } + + return true; + } + } + + ImmutableDictionary _instantiatedMethods = ImmutableDictionary.Empty; + + public InstantiatedMethod GetInstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) + { + Debug.Assert(!(methodDef is InstantiatedMethod)); + + InstantiatedMethod existingInstantiatedMethod; + if (_instantiatedMethods.TryGetValue(new InstantiatedMethodKey(methodDef, instantiation), out existingInstantiatedMethod)) + return existingInstantiatedMethod; + + return CreateInstantiatedMethod(methodDef, instantiation); + } + + InstantiatedMethod CreateInstantiatedMethod(MethodDesc methodDef, Instantiation instantiation) + { + InstantiatedMethod instantiatedMethod = new InstantiatedMethod(methodDef, instantiation); + + lock (this) + { + InstantiatedMethod existingInstantiatedMethod; + if (_instantiatedMethods.TryGetValue(new InstantiatedMethodKey(methodDef, instantiation), out existingInstantiatedMethod)) + return existingInstantiatedMethod; + _instantiatedMethods = _instantiatedMethods.Add(new InstantiatedMethodKey(methodDef, instantiation), instantiatedMethod); + } + + return instantiatedMethod; + } + + // + // Methods for instantiated type + // + + struct MethodForInstantiatedTypeKey : IEquatable + { + MethodDesc _typicalMethodDef; + InstantiatedType _instantiatedType; + + public MethodForInstantiatedTypeKey(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + _typicalMethodDef = typicalMethodDef; + _instantiatedType = instantiatedType; + } + + public override int GetHashCode() + { + return _typicalMethodDef.GetHashCode() ^ _instantiatedType.GetHashCode(); + } + + public bool Equals(MethodForInstantiatedTypeKey other) + { + if (_typicalMethodDef != other._typicalMethodDef) + return false; + + if (_instantiatedType != other._instantiatedType) + return false; + + return true; + } + } + + ImmutableDictionary _methodForInstantiatedTypes = ImmutableDictionary.Empty; + + public MethodDesc GetMethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + Debug.Assert(!(typicalMethodDef is MethodForInstantiatedType)); + Debug.Assert(!(typicalMethodDef is InstantiatedMethod)); + + MethodForInstantiatedType existingMethodForInstantiatedType; + if (_methodForInstantiatedTypes.TryGetValue(new MethodForInstantiatedTypeKey(typicalMethodDef, instantiatedType), out existingMethodForInstantiatedType)) + return existingMethodForInstantiatedType; + + return CreateMethodForInstantiatedType(typicalMethodDef, instantiatedType); + } + + MethodDesc CreateMethodForInstantiatedType(MethodDesc typicalMethodDef, InstantiatedType instantiatedType) + { + MethodForInstantiatedType methodForInstantiatedType = new MethodForInstantiatedType(typicalMethodDef, instantiatedType); + + lock (this) + { + MethodForInstantiatedType existingMethodForInstantiatedType; + if (_methodForInstantiatedTypes.TryGetValue(new MethodForInstantiatedTypeKey(typicalMethodDef, instantiatedType), out existingMethodForInstantiatedType)) + return existingMethodForInstantiatedType; + _methodForInstantiatedTypes = _methodForInstantiatedTypes.Add(new MethodForInstantiatedTypeKey(typicalMethodDef, instantiatedType), methodForInstantiatedType); + } + + return methodForInstantiatedType; + } + + // + // Fields for instantiated type + // + + struct FieldForInstantiatedTypeKey : IEquatable + { + FieldDesc _fieldDef; + InstantiatedType _instantiatedType; + + public FieldForInstantiatedTypeKey(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + _fieldDef = fieldDef; + _instantiatedType = instantiatedType; + } + + public override int GetHashCode() + { + return _fieldDef.GetHashCode() ^ _instantiatedType.GetHashCode(); + } + + public bool Equals(FieldForInstantiatedTypeKey other) + { + if (_fieldDef != other._fieldDef) + return false; + + if (_instantiatedType != other._instantiatedType) + return false; + + return true; + } + } + + ImmutableDictionary _fieldForInstantiatedTypes = ImmutableDictionary.Empty; + + public FieldDesc GetFieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + FieldForInstantiatedType existingFieldForInstantiatedType; + if (_fieldForInstantiatedTypes.TryGetValue(new FieldForInstantiatedTypeKey(fieldDef, instantiatedType), out existingFieldForInstantiatedType)) + return existingFieldForInstantiatedType; + + return CreateFieldForInstantiatedType(fieldDef, instantiatedType); + } + + FieldDesc CreateFieldForInstantiatedType(FieldDesc fieldDef, InstantiatedType instantiatedType) + { + FieldForInstantiatedType fieldForInstantiatedType = new FieldForInstantiatedType(fieldDef, instantiatedType); + + lock (this) + { + FieldForInstantiatedType existingFieldForInstantiatedType; + if (_fieldForInstantiatedTypes.TryGetValue(new FieldForInstantiatedTypeKey(fieldDef, instantiatedType), out existingFieldForInstantiatedType)) + return existingFieldForInstantiatedType; + _fieldForInstantiatedTypes = _fieldForInstantiatedTypes.Add(new FieldForInstantiatedTypeKey(fieldDef, instantiatedType), fieldForInstantiatedType); + } + + return fieldForInstantiatedType; + } + + // + // Signature variables + // + ImmutableDictionary _signatureVariables = ImmutableDictionary.Empty; + + public TypeDesc GetSignatureVariable(int index, bool method) + { + if (index < 0) + throw new BadImageFormatException(); + + uint combinedIndex = method ? ((uint)index | 0x80000000) : (uint)index; + + TypeDesc existingSignatureVariable; + if (_signatureVariables.TryGetValue(combinedIndex, out existingSignatureVariable)) + return existingSignatureVariable; + + return CreateSignatureVariable(index, method); + } + + TypeDesc CreateSignatureVariable(int index, bool method) + { + TypeDesc signatureVariable; + + if (method) + signatureVariable = new SignatureMethodVariable(this, index); + else + signatureVariable = new SignatureTypeVariable(this, index); + + uint combinedIndex = method ? ((uint)index | 0x80000000) : (uint)index; + + lock (this) + { + TypeDesc existingSignatureVariable; + if (_signatureVariables.TryGetValue(combinedIndex, out existingSignatureVariable)) + return existingSignatureVariable; + _signatureVariables = _signatureVariables.Add(combinedIndex, signatureVariable); + } + + return signatureVariable; + } + } +} diff --git a/src/TypeSystem/src/Common/TypeSystemHelpers.cs b/src/TypeSystem/src/Common/TypeSystemHelpers.cs new file mode 100644 index 00000000000..9d9770fabc4 --- /dev/null +++ b/src/TypeSystem/src/Common/TypeSystemHelpers.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Internal.TypeSystem +{ + static public class TypeSystemHelpers + { + static public InstantiatedType MakeInstantiatedType(this MetadataType typeDef, Instantiation instantiation) + { + return typeDef.Context.GetInstantiatedType(typeDef, instantiation); + } + + static public InstantiatedMethod MakeInstantiatedMethod(this MethodDesc methodDef, Instantiation instantiation) + { + return methodDef.Context.GetInstantiatedMethod(methodDef, instantiation); + } + + static public TypeDesc MakeByRefType(this TypeDesc type) + { + return type.Context.GetByRefType(type); + } + } +} diff --git a/src/TypeSystem/src/Common/WellKnownType.cs b/src/TypeSystem/src/Common/WellKnownType.cs new file mode 100644 index 00000000000..c106705dff0 --- /dev/null +++ b/src/TypeSystem/src/Common/WellKnownType.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Internal.TypeSystem +{ + public enum WellKnownType + { + Unknown, + + // Primitive types are first - keep in sync with type flags + Void, + Boolean, + Char, + SByte, + Byte, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + IntPtr, + UIntPtr, + Single, + Double, + + ValueType, + Enum, + Nullable, + + Object, + String, + Array, + MulticastDelegate, + + RuntimeTypeHandle, + RuntimeMethodHandle, + RuntimeFieldHandle, + + Exception, + } +} diff --git a/src/TypeSystem/src/Common/packages.config b/src/TypeSystem/src/Common/packages.config new file mode 100644 index 00000000000..b0f83707d39 --- /dev/null +++ b/src/TypeSystem/src/Common/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/TypeSystem/src/Ecma/EcmaField.cs b/src/TypeSystem/src/Ecma/EcmaField.cs new file mode 100644 index 00000000000..8e4eab0dbc4 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaField.cs @@ -0,0 +1,177 @@ +// 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; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed class EcmaField : FieldDesc + { + [Flags] + enum FieldFlags + { + BasicMetadataCache = 0x01, + Static = 0x02, + InitOnly = 0x04, + }; + + EcmaType _type; + FieldDefinitionHandle _handle; + + TypeDesc _fieldType; + FieldFlags _fieldFlags; + + internal EcmaField(EcmaType type, FieldDefinitionHandle handle) + { + _type = type; + _handle = handle; + } + + public override TypeSystemContext Context + { + get + { + return _type.Module.Context; + } + } + + public override MetadataType OwningType + { + get + { + return _type; + } + } + + public EcmaModule Module + { + get + { + return _type.Module; + } + } + + public MetadataReader MetadataReader + { + get + { + return _type.MetadataReader; + } + } + + public FieldDefinitionHandle Handle + { + get + { + return _handle; + } + } + + public FieldDefinition FieldDefinition + { + get + { + return this.MetadataReader.GetFieldDefinition(_handle); + } + } + + void ComputeFieldType() + { + var metadataReader = this.Module.MetadataReader; + BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetFieldDefinition(_handle).Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(this.Module, signatureReader); + _fieldType = parser.ParseFieldSignature(); + } + + public override TypeDesc FieldType + { + get + { + if (_fieldType == null) + ComputeFieldType(); + return _fieldType; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private FieldFlags InitializeFieldFlags(FieldFlags mask) + { + FieldFlags flags = 0; + + if ((mask & FieldFlags.BasicMetadataCache) != 0) + { + var fieldDefinition = this.MetadataReader.GetFieldDefinition(_handle); + + var fieldAttributes = fieldDefinition.Attributes; + if ((fieldAttributes & FieldAttributes.Static) != 0) + flags |= FieldFlags.Static; + + if ((fieldAttributes & FieldAttributes.InitOnly) != 0) + flags |= FieldFlags.InitOnly; + + flags |= FieldFlags.BasicMetadataCache; + } + + Debug.Assert((flags & mask) != 0); + _fieldFlags |= flags; + + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private FieldFlags GetFieldFlags(FieldFlags mask) + { + FieldFlags flags = _fieldFlags & mask; + if (flags != 0) + return flags; + return InitializeFieldFlags(mask); + } + + public override bool IsStatic + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.Static) & FieldFlags.Static) != 0; + } + } + + public override bool IsInitOnly + { + get + { + return (GetFieldFlags(FieldFlags.BasicMetadataCache | FieldFlags.InitOnly) & FieldFlags.InitOnly) != 0; + } + } + + public FieldAttributes Attributes + { + get + { + var fieldDefinition = this.MetadataReader.GetFieldDefinition(_handle); + return fieldDefinition.Attributes; + } + } + + public override string Name + { + get + { + var metadataReader = this.MetadataReader; + var fieldDefinition = metadataReader.GetFieldDefinition(_handle); + return metadataReader.GetString(fieldDefinition.Name); + } + } + + public override string ToString() + { + return _type.ToString() + "." + this.Name; + } + } +} diff --git a/src/TypeSystem/src/Ecma/EcmaGenericParameter.cs b/src/TypeSystem/src/Ecma/EcmaGenericParameter.cs new file mode 100644 index 00000000000..458dfaceb25 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaGenericParameter.cs @@ -0,0 +1,69 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed class EcmaGenericParameter : TypeDesc + { + EcmaModule _module; + GenericParameterHandle _handle; + + internal EcmaGenericParameter(EcmaModule module, GenericParameterHandle handle) + { + _module = module; + _handle = handle; + } + + // TODO: Use stable hashcode based on the type name? + // public override int GetHashCode() + // { + // } + + public override TypeSystemContext Context + { + get + { + return _module.Context; + } + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + flags |= TypeFlags.ContainsGenericVariablesComputed | TypeFlags.ContainsGenericVariables; + + flags |= TypeFlags.GenericParameter; + + return flags; + } + +#if CCIGLUE + public TypeDesc DefiningType + { + get + { + var genericParameter = _module.MetadataReader.GetGenericParameter(_handle); + return _module.GetObject(genericParameter.Parent) as TypeDesc; + } + } + + public MethodDesc DefiningMethod + { + get + { + var genericParameter = _module.MetadataReader.GetGenericParameter(_handle); + return _module.GetObject(genericParameter.Parent) as MethodDesc; + } + } +#endif + } +} diff --git a/src/TypeSystem/src/Ecma/EcmaMethod.cs b/src/TypeSystem/src/Ecma/EcmaMethod.cs new file mode 100644 index 00000000000..4acc02c7848 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaMethod.cs @@ -0,0 +1,244 @@ +// 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; +using System.Runtime.CompilerServices; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed class EcmaMethod : MethodDesc + { + [Flags] + enum MethodFlags + { + BasicMetadataCache = 0x01, + Virtual = 0x02, + NewSlot = 0x04, + }; + + EcmaType _type; + MethodDefinitionHandle _handle; + + MethodDefinition _methodDefinition; + + // Cached values + MethodSignature _signature; + MethodFlags _methodFlags; + + internal EcmaMethod(EcmaType type, MethodDefinitionHandle handle) + { + _type = type; + _handle = handle; + + _methodDefinition = type.MetadataReader.GetMethodDefinition(handle); + } + + public override TypeSystemContext Context + { + get + { + return _type.Module.Context; + } + } + + public override TypeDesc OwningType + { + get + { + return _type; + } + } + + void ComputeSignature() + { + BlobReader signatureReader = this.MetadataReader.GetBlobReader(_methodDefinition.Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(this.Module, signatureReader); + _signature = parser.ParseMethodSignature(); + } + + public override MethodSignature Signature + { + get + { + if (_signature == null) + ComputeSignature(); + return _signature; + } + } + + public EcmaModule Module + { + get + { + return _type.Module; + } + } + + public MetadataReader MetadataReader + { + get + { + return _type.MetadataReader; + } + } + + public MethodDefinitionHandle Handle + { + get + { + return _handle; + } + } + + public MethodDefinition MethodDefinition + { + get + { + return _methodDefinition; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private MethodFlags InitializeMethodFlags(MethodFlags mask) + { + MethodFlags flags = 0; + + if ((mask & MethodFlags.BasicMetadataCache) != 0) + { + var methodAttributes = _methodDefinition.Attributes; + if ((methodAttributes & MethodAttributes.Virtual) != 0) + flags |= MethodFlags.Virtual; + + if ((methodAttributes & MethodAttributes.NewSlot) != 0) + flags |= MethodFlags.NewSlot; + + flags |= MethodFlags.BasicMetadataCache; + } + + Debug.Assert((flags & mask) != 0); + _methodFlags |= flags; + + return flags & mask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private MethodFlags GetMethodFlags(MethodFlags mask) + { + MethodFlags flags = _methodFlags & mask; + if (flags != 0) + return flags; + return InitializeMethodFlags(mask); + } + + public override bool IsVirtual + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Virtual) & MethodFlags.Virtual) != 0; + } + } + + public override bool IsNewSlot + { + get + { + return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NewSlot) & MethodFlags.NewSlot) != 0; + } + } + + public MethodAttributes Attributes + { + get + { + return _methodDefinition.Attributes; + } + } + + public MethodImplAttributes ImplAttributes + { + get + { + return _methodDefinition.ImplAttributes; + } + } + + public override string Name + { + get + { + return this.MetadataReader.GetString(_methodDefinition.Name); + } + } + + TypeDesc[] _genericParameters; + + public override Instantiation Instantiation + { + get + { + if (_genericParameters == null) + { + var genericParameterHandles = _methodDefinition.GetGenericParameters(); + int count = genericParameterHandles.Count; + if (count > 0) + { + TypeDesc[] genericParameters = new TypeDesc[count]; + int i = 0; + foreach (var genericParameterHandle in genericParameterHandles) + { + genericParameters[i++] = new EcmaGenericParameter(this.Module, genericParameterHandle); + } + Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); + } + else + { + _genericParameters = TypeDesc.EmptyTypes; + } + } + + return new Instantiation(_genericParameters); + } + } + + public bool HasCustomAttribute(string customAttributeName) + { + return this.Module.HasCustomAttribute(_methodDefinition.GetCustomAttributes(), customAttributeName); + } + + public override string ToString() + { + return "[" + Module.GetName().Name + "]" + _type.ToString() + "." + this.Name; + } + + public bool IsPInvoke() + { + return (((int)Attributes & (int)MethodAttributes.PinvokeImpl) != 0); + } + + public string GetPInvokeImportName() + { + if (((int)Attributes & (int)MethodAttributes.PinvokeImpl) == 0) + return null; + + return this.MetadataReader.GetString(_methodDefinition.GetImport().Name); + } + } + + public static class EcmaMethodExtensions + { + public static bool IsPublic(this EcmaMethod method) { return (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; } + public static bool IsPrivate(this EcmaMethod method) { return (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private; } + public static bool IsStatic(this EcmaMethod method) { return (method.Attributes & MethodAttributes.Static) != 0; } + public static bool IsFinal(this EcmaMethod method) { return (method.Attributes & MethodAttributes.Final) != 0; } + public static bool IsHideBySig(this EcmaMethod method) { return (method.Attributes & MethodAttributes.HideBySig) != 0; } + public static bool IsAbstract(this EcmaMethod method) { return (method.Attributes & MethodAttributes.Abstract) != 0; } + public static bool IsSpecialName(this EcmaMethod method) { return (method.Attributes & MethodAttributes.SpecialName) != 0; } + } +} diff --git a/src/TypeSystem/src/Ecma/EcmaModule.cs b/src/TypeSystem/src/Ecma/EcmaModule.cs new file mode 100644 index 00000000000..bd5b3a2a090 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaModule.cs @@ -0,0 +1,435 @@ +// 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.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed class EcmaModule + { + TypeSystemContext _context; + + PEReader _peReader; + MetadataReader _metadataReader; + + AssemblyDefinition _assemblyDefinition; + + ImmutableDictionary _resolvedTokens = ImmutableDictionary.Create(); + + public EcmaModule(TypeSystemContext context, PEReader peReader) + { + _context = context; + + _peReader = peReader; + + var stringDecoderProvider = context as IMetadataStringDecoderProvider; + + _metadataReader = peReader.GetMetadataReader(MetadataReaderOptions.None /* MetadataReaderOptions.ApplyWindowsRuntimeProjections */, + (stringDecoderProvider != null) ? stringDecoderProvider.GetMetadataStringDecoder() : null); + + _assemblyDefinition = _metadataReader.GetAssemblyDefinition(); + } + + public EcmaModule(TypeSystemContext context, MetadataReader metadataReader) + { + _context = context; + + _metadataReader = metadataReader; + } + + public TypeSystemContext Context + { + get + { + return _context; + } + } + + public PEReader PEReader + { + get + { + return _peReader; + } + } + + public MetadataReader MetadataReader + { + get + { + return _metadataReader; + } + } + + public AssemblyDefinition AssemblyDefinition + { + get + { + return _assemblyDefinition; + } + } + + public MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true) + { + var stringComparer = _metadataReader.StringComparer; + + // TODO: More efficient implementation? + foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) + { + var typeDefinition = _metadataReader.GetTypeDefinition(typeDefinitionHandle); + if (stringComparer.Equals(typeDefinition.Name, name) && + stringComparer.Equals(typeDefinition.Namespace, nameSpace)) + { + return (MetadataType)GetType((EntityHandle)typeDefinitionHandle); + } + } + + foreach (var exportedTypeHandle in _metadataReader.ExportedTypes) + { + var exportedType = _metadataReader.GetExportedType(exportedTypeHandle); + if (stringComparer.Equals(exportedType.Name, name) && + stringComparer.Equals(exportedType.Namespace, nameSpace)) + { + if (exportedType.IsForwarder) + { + Object implementation = GetObject(exportedType.Implementation); + + if (implementation is EcmaModule) + { + return ((EcmaModule)(implementation)).GetType(nameSpace, name); + } + + // TODO + throw new NotImplementedException(); + } + // TODO: + throw new NotImplementedException(); + } + } + + if (throwIfNotFound) + throw CreateTypeLoadException(nameSpace + "." + name); + + return null; + } + + public Exception CreateTypeLoadException(string fullTypeName) + { + return new TypeLoadException(String.Format("Could not load type '{0}' from assembly '{1}'.", fullTypeName, this.ToString())); + } + + public TypeDesc GetType(EntityHandle handle) + { + TypeDesc type = GetObject(handle) as TypeDesc; + if (type == null) + throw new BadImageFormatException("Type expected"); + return type; + } + + public MethodDesc GetMethod(EntityHandle handle) + { + MethodDesc method = GetObject(handle) as MethodDesc; + if (method == null) + throw new BadImageFormatException("Method expected"); + return method; + } + + public FieldDesc GetField(EntityHandle handle) + { + FieldDesc field = GetObject(handle) as FieldDesc; + if (field == null) + throw new BadImageFormatException("Field expected"); + return field; + } + + public Object GetObject(EntityHandle handle) + { + Object existingItem; + if (_resolvedTokens.TryGetValue(handle, out existingItem)) + return existingItem; + + return CreateObject(handle); + } + + private Object CreateObject(EntityHandle handle) + { + Object item; + switch (handle.Kind) + { + case HandleKind.TypeDefinition: + item = new EcmaType(this, (TypeDefinitionHandle)handle); + break; + + case HandleKind.MethodDefinition: + { + MethodDefinitionHandle methodDefinitionHandle = (MethodDefinitionHandle)handle; + TypeDefinitionHandle typeDefinitionHandle = _metadataReader.GetMethodDefinition(methodDefinitionHandle).GetDeclaringType(); + EcmaType type = (EcmaType)GetObject(typeDefinitionHandle); + item = new EcmaMethod(type, methodDefinitionHandle); + } + break; + + case HandleKind.FieldDefinition: + { + FieldDefinitionHandle fieldDefinitionHandle = (FieldDefinitionHandle)handle; + TypeDefinitionHandle typeDefinitionHandle = _metadataReader.GetFieldDefinition(fieldDefinitionHandle).GetDeclaringType(); + EcmaType type = (EcmaType)GetObject(typeDefinitionHandle); + item = new EcmaField(type, fieldDefinitionHandle); + } + break; + + case HandleKind.TypeReference: + item = ResolveTypeReference((TypeReferenceHandle)handle); + break; + + case HandleKind.MemberReference: + item = ResolveMemberReference((MemberReferenceHandle)handle); + break; + + case HandleKind.AssemblyReference: + item = ResolveAssemblyReference((AssemblyReferenceHandle)handle); + break; + + case HandleKind.TypeSpecification: + item = ResolveTypeSpecification((TypeSpecificationHandle)handle); + break; + + case HandleKind.MethodSpecification: + item = ResolveMethodSpecification((MethodSpecificationHandle)handle); + break; + + case HandleKind.ExportedType: + item = ResolveExportedType((ExportedTypeHandle)handle); + break; + + // TODO: Resolve other tokens + + default: + throw new BadImageFormatException("Unknown metadata token type"); + } + + lock (this) + { + Object existingItem; + if (_resolvedTokens.TryGetValue(handle, out existingItem)) + return existingItem; + _resolvedTokens = _resolvedTokens.Add(handle, item); + } + + return item; + } + + Object ResolveMethodSpecification(MethodSpecificationHandle handle) + { + MethodSpecification methodSpecification = _metadataReader.GetMethodSpecification(handle); + + MethodDesc methodDef = GetMethod(methodSpecification.Method); + + BlobReader signatureReader = _metadataReader.GetBlobReader(methodSpecification.Signature); + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + TypeDesc[] instantiation = parser.ParseMethodSpecSignature(); + return _context.GetInstantiatedMethod(methodDef, new Instantiation(instantiation)); + } + + Object ResolveTypeSpecification(TypeSpecificationHandle handle) + { + TypeSpecification typeSpecification = _metadataReader.GetTypeSpecification(handle); + + BlobReader signatureReader = _metadataReader.GetBlobReader(typeSpecification.Signature); + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + return parser.ParseType(); + } + + Object ResolveMemberReference(MemberReferenceHandle handle) + { + MemberReference memberReference = _metadataReader.GetMemberReference(handle); + + Object parent = GetObject(memberReference.Parent); + + if (parent is TypeDesc) + { + BlobReader signatureReader = _metadataReader.GetBlobReader(memberReference.Signature); + + EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader); + + string name = _metadataReader.GetString(memberReference.Name); + + if (parser.IsFieldSignature) + { + FieldDesc field = ((TypeDesc)parent).GetField(name); + if (field != null) + return field; + + // TODO: Better error message + throw new MissingMemberException("Field not found " + parent.ToString() + "." + name); + } + else + { + MethodDesc method = ((TypeDesc)parent).GetMethod(name, parser.ParseMethodSignature()); + if (method != null) + return method; + + // TODO: Lookup in parent + + // TODO: Better error message + throw new MissingMemberException("Method not found " + parent.ToString() + "." + name); + } + } + + // TODO: Not implemented + throw new NotImplementedException(); + } + + Object ResolveTypeReference(TypeReferenceHandle handle) + { + TypeReference typeReference = _metadataReader.GetTypeReference(handle); + + Object resolutionScope = GetObject(typeReference.ResolutionScope); + + if (resolutionScope is EcmaModule) + { + return ((EcmaModule)(resolutionScope)).GetType(_metadataReader.GetString(typeReference.Namespace), _metadataReader.GetString(typeReference.Name)); + } + else + if (resolutionScope is EcmaType) + { + return ((EcmaType)(resolutionScope)).GetNestedType(_metadataReader.GetString(typeReference.Name)); + } + + // TODO + throw new NotImplementedException(); + } + + Object ResolveAssemblyReference(AssemblyReferenceHandle handle) + { + AssemblyReference assemblyReference = _metadataReader.GetAssemblyReference(handle); + + AssemblyName an = new AssemblyName(); + an.Name = _metadataReader.GetString(assemblyReference.Name); + an.Version = assemblyReference.Version; + + var publicKeyOrToken = _metadataReader.GetBlobBytes(assemblyReference.PublicKeyOrToken); + if ((an.Flags & AssemblyNameFlags.PublicKey) != 0) + { + an.SetPublicKey(publicKeyOrToken); + } + else + { + an.SetPublicKeyToken(publicKeyOrToken); + } + + // TODO: ContentType, Culture - depends on newer version of the System.Reflection contract + + return _context.ResolveAssembly(an); + } + + Object ResolveExportedType(ExportedTypeHandle handle) + { + ExportedType exportedType = _metadataReader.GetExportedType(handle); + + var implementation = GetObject(exportedType.Implementation); + if (implementation is EcmaModule) + { + var module = (EcmaModule)implementation; + string nameSpace = _metadataReader.GetString(exportedType.Namespace); + string name = _metadataReader.GetString(exportedType.Name); + return module.GetType(nameSpace, name); + } + else + if (implementation is TypeDesc) + { + var type = (EcmaType)implementation; + string name = _metadataReader.GetString(exportedType.Name); + var nestedType = type.GetNestedType(name); + // TODO: Better error message + if (nestedType == null) + throw new TypeLoadException("Nested type not found " + type.ToString() + "." + name); + return nestedType; + } + else + { + throw new BadImageFormatException("Unknown metadata token type for exported type"); + } + } + + public IEnumerable GetAllTypes() + { + foreach (var typeDefinitionHandle in _metadataReader.TypeDefinitions) + { + yield return GetType(typeDefinitionHandle); + } + } + + public TypeDesc GetGlobalModuleType() + { + int typeDefinitionsCount = _metadataReader.TypeDefinitions.Count; + if (typeDefinitionsCount == 0) + return null; + + return GetType(MetadataTokens.EntityHandle(0x02000001 /* COR_GLOBAL_PARENT_TOKEN */)); + } + + AssemblyName _assemblyName; + + // Returns cached copy of the name. Caller has to create a clone before mutating the name. + public AssemblyName GetName() + { + if (_assemblyName == null) + { + AssemblyName an = new AssemblyName(); + an.Name = _metadataReader.GetString(_assemblyDefinition.Name); + an.Version = _assemblyDefinition.Version; + an.SetPublicKey(_metadataReader.GetBlobBytes(_assemblyDefinition.PublicKey)); + + // TODO: ContentType, Culture - depends on newer version of the System.Reflection contract + + _assemblyName = an; + } + + return _assemblyName; + } + + public string GetUserString(UserStringHandle userStringHandle) + { + // String literals are not cached + return _metadataReader.GetUserString(userStringHandle); + } + + internal bool HasCustomAttribute(CustomAttributeHandleCollection customAttributes, string customAttributeName) + { + foreach (var attributeHandle in customAttributes) + { + var customAttribute = _metadataReader.GetCustomAttribute(attributeHandle); + var constructorHandle = customAttribute.Constructor; + + var constructor = GetMethod(constructorHandle); + var type = constructor.OwningType; + + if (type.Name == customAttributeName) + return true; + } + + return false; + } + + public bool HasCustomAttribute(string customAttributeName) + { + return HasCustomAttribute(_assemblyDefinition.GetCustomAttributes(), customAttributeName); + } + + public override string ToString() + { + return GetName().FullName; + } + } +} diff --git a/src/TypeSystem/src/Ecma/EcmaSignatureParser.cs b/src/TypeSystem/src/Ecma/EcmaSignatureParser.cs new file mode 100644 index 00000000000..f55b506e843 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaSignatureParser.cs @@ -0,0 +1,233 @@ +// 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.Metadata; +using System.Runtime.InteropServices; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public struct EcmaSignatureParser + { + EcmaModule _module; + BlobReader _reader; + + // TODO + // bool _hasModifiers; + + public EcmaSignatureParser(EcmaModule module, BlobReader reader) + { + _module = module; + _reader = reader; + + // _hasModifiers = false; + } + + private TypeDesc GetWellKnownType(WellKnownType wellKnownType) + { + return _module.Context.GetWellKnownType(wellKnownType); + } + + private TypeDesc ParseType(SignatureTypeCode typeCode) + { + // Switch on the type. + switch (typeCode) + { + case SignatureTypeCode.Void: + return GetWellKnownType(WellKnownType.Void); + case SignatureTypeCode.Boolean: + return GetWellKnownType(WellKnownType.Boolean); + case SignatureTypeCode.SByte: + return GetWellKnownType(WellKnownType.SByte); + case SignatureTypeCode.Byte: + return GetWellKnownType(WellKnownType.Byte); + case SignatureTypeCode.Int16: + return GetWellKnownType(WellKnownType.Int16); + case SignatureTypeCode.UInt16: + return GetWellKnownType(WellKnownType.UInt16); + case SignatureTypeCode.Int32: + return GetWellKnownType(WellKnownType.Int32); + case SignatureTypeCode.UInt32: + return GetWellKnownType(WellKnownType.UInt32); + case SignatureTypeCode.Int64: + return GetWellKnownType(WellKnownType.Int64); + case SignatureTypeCode.UInt64: + return GetWellKnownType(WellKnownType.UInt64); + case SignatureTypeCode.Single: + return GetWellKnownType(WellKnownType.Single); + case SignatureTypeCode.Double: + return GetWellKnownType(WellKnownType.Double); + case SignatureTypeCode.Char: + return GetWellKnownType(WellKnownType.Char); + case SignatureTypeCode.String: + return GetWellKnownType(WellKnownType.String); + case SignatureTypeCode.IntPtr: + return GetWellKnownType(WellKnownType.IntPtr); + case SignatureTypeCode.UIntPtr: + return GetWellKnownType(WellKnownType.UIntPtr); + case SignatureTypeCode.Object: + return GetWellKnownType(WellKnownType.Object); + case SignatureTypeCode.TypeHandle: + return _module.GetType(_reader.ReadTypeHandle()); + case SignatureTypeCode.SZArray: + return _module.Context.GetArrayType(ParseType()); + case SignatureTypeCode.Array: + { + var elementType = ParseType(); + var rank = _reader.ReadCompressedInteger(); + + // TODO: Bounds for multi-dimmensional arrays + var boundsCount = _reader.ReadCompressedInteger(); + for (int i = 0; i < boundsCount; i++) + _reader.ReadCompressedInteger(); + var lowerBoundsCount = _reader.ReadCompressedInteger(); + for (int j = 0; j < lowerBoundsCount; j++) + _reader.ReadCompressedInteger(); + + return _module.Context.GetArrayType(elementType, rank); + } + case SignatureTypeCode.ByReference: + return ParseType().MakeByRefType(); + case SignatureTypeCode.Pointer: + return _module.Context.GetPointerType(ParseType()); + case SignatureTypeCode.Pinned: // TODO: Pinned types in local signatures! + return ParseType(); + case SignatureTypeCode.GenericTypeParameter: + return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), false); + case SignatureTypeCode.GenericMethodParameter: + return _module.Context.GetSignatureVariable(_reader.ReadCompressedInteger(), true); + case SignatureTypeCode.GenericTypeInstance: + { + TypeDesc typeDef = ParseType(); + MetadataType metadataTypeDef = typeDef as MetadataType; + if (metadataTypeDef == null) + throw new BadImageFormatException(); + + TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()]; + for (int i = 0; i < instance.Length; i++) + instance[i] = ParseType(); + return _module.Context.GetInstantiatedType(metadataTypeDef, new Instantiation(instance)); + } + case SignatureTypeCode.TypedReference: + throw new PlatformNotSupportedException("TypedReference not supported in .NET Core"); + default: + throw new BadImageFormatException(); + } + } + + private SignatureTypeCode ParseTypeCode() + { + for (;;) + { + SignatureTypeCode typeCode = _reader.ReadSignatureTypeCode(); + + if (typeCode != SignatureTypeCode.RequiredModifier && typeCode != SignatureTypeCode.OptionalModifier) + return typeCode; + + _reader.ReadTypeHandle(); + + // _hasModifiers = true; + } + } + + public TypeDesc ParseType() + { + return ParseType(ParseTypeCode()); + } + + public bool IsFieldSignature + { + get + { + BlobReader peek = _reader; + return (peek.ReadByte() & 0xF) == 6; // IMAGE_CEE_CS_CALLCONV_FIELD - add it to SignatureCallingConvention? + } + } + + public MethodSignature ParseMethodSignature() + { + MethodSignatureFlags flags = 0; + + byte callingConvention = _reader.ReadByte(); + if ((callingConvention & (byte)SignatureAttributes.Instance) == 0) + flags |= MethodSignatureFlags.Static; + + int arity = ((callingConvention & (byte)SignatureAttributes.Generic) != 0) ? _reader.ReadCompressedInteger() : 0; + + int count = _reader.ReadCompressedInteger(); + + TypeDesc returnType = ParseType(); + TypeDesc[] parameters; + + if (count > 0) + { + // Get all of the parameters. + parameters = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + parameters[i] = ParseType(); + } + } + else + { + parameters = TypeDesc.EmptyTypes; + } + + return new MethodSignature(flags, arity, returnType, parameters); + } + + public TypeDesc ParseFieldSignature() + { + if ((_reader.ReadByte() & 0xF) != 6) // IMAGE_CEE_CS_CALLCONV_FIELD - add it to SignatureCallingConvention? + throw new BadImageFormatException(); + + return ParseType(); + } + + public TypeDesc[] ParseLocalsSignature() + { + if ((_reader.ReadByte() & 0xF) != 7) // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG - add it to SignatureCallingConvention? + throw new BadImageFormatException(); + + int count = _reader.ReadCompressedInteger(); + + TypeDesc[] locals; + + if (count > 0) + { + locals = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + SignatureTypeCode typeCode = ParseTypeCode(); + // TODO: Handle SignatureTypeCode.Pinned + locals[i] = ParseType(typeCode); + } + } + else + { + locals = TypeDesc.EmptyTypes; + } + return locals; + } + + public TypeDesc[] ParseMethodSpecSignature() + { + if ((_reader.ReadByte() & 0xF) != 0xa) // IMAGE_CEE_CS_CALLCONV_GENERICINST - add it to SignatureCallingConvention? + throw new BadImageFormatException(); + + int count = _reader.ReadCompressedInteger(); + + if (count <= 0) + throw new BadImageFormatException(); + + TypeDesc[] arguments = new TypeDesc[count]; + for (int i = 0; i < count; i++) + { + arguments[i] = ParseType(); + } + return arguments; + } + } +} diff --git a/src/TypeSystem/src/Ecma/EcmaType.cs b/src/TypeSystem/src/Ecma/EcmaType.cs new file mode 100644 index 00000000000..dc8a7988bd8 --- /dev/null +++ b/src/TypeSystem/src/Ecma/EcmaType.cs @@ -0,0 +1,403 @@ +// 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.Collections.Generic; +using System.Reflection; +using System.Reflection.Metadata; +using System.Threading; +using Debug = System.Diagnostics.Debug; + +using Internal.TypeSystem; + +namespace Internal.TypeSystem.Ecma +{ + public sealed class EcmaType : MetadataType + { + EcmaModule _module; + TypeDefinitionHandle _handle; + + TypeDefinition _typeDefinition; + + internal EcmaType(EcmaModule module, TypeDefinitionHandle handle) + { + _module = module; + _handle = handle; + + _typeDefinition = module.MetadataReader.GetTypeDefinition(handle); + + _baseType = this; // Not yet initialized flag + } + + // TODO: Use stable hashcode based on the type name? + // public override int GetHashCode() + // { + // } + + public override TypeSystemContext Context + { + get + { + return _module.Context; + } + } + + TypeDesc[] _genericParameters; + + public override Instantiation Instantiation + { + get + { + if (_genericParameters == null) + { + var genericParameterHandles = _typeDefinition.GetGenericParameters(); + int count = genericParameterHandles.Count; + if (count > 0) + { + TypeDesc[] genericParameters = new TypeDesc[count]; + int i = 0; + foreach (var genericParameterHandle in genericParameterHandles) + { + genericParameters[i++] = new EcmaGenericParameter(this.Module, genericParameterHandle); + } + Interlocked.CompareExchange(ref _genericParameters, genericParameters, null); + } + else + { + _genericParameters = TypeDesc.EmptyTypes; + } + + } + + return new Instantiation(_genericParameters); + } + } + + public EcmaModule Module + { + get + { + return _module; + } + } + + public MetadataReader MetadataReader + { + get + { + return _module.MetadataReader; + } + } + + public TypeDefinitionHandle Handle + { + get + { + return _handle; + } + } + + + public TypeDefinition TypeDefinition + { + get + { + return _typeDefinition; + } + } + + MetadataType _baseType /* = this */; + + MetadataType InitializeBaseType() + { + var baseTypeHandle = _typeDefinition.BaseType; + if (baseTypeHandle.IsNil) + { + _baseType = null; + return null; + } + + var type = _module.GetType(baseTypeHandle) as MetadataType; + if (type == null) + { + throw new BadImageFormatException(); + } + _baseType = type; + return type; + } + + public override MetadataType BaseType + { + get + { + if (_baseType == this) + return InitializeBaseType(); + return _baseType; + } + } + + TypeDesc[] _implementedInterfaces; + + private TypeDesc[] InitializeImplementedInterfaces() + { + var interfaceHandles = _typeDefinition.GetInterfaceImplementations(); + + int count = interfaceHandles.Count; + if (count == 0) + return (_implementedInterfaces = TypeDesc.EmptyTypes); + + TypeDesc[] implementedInterfaces = new TypeDesc[count]; + int i = 0; + foreach (var interfaceHandle in interfaceHandles) + { + var interfaceImplementation = this.MetadataReader.GetInterfaceImplementation(interfaceHandle); + implementedInterfaces[i++] = _module.GetType(interfaceImplementation.Interface); + } + return (_implementedInterfaces = implementedInterfaces); + } + + public override TypeDesc[] ImplementedInterfaces + { + get + { + if (_implementedInterfaces == null) + return InitializeImplementedInterfaces(); + return _implementedInterfaces; + } + } + + protected override TypeFlags ComputeTypeFlags(TypeFlags mask) + { + TypeFlags flags = 0; + + if ((mask & TypeFlags.ContainsGenericVariablesComputed) != 0) + { + flags |= TypeFlags.ContainsGenericVariablesComputed; + + // TODO: Do we really want to get the instantiation to figure out whether the type is generic? + if (this.HasInstantiation) + flags |= TypeFlags.ContainsGenericVariables; + } + + if ((mask & TypeFlags.CategoryMask) != 0) + { + TypeDesc baseType = this.BaseType; + + if (_module.Context.IsWellKnownType(baseType, WellKnownType.ValueType)) + { + flags |= TypeFlags.ValueType; + } + else + if (_module.Context.IsWellKnownType(baseType, WellKnownType.Enum)) + { + flags |= TypeFlags.Enum; + } + else + { + if ((_typeDefinition.Attributes & TypeAttributes.Interface) != 0) + flags |= TypeFlags.Interface; + else + flags |= TypeFlags.Class; + } + + // All other cases are handled during TypeSystemContext intitialization + } + + return flags; + } + + string _name; + + private string InitializeName() + { + var metadataReader = this.MetadataReader; + string typeName = metadataReader.GetString(_typeDefinition.Name); + string typeNamespace = metadataReader.GetString(_typeDefinition.Namespace); + string name = (typeNamespace.Length > 0) ? (typeNamespace + "." + typeName) : typeName; + return (_name = name); + } + + public override string Name + { + get + { + if (_name == null) + return InitializeName(); + return _name; + } + } + + public override IEnumerable GetMethods() + { + foreach (var handle in _typeDefinition.GetMethods()) + { + yield return (MethodDesc)this.Module.GetObject(handle); + } + } + + public override MethodDesc GetMethod(string name, MethodSignature signature) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetMethods()) + { + if (stringComparer.Equals(metadataReader.GetMethodDefinition(handle).Name, name)) + { + MethodDesc method = (MethodDesc)this.Module.GetObject(handle); + if (signature == null || signature.Equals(method.Signature)) + return method; + } + } + + return null; + } + + public override IEnumerable GetFields() + { + foreach (var handle in _typeDefinition.GetFields()) + { + yield return (FieldDesc)this.Module.GetObject(handle); + } + } + + public override FieldDesc GetField(string name) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetFields()) + { + if (stringComparer.Equals(metadataReader.GetFieldDefinition(handle).Name, name)) + return (FieldDesc)this.Module.GetObject(handle); + } + + return null; + } + + public IEnumerable GetNestedTypes() + { + foreach (var handle in _typeDefinition.GetNestedTypes()) + { + yield return (TypeDesc)this.Module.GetObject(handle); + } + } + + public TypeDesc GetNestedType(string name) + { + var metadataReader = this.MetadataReader; + var stringComparer = metadataReader.StringComparer; + + foreach (var handle in _typeDefinition.GetNestedTypes()) + { + if (stringComparer.Equals(metadataReader.GetTypeDefinition(handle).Name, name)) + return (TypeDesc)this.Module.GetObject(handle); + } + + return null; + } + + public TypeAttributes Attributes + { + get + { + return _typeDefinition.Attributes; + } + } + + // + // ContainingType of nested type + // + public TypeDesc ContainingType + { + get + { + var handle = _typeDefinition.GetDeclaringType(); + if (handle.IsNil) + return null; + return _module.GetType(handle); + } + } + + public bool HasCustomAttribute(string customAttributeName) + { + return this.Module.HasCustomAttribute(_typeDefinition.GetCustomAttributes(), customAttributeName); + } + + public override string ToString() + { + return this.Name; + } + + public override ClassLayoutMetadata GetClassLayout() + { + TypeLayout layout = TypeDefinition.GetLayout(); + + ClassLayoutMetadata result; + result.PackingSize = layout.PackingSize; + result.Size = layout.Size; + + // Skip reading field offsets if this is not explicit layout + if (IsExplicitLayout) + { + var numInstanceFields = 0; + + foreach (var handle in _typeDefinition.GetFields()) + { + var fieldDefinition = MetadataReader.GetFieldDefinition(handle); + if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) + continue; + + numInstanceFields++; + } + + result.Offsets = new FieldAndOffset[numInstanceFields]; + + int index = 0; + foreach (var handle in _typeDefinition.GetFields()) + { + var fieldDefinition = MetadataReader.GetFieldDefinition(handle); + if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0) + continue; + + // Note: GetOffset() returns -1 when offset was not set in the metadata which maps nicely + // to FieldAndOffset.InvalidOffset. + Debug.Assert(FieldAndOffset.InvalidOffset == -1); + result.Offsets[index] = + new FieldAndOffset((FieldDesc)this.Module.GetObject(handle), fieldDefinition.GetOffset()); + + index++; + } + } + else + result.Offsets = null; + + return result; + } + + public override bool IsExplicitLayout + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.ExplicitLayout) != 0; + } + } + + public override bool IsSequentialLayout + { + get + { + return (_typeDefinition.Attributes & TypeAttributes.SequentialLayout) != 0; + } + } + + public override bool IsModuleType + { + get + { + // TODO: make this return true if this is the type. + return false; + } + } + } +} diff --git a/src/TypeSystem/src/Ecma/IMetadataStringDecoderProvider.cs b/src/TypeSystem/src/Ecma/IMetadataStringDecoderProvider.cs new file mode 100644 index 00000000000..841c6c9fa91 --- /dev/null +++ b/src/TypeSystem/src/Ecma/IMetadataStringDecoderProvider.cs @@ -0,0 +1,13 @@ +// 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.Metadata; + +namespace Internal.TypeSystem.Ecma +{ + public interface IMetadataStringDecoderProvider + { + MetadataStringDecoder GetMetadataStringDecoder(); + } +} diff --git a/src/TypeSystem/src/Ecma/TypeSystem.Ecma.csproj b/src/TypeSystem/src/Ecma/TypeSystem.Ecma.csproj new file mode 100644 index 00000000000..14e070a9904 --- /dev/null +++ b/src/TypeSystem/src/Ecma/TypeSystem.Ecma.csproj @@ -0,0 +1,88 @@ + + + + + 12.0 + Debug + AnyCPU + {05F88F48-EF79-4866-8CAF-870BD1949196} + Library + Properties + Internal.TypeSystem.Ecma + TypeSystem.Ecma + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile44 + v4.6 + ..\ + true + SAK + SAK + SAK + SAK + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + {dd5b6baa-d41a-4a6e-9e7d-83060f394b10} + TypeSystem + + + + + ..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + + + ..\packages\System.Reflection.Metadata.1.0.22\lib\portable-net45+win8\System.Reflection.Metadata.dll + True + + + + + Designer + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/TypeSystem/src/Ecma/packages.config b/src/TypeSystem/src/Ecma/packages.config new file mode 100644 index 00000000000..80941725494 --- /dev/null +++ b/src/TypeSystem/src/Ecma/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file