Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Nattress <simonn@microsoft.com>2015-11-23 22:42:12 +0300
committerSimon Nattress <simonn@microsoft.com>2015-12-04 10:43:16 +0300
commitd4f77bc3fa5601d8c8956d5681eb080f0993fe8a (patch)
tree1cf144aaf1dbb16ccf13fa61857a43c1e387a618 /src/ILCompiler.Compiler
parentde72db556da5ff4f205ec7aa6b76dbd1a72d8550 (diff)
Fill out EEType fields
Fill out the fixed portion of the EEType data structure as expected by the runtime along with most of the variable pieces that follow. Correct the code-gen's calculation of where VTable entries start in the EEType. Add type-system support for asking if a type has a finalizer. Move EEType Flags and Kinds enums to the Common folder and consume them from the compiler and runtime. Transpose the new Type System's Category to a CorElementType for primitives / enum underlying types. Remove HasFinalizer assert in RhNewObject The following pieces are incomplete: Optional fields side data structure Interface dispatch map pointers Type variance Sealed virtual slots blob Generic Type Def EETypes
Diffstat (limited to 'src/ILCompiler.Compiler')
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs337
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs4
-rw-r--r--src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj3
3 files changed, 289 insertions, 55 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs
index beaac9bc9..782f03a03 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs
@@ -1,20 +1,53 @@
// 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 ILCompiler.DependencyAnalysisFramework;
+using Internal.Runtime;
using Internal.TypeSystem;
-
+using System;
+using System.Collections.Generic;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler.DependencyAnalysis
{
+ /// <summary>
+ /// Given a type, EETypeNode writes an EEType data structure in the format expected by the runtime.
+ ///
+ /// Format of an EEType:
+ ///
+ /// Field Size | Contents
+ /// ----------------+-----------------------------------
+ /// UInt16 | Component Size. For arrays this is the element type size, for strings it is 2 (.NET uses
+ /// | UTF16 character encoding), and 0 for all other types.
+ /// |
+ /// UInt16 | EETypeKind (Normal, Array, Pointer type). Flags for: IsValueType, IsCrossModule, HasPointers,
+ /// | HasOptionalFields, IsInterface, IsGeneric. Top 5 bits are used for enum CorElementType to
+ /// | record whether it's back by an Int32, Int16 etc
+ /// |
+ /// [Pointer Size] | Related type. Base type for regular types. Element type for arrays / pointer types.
+ /// |
+ /// UInt16 | Number of VTable slots (X)
+ /// |
+ /// UInt16 | Number of interfaces implemented by type (Y)
+ /// |
+ /// UInt32 | Hash code
+ /// |
+ /// X * [Ptr Size] | VTable entries (optional)
+ /// |
+ /// Y * [Ptr Size] | Pointers to interface map data structures (optional)
+ /// |
+ /// [Pointer Size] | Pointer to finalizer method (optional)
+ /// |
+ /// [Pointer Size] | Pointer to optional fields (optional)
+ /// |
+ /// [Pointer Size] | Pointer to the generic type argument of a Nullable&lt;T&gt; (optional)
+ ///
+ /// </summary>
internal class EETypeNode : ObjectNode, ISymbolNode
{
private TypeDesc _type;
private bool _constructed;
-
+
public EETypeNode(TypeDesc type, bool constructed)
{
_type = type;
@@ -94,25 +127,210 @@ namespace ILCompiler.DependencyAnalysis
ObjectDataBuilder objData = new ObjectDataBuilder(factory);
objData.Alignment = 16;
objData.DefinedSymbols.Add(this);
+
+ OutputComponentSize(ref objData);
+ OutputFlags(factory, ref objData);
+ OutputBaseSize(ref objData);
+ OutputRelatedType(factory, ref objData);
+ OutputVirtualSlotAndInterfaceCount(factory, ref objData);
+
+ objData.EmitInt(_type.GetHashCode());
+
+ if (_constructed)
+ {
+ OutputVirtualSlots(factory, ref objData, _type, _type);
+ OutputFinalizerMethod(factory, ref objData);
+ OutputNullableTypeParameter(factory, ref objData);
+ }
+
+ return objData.ToObjectData();
+ }
+
+ public override bool HasConditionalStaticDependencies
+ {
+ get
+ {
+ // non constructed types don't have vtables
+ if (!_constructed)
+ return false;
+
+ // Since the vtable is dependency driven, generate conditional static dependencies for
+ // all possible vtable entries
+ foreach (MethodDesc method in _type.GetMethods())
+ {
+ if (method.IsVirtual)
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
+ {
+ if (_type is MetadataType)
+ {
+ foreach (MethodDesc decl in VirtualFunctionResolution.EnumAllVirtualSlots((MetadataType)_type))
+ {
+ MethodDesc impl = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(decl, (MetadataType)_type);
+ if (impl.OwningType == _type && !impl.IsAbstract)
+ {
+ yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.MethodEntrypoint(impl), factory.VirtualMethodUse(decl), "Virtual method");
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns the offset within an EEType of the beginning of VTable entries
+ /// </summary>
+ /// <param name="pointerSize">The size of a pointer in bytes in the target architecture</param>
+ public static int GetVTableOffset(int pointerSize)
+ {
+ return 16 + pointerSize;
+ }
+
+ private void OutputComponentSize(ref ObjectDataBuilder objData)
+ {
if (_type.IsArray)
{
- objData.EmitShort((short)((ArrayType)_type).ElementType.GetElementSize()); // m_ComponentSize
- objData.EmitShort(0x4); // m_flags: IsArray(0x4)
+ objData.EmitShort((short)((ArrayType)_type).ElementType.GetElementSize());
}
else if (_type.IsString)
{
- objData.EmitShort(2); // m_ComponentSize
- objData.EmitShort(0); // m_flags: 0
+ objData.EmitShort(2);
}
else
{
- objData.EmitShort(0); // m_ComponentSize
- objData.EmitShort(0); // m_flags: 0
+ objData.EmitShort(0);
+ }
+ }
+
+ private void OutputFlags(NodeFactory factory, ref ObjectDataBuilder objData)
+ {
+ // Todo: RelatedTypeViaIATFlag when we support cross-module EETypes
+ // Todo: GenericVarianceFlag when we support variance
+ // Todo: OptionalFieldsFlag
+ // Todo: Generic Type Definition EETypes
+
+ UInt16 flags = (UInt16)EETypeKind.CanonicalEEType;
+
+ if (_type.IsArray || _type.IsPointer)
+ {
+ flags = (UInt16)EETypeKind.ParameterizedEEType;
+ }
+
+ if (_type.IsValueType)
+ {
+ flags |= (UInt16)EETypeFlags.ValueTypeFlag;
+ }
+
+ if (_type.HasFinalizer)
+ {
+ flags |= (UInt16)EETypeFlags.HasFinalizerFlag;
+ }
+
+ if (_type is MetadataType && ((MetadataType)_type).ContainsPointers)
+ {
+ flags |= (UInt16)EETypeFlags.HasPointersFlag;
+ }
+ else if (_type.IsArray)
+ {
+ ArrayType arrayType = _type as ArrayType;
+ if ((arrayType.ElementType.IsValueType && ((DefType)arrayType.ElementType).ContainsPointers) ||
+ !arrayType.ElementType.IsValueType)
+ {
+ flags |= (UInt16)EETypeFlags.HasPointersFlag;
+ }
+ }
+
+ if (_type.IsInterface)
+ {
+ flags |= (UInt16)EETypeFlags.IsInterfaceFlag;
+ }
+
+ if (_type.HasInstantiation)
+ {
+ flags |= (UInt16)EETypeFlags.IsGenericFlag;
+ }
+
+ int corElementType = 0;
+
+ // The top 5 bits of flags are used to convey enum underlying type, primitive type, or mark the type as being System.Array
+ if (_type.IsEnum)
+ {
+ TypeDesc underlyingType = _type.UnderlyingType;
+ Debug.Assert(TypeFlags.SByte <= underlyingType.Category && underlyingType.Category <= TypeFlags.UInt64);
+ corElementType = ComputeRhCorElementType(underlyingType);
+ }
+ else if (_type.IsPrimitive)
+ {
+ corElementType = ComputeRhCorElementType(_type);
+ }
+ else if (_type.IsArray)
+ {
+ corElementType = 0x14; // ELEMENT_TYPE_ARRAY
+ }
+
+ if (corElementType > 0)
+ {
+ flags |= (UInt16)(corElementType << (UInt16)EETypeFlags.CorElementTypeShift);
}
+ objData.EmitShort((short)flags);
+ }
+
+ private int ComputeRhCorElementType(TypeDesc type)
+ {
+ Debug.Assert(type.IsPrimitive);
+ Debug.Assert(type.Category != TypeFlags.Unknown);
+
+ switch (type.Category)
+ {
+ case TypeFlags.Void:
+ return 0x00;
+ case TypeFlags.Boolean:
+ return 0x02;
+ case TypeFlags.Char:
+ return 0x03;
+ case TypeFlags.SByte:
+ return 0x04;
+ case TypeFlags.Byte:
+ return 0x05;
+ case TypeFlags.Int16:
+ return 0x06;
+ case TypeFlags.UInt16:
+ return 0x07;
+ case TypeFlags.Int32:
+ return 0x08;
+ case TypeFlags.UInt32:
+ return 0x09;
+ case TypeFlags.Int64:
+ return 0x0A;
+ case TypeFlags.UInt64:
+ return 0x0B;
+ case TypeFlags.IntPtr:
+ return 0x18;
+ case TypeFlags.UIntPtr:
+ return 0x19;
+ case TypeFlags.Single:
+ return 0x0C;
+ case TypeFlags.Double:
+ return 0x0D;
+ default:
+ break;
+ }
+
+ Debug.Assert(false, "Primitive type value expected.");
+ return 0;
+ }
+
+ private void OutputBaseSize(ref ObjectDataBuilder objData)
+ {
int pointerSize = _type.Context.Target.PointerSize;
int minimumObjectSize = pointerSize * 3;
int objectSize;
+
if (_type is MetadataType)
{
objectSize = pointerSize +
@@ -126,12 +344,18 @@ namespace ILCompiler.DependencyAnalysis
objectSize +=
2 * _type.Context.GetWellKnownType(WellKnownType.Int32).GetElementSize() * rank;
}
+ else if (_type is PointerType)
+ {
+ // Object size 0 is a sentinel value in the runtime for parameterized types that means "Pointer Type"
+ objData.EmitInt(0);
+ return;
+ }
else
throw new NotImplementedException();
-
+
objectSize = AlignmentHelper.AlignUp(objectSize, pointerSize);
objectSize = Math.Max(minimumObjectSize, objectSize);
-
+
if (_type.IsString)
{
// If this is a string, throw away objectSize we computed so far. Strings are special.
@@ -142,89 +366,96 @@ namespace ILCompiler.DependencyAnalysis
}
objData.EmitInt(objectSize);
+ }
- if (Type.BaseType != null)
+ private void OutputRelatedType(NodeFactory factory, ref ObjectDataBuilder objData)
+ {
+ TypeDesc relatedType = _type.BaseType;
+ if (_type.IsArray || _type.IsPointer)
+ {
+ relatedType = ((ParameterizedType)_type).ParameterType;
+ }
+
+ if (relatedType != null)
{
if (_constructed)
{
- objData.EmitPointerReloc(factory.ConstructedTypeSymbol(Type.BaseType));
+ objData.EmitPointerReloc(factory.ConstructedTypeSymbol(relatedType));
}
else
{
- objData.EmitPointerReloc(factory.NecessaryTypeSymbol(Type.BaseType));
+ objData.EmitPointerReloc(factory.NecessaryTypeSymbol(relatedType));
}
}
else
{
objData.EmitZeroPointer();
}
-
- if (_constructed)
- {
- OutputVirtualSlots(ref objData, _type, _type, factory);
- }
-
- return objData.ToObjectData();
}
- public override bool HasConditionalStaticDependencies
+ private void OutputVirtualSlotAndInterfaceCount(NodeFactory factory, ref ObjectDataBuilder objData)
{
- get
- {
- // non constructed types don't have vtables
- if (!_constructed)
- return false;
+ int virtualSlotCount = 0;
+ TypeDesc currentTypeSlice = _type;
- // Since the vtable is dependency driven, generate conditional static dependencies for
- // all possible vtable entries
- foreach (MethodDesc method in _type.GetMethods())
+ while (currentTypeSlice != null)
+ {
+ List<MethodDesc> virtualSlots;
+ factory.VirtualSlots.TryGetValue(currentTypeSlice, out virtualSlots);
+ if (virtualSlots != null)
{
- if (method.IsVirtual)
- return true;
+ virtualSlotCount += virtualSlots.Count;
}
- return false;
+ currentTypeSlice = currentTypeSlice.BaseType;
}
- }
+
+ objData.EmitShort(checked((short)virtualSlotCount));
- public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
- {
- if (_type is MetadataType)
- {
- foreach (MethodDesc decl in VirtualFunctionResolution.EnumAllVirtualSlots((MetadataType)_type))
- {
- MethodDesc impl = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(decl, (MetadataType)_type);
- if (impl.OwningType == _type && !impl.IsAbstract)
- {
- yield return new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(factory.MethodEntrypoint(impl), factory.VirtualMethodUse(decl), "Virtual method");
- }
- }
- }
+ // Todo: Number of slots of EEInterfaceInfo when we add interface support
+ objData.EmitShort(0);
}
- private void OutputVirtualSlots(ref ObjectDataBuilder objData, TypeDesc implType, TypeDesc declType, NodeFactory context)
+ private void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objData, TypeDesc implType, TypeDesc declType)
{
var baseType = declType.BaseType;
if (baseType != null)
- OutputVirtualSlots(ref objData, implType, baseType, context);
+ OutputVirtualSlots(factory, ref objData, implType, baseType);
List<MethodDesc> virtualSlots;
- context.VirtualSlots.TryGetValue(declType, out virtualSlots);
+ factory.VirtualSlots.TryGetValue(declType, out virtualSlots);
if (virtualSlots != null)
{
for (int i = 0; i < virtualSlots.Count; i++)
{
MethodDesc declMethod = virtualSlots[i];
-
MethodDesc implMethod = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(declMethod, implType.GetClosestMetadataType());
if (!implMethod.IsAbstract)
- objData.EmitPointerReloc(context.MethodEntrypoint(implMethod));
+ objData.EmitPointerReloc(factory.MethodEntrypoint(implMethod));
else
objData.EmitZeroPointer();
}
}
}
+
+ private void OutputFinalizerMethod(NodeFactory factory, ref ObjectDataBuilder objData)
+ {
+ MethodDesc finalizerMethod = _type.GetFinalizer();
+
+ if (finalizerMethod != null)
+ {
+ objData.EmitPointerReloc(factory.MethodEntrypoint(finalizerMethod));
+ }
+ }
+
+ private void OutputNullableTypeParameter(NodeFactory factory, ref ObjectDataBuilder objData)
+ {
+ if (_type.IsNullable)
+ {
+ objData.EmitPointerReloc(factory.NecessaryTypeSymbol(_type.Instantiation[0]));
+ }
+ }
}
}
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs
index 73a1e9e56..c50307fd2 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs
@@ -58,9 +58,9 @@ namespace ILCompiler.DependencyAnalysis
break;
}
}
-
+
Debug.Assert(methodSlot != -1);
- AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, 16 + (baseSlots + methodSlot) * factory.Target.PointerSize, 0, AddrModeSize.Int64);
+ AddrMode jmpAddrMode = new AddrMode(encoder.TargetRegister.Result, null, EETypeNode.GetVTableOffset(factory.Target.PointerSize) + (baseSlots + methodSlot) * factory.Target.PointerSize, 0, AddrModeSize.Int64);
encoder.EmitJmpToAddrMode(ref jmpAddrMode);
}
break;
diff --git a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
index 8d28d0664..e8f4c1ef4 100644
--- a/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
+++ b/src/ILCompiler.Compiler/src/ILCompiler.Compiler.csproj
@@ -83,6 +83,9 @@
<Compile Include="..\..\Common\src\System\Collections\Generic\ArrayBuilder.cs">
<Link>Common\ArrayBuilder.cs</Link>
</Compile>
+ <Compile Include="..\..\Common\src\Internal\Runtime\EETypeFlags.cs" >
+ <Link>Common\EETypeFlags.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Common\src\TypeSystem\IL\EcmaMethodIL.cs">