// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Internal.NativeFormat;
using Internal.Runtime;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysisFramework;
namespace ILCompiler.DependencyAnalysis
{
///
/// Wrapper nodes for native layout vertex structures. These wrapper nodes are "abstract" as they do not
/// generate any data. They are used to keep track of the dependency nodes required by a Vertex structure.
///
/// Any node in the graph that references data in the native layout blob needs to create one of these
/// NativeLayoutVertexNode nodes, and track it as a dependency of itself.
/// Example: MethodCodeNodes that are saved to the table in the ExactMethodInstantiationsNode reference
/// signatures stored in the native layout blob, so a NativeLayoutPlacedSignatureVertexNode node is created
/// and returned as a static dependency of the associated MethodCodeNode (in the GetStaticDependencies API).
///
/// Each NativeLayoutVertexNode that gets marked in the graph will register itself with the NativeLayoutInfoNode,
/// so that the NativeLayoutInfoNode can write it later to the native layout blob during the call to its GetData API.
///
public abstract class NativeLayoutVertexNode : DependencyNodeCore
{
public override bool HasConditionalStaticDependencies => false;
public override bool HasDynamicDependencies => false;
public override bool InterestingForDynamicDependencyAnalysis => false;
public override bool StaticDependenciesAreComputed => true;
[Conditional("DEBUG")]
public virtual void CheckIfMarkedEnoughToWrite()
{
Debug.Assert(Marked);
}
public override IEnumerable GetConditionalStaticDependencies(NodeFactory context)
{
return Array.Empty();
}
public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory context)
{
return Array.Empty();
}
protected override void OnMarked(NodeFactory context)
{
context.MetadataManager.NativeLayoutInfo.AddVertexNodeToNativeLayout(this);
}
public abstract Vertex WriteVertex(NodeFactory factory);
protected NativeWriter GetNativeWriter(NodeFactory factory)
{
// There is only one native layout info blob, so only one writer for now...
return factory.MetadataManager.NativeLayoutInfo.Writer;
}
}
///
/// Any NativeLayoutVertexNode that needs to expose the native layout Vertex after it has been saved
/// needs to derive from this NativeLayoutSavedVertexNode class.
///
/// A nativelayout Vertex should typically only be exposed for Vertex offset fetching purposes, after the native
/// writer is saved (Vertex offsets get generated when the native writer gets saved).
///
/// It is important for whoever derives from this class to produce unified Vertices. Calling the WriteVertex method
/// multiple times should always produce the same exact unified Vertex each time (hence the assert in SetSavedVertex).
/// All nativewriter.Getxyz methods return unified Vertices.
///
/// When exposing a saved Vertex that is a result of a section placement operation (Section.Place(...)), always make
/// sure a unified Vertex is being placed in the section (Section.Place creates a PlacedVertex structure that wraps the
/// Vertex to be placed, so if the Vertex to be placed is unified, there will only be a single unified PlacedVertex
/// structure created for that placed Vertex).
///
public abstract class NativeLayoutSavedVertexNode : NativeLayoutVertexNode
{
public Vertex SavedVertex { get; private set; }
protected Vertex SetSavedVertex(Vertex value)
{
Debug.Assert(SavedVertex == null || Object.ReferenceEquals(SavedVertex, value));
SavedVertex = value;
return value;
}
}
internal abstract class NativeLayoutMethodEntryVertexNode : NativeLayoutSavedVertexNode
{
[Flags]
public enum MethodEntryFlags
{
CreateInstantiatedSignature = 1,
SaveEntryPoint = 2,
}
protected readonly MethodDesc _method;
private MethodEntryFlags _flags;
private NativeLayoutTypeSignatureVertexNode _containingTypeSig;
private NativeLayoutMethodSignatureVertexNode _methodSig;
private NativeLayoutTypeSignatureVertexNode[] _instantiationArgsSig;
public NativeLayoutMethodEntryVertexNode(NodeFactory factory, MethodDesc method, MethodEntryFlags flags)
{
_method = method;
_flags = flags;
_methodSig = factory.NativeLayout.MethodSignatureVertex(method.GetTypicalMethodDefinition().Signature);
if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) == 0)
{
_containingTypeSig = factory.NativeLayout.TypeSignatureVertex(method.OwningType);
if (method.HasInstantiation && !method.IsMethodDefinition)
{
_instantiationArgsSig = new NativeLayoutTypeSignatureVertexNode[method.Instantiation.Length];
for (int i = 0; i < _instantiationArgsSig.Length; i++)
_instantiationArgsSig[i] = factory.NativeLayout.TypeSignatureVertex(method.Instantiation[i]);
}
}
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
DependencyList dependencies = new DependencyList();
dependencies.Add(new DependencyListEntry(_methodSig, "NativeLayoutMethodEntryVertexNode method signature"));
if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) != 0)
{
dependencies.Add(new DependencyListEntry(context.NecessaryTypeSymbol(_method.OwningType), "NativeLayoutMethodEntryVertexNode containing type"));
foreach (var arg in _method.Instantiation)
dependencies.Add(new DependencyListEntry(context.NecessaryTypeSymbol(arg), "NativeLayoutMethodEntryVertexNode instantiation argument type"));
}
else
{
dependencies.Add(new DependencyListEntry(_containingTypeSig, "NativeLayoutMethodEntryVertexNode containing type signature"));
if (_method.HasInstantiation && !_method.IsMethodDefinition)
{
foreach (var arg in _instantiationArgsSig)
dependencies.Add(new DependencyListEntry(arg, "NativeLayoutMethodEntryVertexNode instantiation argument signature"));
}
}
if ((_flags & MethodEntryFlags.SaveEntryPoint) != 0)
{
bool unboxingStub;
IMethodNode methodEntryPointNode = GetMethodEntrypointNode(context, out unboxingStub);
dependencies.Add(new DependencyListEntry(methodEntryPointNode, "NativeLayoutMethodEntryVertexNode entrypoint"));
}
return dependencies;
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex containingType = GetContainingTypeVertex(factory);
Vertex methodSig = _methodSig.WriteVertex(factory);
Vertex methodNameAndSig = GetNativeWriter(factory).GetMethodNameAndSigSignature(_method.Name, methodSig);
Vertex[] args = null;
MethodFlags flags = 0;
if (_method.HasInstantiation && !_method.IsMethodDefinition)
{
Debug.Assert(_instantiationArgsSig == null || (_instantiationArgsSig != null && _method.Instantiation.Length == _instantiationArgsSig.Length));
flags |= MethodFlags.HasInstantiation;
args = new Vertex[_method.Instantiation.Length];
for (int i = 0; i < args.Length; i++)
{
if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) != 0)
{
IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_method.Instantiation[i]);
uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode);
args[i] = GetNativeWriter(factory).GetExternalTypeSignature(typeIndex);
}
else
{
args[i] = _instantiationArgsSig[i].WriteVertex(factory);
}
}
}
uint fptrReferenceId = 0;
if ((_flags & MethodEntryFlags.SaveEntryPoint) != 0)
{
flags |= MethodFlags.HasFunctionPointer;
bool unboxingStub;
IMethodNode methodEntryPointNode = GetMethodEntrypointNode(factory, out unboxingStub);
fptrReferenceId = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(methodEntryPointNode);
if (unboxingStub)
flags |= MethodFlags.IsUnboxingStub;
if (methodEntryPointNode.Method.IsCanonicalMethod(CanonicalFormKind.Universal))
flags |= MethodFlags.FunctionPointerIsUSG;
}
return GetNativeWriter(factory).GetMethodSignature((uint)flags, fptrReferenceId, containingType, methodNameAndSig, args);
}
private Vertex GetContainingTypeVertex(NodeFactory factory)
{
if ((_flags & MethodEntryFlags.CreateInstantiatedSignature) != 0)
{
IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_method.OwningType);
uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode);
return GetNativeWriter(factory).GetExternalTypeSignature(typeIndex);
}
else
{
return _containingTypeSig.WriteVertex(factory);
}
}
protected virtual IMethodNode GetMethodEntrypointNode(NodeFactory factory, out bool unboxingStub)
{
unboxingStub = _method.OwningType.IsValueType && !_method.Signature.IsStatic;
IMethodNode methodEntryPointNode = factory.MethodEntrypoint(_method, unboxingStub);
return methodEntryPointNode;
}
}
internal sealed class NativeLayoutMethodLdTokenVertexNode : NativeLayoutMethodEntryVertexNode
{
protected override string GetName(NodeFactory factory) => "NativeLayoutMethodLdTokenVertexNode_" + factory.NameMangler.GetMangledMethodName(_method);
public NativeLayoutMethodLdTokenVertexNode(NodeFactory factory, MethodDesc method)
: base(factory, method, 0)
{
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex methodEntryVertex = base.WriteVertex(factory);
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.LdTokenInfoSection.Place(methodEntryVertex));
}
}
internal sealed class NativeLayoutFieldLdTokenVertexNode : NativeLayoutSavedVertexNode
{
private readonly FieldDesc _field;
private readonly NativeLayoutTypeSignatureVertexNode _containingTypeSig;
public NativeLayoutFieldLdTokenVertexNode(NodeFactory factory, FieldDesc field)
{
_field = field;
_containingTypeSig = factory.NativeLayout.TypeSignatureVertex(field.OwningType);
}
protected override string GetName(NodeFactory factory) => "NativeLayoutFieldLdTokenVertexNode_" + factory.NameMangler.GetMangledFieldName(_field);
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[]
{
new DependencyListEntry(_containingTypeSig, "NativeLayoutFieldLdTokenVertexNode containing type signature"),
};
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex containingType = _containingTypeSig.WriteVertex(factory);
Vertex unplacedVertex = GetNativeWriter(factory).GetFieldSignature(containingType, _field.Name);
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.LdTokenInfoSection.Place(unplacedVertex));
}
}
internal sealed class NativeLayoutMethodSignatureVertexNode : NativeLayoutVertexNode
{
private Internal.TypeSystem.MethodSignature _signature;
private NativeLayoutTypeSignatureVertexNode _returnTypeSig;
private NativeLayoutTypeSignatureVertexNode[] _parametersSig;
protected override string GetName(NodeFactory factory) => "NativeLayoutMethodSignatureVertexNode " + _signature.GetName();
public NativeLayoutMethodSignatureVertexNode(NodeFactory factory, Internal.TypeSystem.MethodSignature signature)
{
_signature = signature;
_returnTypeSig = factory.NativeLayout.TypeSignatureVertex(signature.ReturnType);
_parametersSig = new NativeLayoutTypeSignatureVertexNode[signature.Length];
for (int i = 0; i < _parametersSig.Length; i++)
_parametersSig[i] = factory.NativeLayout.TypeSignatureVertex(signature[i]);
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
DependencyList dependencies = new DependencyList();
dependencies.Add(new DependencyListEntry(_returnTypeSig, "NativeLayoutMethodSignatureVertexNode return type signature"));
foreach (var arg in _parametersSig)
dependencies.Add(new DependencyListEntry(arg, "NativeLayoutMethodSignatureVertexNode parameter signature"));
return dependencies;
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
MethodCallingConvention methodCallingConvention = default(MethodCallingConvention);
if (_signature.GenericParameterCount > 0)
methodCallingConvention |= MethodCallingConvention.Generic;
if (_signature.IsStatic)
methodCallingConvention |= MethodCallingConvention.Static;
Debug.Assert(_signature.Length == _parametersSig.Length);
Vertex returnType = _returnTypeSig.WriteVertex(factory);
Vertex[] parameters = new Vertex[_parametersSig.Length];
for (int i = 0; i < _parametersSig.Length; i++)
parameters[i] = _parametersSig[i].WriteVertex(factory);
Vertex signature = GetNativeWriter(factory).GetMethodSigSignature((uint)methodCallingConvention, (uint)_signature.GenericParameterCount, returnType, parameters);
return factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(signature);
}
}
internal sealed class NativeLayoutMethodNameAndSignatureVertexNode : NativeLayoutVertexNode
{
private MethodDesc _method;
private NativeLayoutMethodSignatureVertexNode _methodSig;
protected override string GetName(NodeFactory factory) => "NativeLayoutMethodNameAndSignatureVertexNode" + factory.NameMangler.GetMangledMethodName(_method);
public NativeLayoutMethodNameAndSignatureVertexNode(NodeFactory factory, MethodDesc method)
{
_method = method;
_methodSig = factory.NativeLayout.MethodSignatureVertex(method.Signature);
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[] { new DependencyListEntry(_methodSig, "NativeLayoutMethodNameAndSignatureVertexNode signature vertex") };
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex methodSig = _methodSig.WriteVertex(factory);
return GetNativeWriter(factory).GetMethodNameAndSigSignature(_method.Name, methodSig);
}
}
internal abstract class NativeLayoutTypeSignatureVertexNode : NativeLayoutVertexNode
{
protected readonly TypeDesc _type;
protected NativeLayoutTypeSignatureVertexNode(TypeDesc type)
{
_type = type;
}
protected override string GetName(NodeFactory factory) => "NativeLayoutTypeSignatureVertexNode: " + _type.ToString();
public static NativeLayoutTypeSignatureVertexNode NewTypeSignatureVertexNode(NodeFactory factory, TypeDesc type)
{
switch (type.Category)
{
case Internal.TypeSystem.TypeFlags.Array:
case Internal.TypeSystem.TypeFlags.SzArray:
case Internal.TypeSystem.TypeFlags.Pointer:
case Internal.TypeSystem.TypeFlags.ByRef:
return new NativeLayoutParameterizedTypeSignatureVertexNode(factory, type);
case Internal.TypeSystem.TypeFlags.SignatureTypeVariable:
case Internal.TypeSystem.TypeFlags.SignatureMethodVariable:
return new NativeLayoutGenericVarSignatureVertexNode(factory, type);
// TODO Internal.TypeSystem.TypeFlags.FunctionPointer (Runtime parsing also not yet implemented)
case Internal.TypeSystem.TypeFlags.FunctionPointer:
throw new NotImplementedException("FunctionPointer signature");
default:
{
Debug.Assert(type.IsDefType);
if (type.HasInstantiation && !type.IsGenericDefinition)
return new NativeLayoutInstantiatedTypeSignatureVertexNode(factory, type);
else
return new NativeLayoutEETypeSignatureVertexNode(factory, type);
}
}
}
sealed class NativeLayoutParameterizedTypeSignatureVertexNode : NativeLayoutTypeSignatureVertexNode
{
private NativeLayoutVertexNode _parameterTypeSig;
public NativeLayoutParameterizedTypeSignatureVertexNode(NodeFactory factory, TypeDesc type) : base(type)
{
_parameterTypeSig = factory.NativeLayout.TypeSignatureVertex(((ParameterizedType)type).ParameterType);
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[] { new DependencyListEntry(_parameterTypeSig, "NativeLayoutParameterizedTypeSignatureVertexNode parameter type signature") };
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
switch (_type.Category)
{
case Internal.TypeSystem.TypeFlags.SzArray:
return GetNativeWriter(factory).GetModifierTypeSignature(TypeModifierKind.Array, _parameterTypeSig.WriteVertex(factory));
case Internal.TypeSystem.TypeFlags.Pointer:
return GetNativeWriter(factory).GetModifierTypeSignature(TypeModifierKind.Pointer, _parameterTypeSig.WriteVertex(factory));
case Internal.TypeSystem.TypeFlags.ByRef:
return GetNativeWriter(factory).GetModifierTypeSignature(TypeModifierKind.ByRef, _parameterTypeSig.WriteVertex(factory));
case Internal.TypeSystem.TypeFlags.Array:
{
Vertex elementType = _parameterTypeSig.WriteVertex(factory);
// Skip bounds and lobounds (TODO)
var bounds = Array.Empty();
var lobounds = Array.Empty();
return GetNativeWriter(factory).GetMDArrayTypeSignature(elementType, (uint)((ArrayType)_type).Rank, bounds, lobounds);
}
}
Debug.Fail("UNREACHABLE");
return null;
}
}
sealed class NativeLayoutGenericVarSignatureVertexNode : NativeLayoutTypeSignatureVertexNode
{
public NativeLayoutGenericVarSignatureVertexNode(NodeFactory factory, TypeDesc type) : base(type)
{
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return Array.Empty();
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
switch (_type.Category)
{
case Internal.TypeSystem.TypeFlags.SignatureTypeVariable:
return GetNativeWriter(factory).GetVariableTypeSignature((uint)((SignatureVariable)_type).Index, false);
case Internal.TypeSystem.TypeFlags.SignatureMethodVariable:
return GetNativeWriter(factory).GetVariableTypeSignature((uint)((SignatureMethodVariable)_type).Index, true);
}
Debug.Fail("UNREACHABLE");
return null;
}
}
sealed class NativeLayoutInstantiatedTypeSignatureVertexNode : NativeLayoutTypeSignatureVertexNode
{
private NativeLayoutTypeSignatureVertexNode _genericTypeDefSig;
private NativeLayoutTypeSignatureVertexNode[] _instantiationArgs;
public NativeLayoutInstantiatedTypeSignatureVertexNode(NodeFactory factory, TypeDesc type) : base(type)
{
Debug.Assert(type.HasInstantiation && !type.IsGenericDefinition);
_genericTypeDefSig = factory.NativeLayout.TypeSignatureVertex(type.GetTypeDefinition());
_instantiationArgs = new NativeLayoutTypeSignatureVertexNode[type.Instantiation.Length];
for (int i = 0; i < _instantiationArgs.Length; i++)
_instantiationArgs[i] = factory.NativeLayout.TypeSignatureVertex(type.Instantiation[i]);
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
DependencyList dependencies = new DependencyList();
dependencies.Add(new DependencyListEntry(_genericTypeDefSig, "NativeLayoutInstantiatedTypeSignatureVertexNode generic definition signature"));
foreach (var arg in _instantiationArgs)
dependencies.Add(new DependencyListEntry(arg, "NativeLayoutInstantiatedTypeSignatureVertexNode instantiation argument signature"));
return dependencies;
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex genericDefVertex = _genericTypeDefSig.WriteVertex(factory);
Vertex[] args = new Vertex[_instantiationArgs.Length];
for (int i = 0; i < args.Length; i++)
args[i] = _instantiationArgs[i].WriteVertex(factory);
return GetNativeWriter(factory).GetInstantiationTypeSignature(genericDefVertex, args);
}
}
sealed class NativeLayoutEETypeSignatureVertexNode : NativeLayoutTypeSignatureVertexNode
{
public NativeLayoutEETypeSignatureVertexNode(NodeFactory factory, TypeDesc type) : base(type)
{
Debug.Assert(!type.IsRuntimeDeterminedSubtype);
Debug.Assert(!type.HasInstantiation || type.IsGenericDefinition);
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[]
{
new DependencyListEntry(context.NecessaryTypeSymbol(_type), "NativeLayoutEETypeVertexNode containing type signature")
};
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
IEETypeNode eetypeNode = factory.NecessaryTypeSymbol(_type);
uint typeIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(eetypeNode);
return GetNativeWriter(factory).GetExternalTypeSignature(typeIndex);
}
}
}
public sealed class NativeLayoutExternalReferenceVertexNode : NativeLayoutVertexNode
{
private ISymbolNode _symbol;
public NativeLayoutExternalReferenceVertexNode(NodeFactory factory, ISymbolNode symbol)
{
_symbol = symbol;
}
protected override string GetName(NodeFactory factory) => "NativeLayoutISymbolNodeReferenceVertexNode " + _symbol.GetMangledName(factory.NameMangler);
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[]
{
new DependencyListEntry(_symbol, "NativeLayoutISymbolNodeReferenceVertexNode containing symbol")
};
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
uint symbolIndex = factory.MetadataManager.NativeLayoutInfo.ExternalReferences.GetIndex(_symbol);
return GetNativeWriter(factory).GetUnsignedConstant(symbolIndex);
}
}
internal sealed class NativeLayoutPlacedSignatureVertexNode : NativeLayoutSavedVertexNode
{
private NativeLayoutVertexNode _signatureToBePlaced;
protected override string GetName(NodeFactory factory) => "NativeLayoutPlacedSignatureVertexNode";
public NativeLayoutPlacedSignatureVertexNode(NativeLayoutVertexNode signatureToBePlaced)
{
_signatureToBePlaced = signatureToBePlaced;
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[] { new DependencyListEntry(_signatureToBePlaced, "NativeLayoutPlacedSignatureVertexNode placed signature") };
}
public override Vertex WriteVertex(NodeFactory factory)
{
// This vertex doesn't need to assert as marked, as it simply represents the concept of an existing vertex which has been placed.
// Always use the NativeLayoutInfo blob for names and sigs, even if the associated types/methods are written elsewhere.
// This saves space, since we can Unify more signatures, allows optimizations in comparing sigs in the same module, and
// prevents the dynamic type loader having to know about other native layout sections (since sigs contain types). If we are
// using a non-native layout info writer, write the sig to the native layout info, and refer to it by offset in its own
// section. At runtime, we will assume all names and sigs are in the native layout and find it.
Vertex signature = _signatureToBePlaced.WriteVertex(factory);
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(signature));
}
}
internal sealed class NativeLayoutPlacedVertexSequenceOfUIntVertexNode : NativeLayoutSavedVertexNode
{
private List _uints;
protected override string GetName(NodeFactory factory) => "NativeLayoutPlacedVertexSequenceVertexNode";
public NativeLayoutPlacedVertexSequenceOfUIntVertexNode(List uints)
{
_uints = uints;
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
// There are no interesting dependencies
return null;
}
public override Vertex WriteVertex(NodeFactory factory)
{
// Eagerly return the SavedVertex so that we can unify the VertexSequence
if (SavedVertex != null)
return SavedVertex;
// This vertex doesn't need to assert as marked, as it simply represents the concept of an existing vertex which has been placed.
NativeWriter writer = GetNativeWriter(factory);
VertexSequence sequence = new VertexSequence();
foreach (uint value in _uints)
{
sequence.Append(writer.GetUnsignedConstant(value));
}
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(sequence));
}
}
internal sealed class NativeLayoutPlacedVertexSequenceVertexNode : NativeLayoutSavedVertexNode
{
private List _vertices;
protected override string GetName(NodeFactory factory) => "NativeLayoutPlacedVertexSequenceVertexNode";
public NativeLayoutPlacedVertexSequenceVertexNode(List vertices)
{
_vertices = vertices;
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
DependencyListEntry[] dependencies = new DependencyListEntry[_vertices.Count];
for (int i = 0; i < _vertices.Count; i++)
{
dependencies[i] = new DependencyListEntry(_vertices[i], "NativeLayoutPlacedVertexSequenceVertexNode element");
}
return dependencies;
}
public override Vertex WriteVertex(NodeFactory factory)
{
// Eagerly return the SavedVertex so that we can unify the VertexSequence
if (SavedVertex != null)
return SavedVertex;
// This vertex doesn't need to assert as marked, as it simply represents the concept of an existing vertex which has been placed.
VertexSequence sequence = new VertexSequence();
foreach (NativeLayoutVertexNode vertex in _vertices)
{
sequence.Append(vertex.WriteVertex(factory));
}
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(sequence));
}
}
internal sealed class NativeLayoutTemplateMethodSignatureVertexNode : NativeLayoutMethodEntryVertexNode
{
protected override string GetName(NodeFactory factory) => "NativeLayoutTemplateMethodSignatureVertexNode_" + factory.NameMangler.GetMangledMethodName(_method);
public NativeLayoutTemplateMethodSignatureVertexNode(NodeFactory factory, MethodDesc method)
: base(factory, method, MethodEntryFlags.CreateInstantiatedSignature | (method.IsVirtual ? MethodEntryFlags.SaveEntryPoint : 0))
{
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
Vertex methodEntryVertex = base.WriteVertex(factory);
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.TemplatesSection.Place(methodEntryVertex));
}
protected override IMethodNode GetMethodEntrypointNode(NodeFactory factory, out bool unboxingStub)
{
// Only GVM templates need entry points.
Debug.Assert(_method.IsVirtual);
unboxingStub = _method.OwningType.IsValueType;
IMethodNode methodEntryPointNode = factory.MethodEntrypoint(_method, unboxingStub);
// Note: We don't set the IsUnboxingStub flag on template methods (all template lookups performed at runtime are performed with this flag not set,
// since it can't always be conveniently computed for a concrete method before looking up its template)
unboxingStub = false;
return methodEntryPointNode;
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
DependencyList dependencies = (DependencyList)base.GetStaticDependencies(context);
foreach (var arg in _method.Instantiation)
{
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(arg))
{
dependencies.Add(new DependencyListEntry(dependency, "Dependencies to make a generic method template viable Method Instantiation"));
}
}
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(_method.OwningType))
{
dependencies.Add(new DependencyListEntry(dependency, "Dependencies to make a generic method template viable OwningType"));
}
return dependencies;
}
}
public sealed class NativeLayoutDictionarySignatureNode : NativeLayoutSavedVertexNode
{
private TypeSystemEntity _owningMethodOrType;
public NativeLayoutDictionarySignatureNode(NodeFactory nodeFactory, TypeSystemEntity owningMethodOrType)
{
if (owningMethodOrType is MethodDesc)
{
MethodDesc owningMethod = (MethodDesc)owningMethodOrType;
Debug.Assert(owningMethod.IsCanonicalMethod(CanonicalFormKind.Universal) || nodeFactory.LazyGenericsPolicy.UsesLazyGenerics(owningMethod));
Debug.Assert(owningMethod.IsCanonicalMethod(CanonicalFormKind.Any));
Debug.Assert(owningMethod.HasInstantiation);
}
else
{
TypeDesc owningType = (TypeDesc)owningMethodOrType;
Debug.Assert(owningType.IsCanonicalSubtype(CanonicalFormKind.Universal) || nodeFactory.LazyGenericsPolicy.UsesLazyGenerics(owningType));
Debug.Assert(owningType.IsCanonicalSubtype(CanonicalFormKind.Any));
}
_owningMethodOrType = owningMethodOrType;
}
private GenericContextKind ContextKind(NodeFactory factory)
{
if (_owningMethodOrType is MethodDesc)
{
MethodDesc owningMethod = (MethodDesc)_owningMethodOrType;
Debug.Assert(owningMethod.HasInstantiation);
return GenericContextKind.FromMethodHiddenArg | GenericContextKind.NeedsUSGContext;
}
else
{
TypeDesc owningType = (TypeDesc)_owningMethodOrType;
if (owningType.IsSzArray || owningType.HasSameTypeDefinition(factory.ArrayOfTClass) || owningType.IsValueType || owningType.IsSealed())
{
return GenericContextKind.FromHiddenArg | GenericContextKind.NeedsUSGContext;
}
else
{
return GenericContextKind.FromHiddenArg | GenericContextKind.NeedsUSGContext | GenericContextKind.HasDeclaringType;
}
}
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
if ((ContextKind(context) & GenericContextKind.HasDeclaringType) != 0)
{
return new DependencyListEntry[]
{
new DependencyListEntry(context.NativeLayout.TypeSignatureVertex((TypeDesc)_owningMethodOrType), "DeclaringType signature"),
new DependencyListEntry(context.GenericDictionaryLayout(_owningMethodOrType), "Dictionary Layout")
};
}
else
{
return new DependencyListEntry[]
{
new DependencyListEntry(context.GenericDictionaryLayout(_owningMethodOrType), "Dictionary Layout")
};
}
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
VertexSequence sequence = new VertexSequence();
DictionaryLayoutNode associatedLayout = factory.GenericDictionaryLayout(_owningMethodOrType);
Debug.Assert(associatedLayout.Marked);
ICollection templateLayout = associatedLayout.GetTemplateEntries(factory);
foreach (NativeLayoutVertexNode dictionaryEntry in templateLayout)
{
dictionaryEntry.CheckIfMarkedEnoughToWrite();
sequence.Append(dictionaryEntry.WriteVertex(factory));
}
Vertex signature;
GenericContextKind contextKind = ContextKind(factory);
NativeWriter nativeWriter = GetNativeWriter(factory);
if ((contextKind & GenericContextKind.HasDeclaringType) != 0)
{
signature = nativeWriter.GetTuple(factory.NativeLayout.TypeSignatureVertex((TypeDesc)_owningMethodOrType).WriteVertex(factory), sequence);
}
else
{
signature = sequence;
}
Vertex signatureWithContextKind = nativeWriter.GetTuple(nativeWriter.GetUnsignedConstant((uint)contextKind), signature);
return SetSavedVertex(factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(signatureWithContextKind));
}
protected override string GetName(NodeFactory factory) => $"Dictionary layout signature for {_owningMethodOrType.ToString()}";
}
public sealed class NativeLayoutTemplateMethodLayoutVertexNode : NativeLayoutSavedVertexNode
{
private MethodDesc _method;
protected override string GetName(NodeFactory factory) => "NativeLayoutTemplateMethodLayoutVertexNode" + factory.NameMangler.GetMangledMethodName(_method);
public NativeLayoutTemplateMethodLayoutVertexNode(NodeFactory factory, MethodDesc method)
{
_method = method;
Debug.Assert(method.HasInstantiation);
Debug.Assert(method.IsCanonicalMethod(CanonicalFormKind.Any));
Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method, "Assert that the canonical method passed in is in standard canonical form");
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(_method.OwningType))
{
yield return new DependencyListEntry(dependency, "method OwningType itself must be template loadable");
}
foreach (var type in _method.Instantiation)
{
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(type))
{
yield return new DependencyListEntry(dependency, "method's instantiation arguments must be template loadable");
}
}
yield return new DependencyListEntry(context.GenericDictionaryLayout(_method), "Dictionary layout");
}
private int CompareDictionaryEntries(KeyValuePair left, KeyValuePair right)
{
return left.Key - right.Key;
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
VertexBag layoutInfo = new VertexBag();
DictionaryLayoutNode associatedLayout = factory.GenericDictionaryLayout(_method);
ICollection templateLayout = associatedLayout.GetTemplateEntries(factory);
if (!(_method.IsCanonicalMethod(CanonicalFormKind.Universal) || (factory.LazyGenericsPolicy.UsesLazyGenerics(_method))) && (templateLayout.Count > 0))
{
List dictionaryVertices = new List();
foreach (NativeLayoutVertexNode dictionaryEntry in templateLayout)
{
dictionaryEntry.CheckIfMarkedEnoughToWrite();
dictionaryVertices.Add(dictionaryEntry);
}
NativeLayoutVertexNode dictionaryLayout = factory.NativeLayout.PlacedVertexSequence(dictionaryVertices);
layoutInfo.Append(BagElementKind.DictionaryLayout, dictionaryLayout.WriteVertex(factory));
}
factory.MetadataManager.NativeLayoutInfo.TemplatesSection.Place(layoutInfo);
return SetSavedVertex(layoutInfo);
}
}
public sealed class NativeLayoutTemplateTypeLayoutVertexNode : NativeLayoutSavedVertexNode
{
private TypeDesc _type;
private bool _isUniversalCanon;
protected override string GetName(NodeFactory factory) => "NativeLayoutTemplateTypeLayoutVertexNode_" + factory.NameMangler.GetMangledTypeName(_type);
public NativeLayoutTemplateTypeLayoutVertexNode(NodeFactory factory, TypeDesc type)
{
Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any));
Debug.Assert(type.ConvertToCanonForm(CanonicalFormKind.Specific) == type, "Assert that the canonical type passed in is in standard canonical form");
_isUniversalCanon = type.IsCanonicalSubtype(CanonicalFormKind.Universal);
_type = GetActualTemplateTypeForType(factory, type);
}
private static TypeDesc GetActualTemplateTypeForType(NodeFactory factory, TypeDesc type)
{
DefType defType = type as DefType;
if (defType == null)
{
Debug.Assert(GenericTypesTemplateMap.IsArrayTypeEligibleForTemplate(type));
defType = type.GetClosestDefType().ConvertToSharedRuntimeDeterminedForm();
Debug.Assert(defType.Instantiation.Length == 1);
return factory.TypeSystemContext.GetArrayType(defType.Instantiation[0]);
}
else
{
return defType.ConvertToSharedRuntimeDeterminedForm();
}
}
private ISymbolNode GetStaticsNode(NodeFactory context, out BagElementKind staticsBagKind)
{
ISymbolNode symbol;
if (context is UtcNodeFactory)
{
symbol = ((UtcNodeFactory)context).TypeGCStaticDescSymbol((MetadataType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific));
staticsBagKind = BagElementKind.GcStaticDesc;
}
else
{
symbol = context.GCStaticEEType(GCPointerMap.FromStaticLayout(_type.GetClosestDefType()));
staticsBagKind = BagElementKind.GcStaticEEType;
}
return symbol;
}
private ISymbolNode GetThreadStaticsNode(NodeFactory context, out BagElementKind staticsBagKind)
{
ISymbolNode symbol;
if (context is UtcNodeFactory)
{
symbol = ((UtcNodeFactory)context).TypeThreadStaticGCDescNode((MetadataType)_type.GetClosestDefType().ConvertToCanonForm(CanonicalFormKind.Specific));
staticsBagKind = BagElementKind.ThreadStaticDesc;
}
else
{
symbol = context.GCStaticEEType(GCPointerMap.FromThreadStaticLayout(_type.GetClosestDefType()));
staticsBagKind = BagElementKind.End; // GC static EETypes not yet implemented in type loader
}
return symbol;
}
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
ISymbolNode typeNode = context.MaximallyConstructableType(_type.ConvertToCanonForm(CanonicalFormKind.Specific));
yield return new DependencyListEntry(typeNode, "Template EEType");
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(_type))
{
yield return new DependencyListEntry(dependency, "type itslef must be template loadable");
}
yield return new DependencyListEntry(context.GenericDictionaryLayout(_type.ConvertToCanonForm(CanonicalFormKind.Specific).GetClosestDefType()), "Dictionary layout");
foreach (TypeDesc iface in _type.RuntimeInterfaces)
{
yield return new DependencyListEntry(context.NativeLayout.TypeSignatureVertex(iface), "template interface list");
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(iface))
{
yield return new DependencyListEntry(dependency, "interface type dependency must be template loadable");
}
}
if (context.TypeSystemContext.HasLazyStaticConstructor(_type))
{
yield return new DependencyListEntry(context.MethodEntrypoint(_type.GetStaticConstructor().GetCanonMethodTarget(CanonicalFormKind.Specific)), "cctor for template");
}
if (!_isUniversalCanon)
{
if (_type.GetClosestDefType().GCStaticFieldSize.AsInt > 0)
{
BagElementKind ignored;
yield return new DependencyListEntry(GetStaticsNode(context, out ignored), "type gc static info");
}
if (_type.GetClosestDefType().ThreadGcStaticFieldSize.AsInt > 0)
{
BagElementKind ignored;
yield return new DependencyListEntry(GetThreadStaticsNode(context, out ignored), "type thread static info");
}
}
if (_type.BaseType != null && !_type.BaseType.IsRuntimeDeterminedSubtype)
{
TypeDesc baseType = _type.BaseType;
do
{
yield return new DependencyListEntry(context.MaximallyConstructableType(baseType), "base types of canonical types must have their full vtables");
baseType = baseType.BaseType;
} while (baseType != null);
}
if (_type.BaseType != null && _type.BaseType.IsRuntimeDeterminedSubtype)
{
yield return new DependencyListEntry(context.NativeLayout.PlacedSignatureVertex(context.NativeLayout.TypeSignatureVertex(_type.BaseType)), "template base type");
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(_type.BaseType))
{
yield return new DependencyListEntry(dependency, "base type must be template loadable");
}
}
else if (_type.IsDelegate && _isUniversalCanon)
{
// For USG delegate, we need to write the signature of the Invoke method to the native layout.
// This signature is used by the calling convention converter to marshal parameters during delegate calls.
yield return new DependencyListEntry(context.NativeLayout.MethodSignatureVertex(_type.GetMethod("Invoke", null).GetTypicalMethodDefinition().Signature), "invoke method signature");
}
if (_isUniversalCanon)
{
// For universal canonical template types, we need to write out field layout information so that we
// can correctly compute the type sizes for dynamically created types at runtime, and construct
// their GCDesc info
foreach (FieldDesc field in _type.GetFields())
{
// If this field does not contribute to layout, skip
if (field.HasRva || field.IsLiteral)
{
continue;
}
DependencyListEntry typeForFieldLayout;
if (field.FieldType.IsGCPointer)
{
typeForFieldLayout = new DependencyListEntry(context.NativeLayout.PlacedSignatureVertex(context.NativeLayout.TypeSignatureVertex(field.Context.GetWellKnownType(WellKnownType.Object))), "universal field layout type object sized");
}
else if (field.FieldType.IsPointer || field.FieldType.IsFunctionPointer)
{
typeForFieldLayout = new DependencyListEntry(context.NativeLayout.PlacedSignatureVertex(context.NativeLayout.TypeSignatureVertex(field.Context.GetWellKnownType(WellKnownType.IntPtr))), "universal field layout type IntPtr sized");
}
else
{
typeForFieldLayout = new DependencyListEntry(context.NativeLayout.PlacedSignatureVertex(context.NativeLayout.TypeSignatureVertex(field.FieldType)), "universal field layout type");
// And ensure the type can be properly laid out
foreach (var dependency in context.NativeLayout.TemplateConstructableTypes(field.FieldType))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
yield return typeForFieldLayout;
}
// We also need to write out the signatures of interesting methods in the type's vtable, which
// will be needed by the calling convention translation logic at runtime, when the type's methods
// get invoked. This logic gathers nodes for entries *unconditionally* present. (entries may be conditionally
// present if a type has a vtable which has a size computed by usage not by IL contents)
List vtableSignatureNodeEntries = null;
int currentVTableIndexUnused = 0;
ProcessVTableEntriesForCallingConventionSignatureGeneration(context, VTableEntriesToProcess.AllOnTypesThatShouldProduceFullVTables, ref currentVTableIndexUnused,
(int vtableIndex, bool isSealedVTableSlot, MethodDesc declMethod, MethodDesc implMethod) =>
{
if (implMethod.IsAbstract)
return;
if (UniversalGenericParameterLayout.VTableMethodRequiresCallingConventionConverter(implMethod))
{
if (vtableSignatureNodeEntries == null)
vtableSignatureNodeEntries = new List();
vtableSignatureNodeEntries.Add(context.NativeLayout.MethodSignatureVertex(declMethod.GetTypicalMethodDefinition().Signature));
}
}
, _type, _type, _type);
if (vtableSignatureNodeEntries != null)
{
foreach (NativeLayoutVertexNode node in vtableSignatureNodeEntries)
yield return new DependencyListEntry(node, "vtable cctor sig");
}
}
}
public override bool HasConditionalStaticDependencies => _isUniversalCanon;
public override IEnumerable GetConditionalStaticDependencies(NodeFactory context)
{
List conditionalDependencies = null;
if (_isUniversalCanon)
{
// We also need to write out the signatures of interesting methods in the type's vtable, which
// will be needed by the calling convention translation logic at runtime, when the type's methods
// get invoked. This logic gathers nodes for entries *conditionally* present. (entries may be conditionally
// present if a type has a vtable which has a size computed by usage not by IL contents)
int currentVTableIndexUnused = 0;
ProcessVTableEntriesForCallingConventionSignatureGeneration(context, VTableEntriesToProcess.AllOnTypesThatProducePartialVTables, ref currentVTableIndexUnused,
(int vtableIndex, bool isSealedVTableSlot, MethodDesc declMethod, MethodDesc implMethod) =>
{
if (implMethod.IsAbstract)
return;
if (UniversalGenericParameterLayout.VTableMethodRequiresCallingConventionConverter(implMethod))
{
if (conditionalDependencies == null)
conditionalDependencies = new List();
conditionalDependencies.Add(
new CombinedDependencyListEntry(context.NativeLayout.MethodSignatureVertex(declMethod.GetTypicalMethodDefinition().Signature),
context.VirtualMethodUse(declMethod),
"conditional vtable cctor sig"));
}
}
, _type, _type, _type);
}
if (conditionalDependencies != null)
return conditionalDependencies;
else
return Array.Empty();
}
private int CompareDictionaryEntries(KeyValuePair left, KeyValuePair right)
{
return left.Key - right.Key;
}
private bool HasInstantiationDeterminedSize()
{
Debug.Assert(_isUniversalCanon);
return _type.GetClosestDefType().InstanceFieldSize.IsIndeterminate;
}
public override Vertex WriteVertex(NodeFactory factory)
{
Debug.Assert(Marked, "WriteVertex should only happen for marked vertices");
VertexBag layoutInfo = new VertexBag();
DictionaryLayoutNode associatedLayout = factory.GenericDictionaryLayout(_type.ConvertToCanonForm(CanonicalFormKind.Specific).GetClosestDefType());
ICollection templateLayout = associatedLayout.GetTemplateEntries(factory);
NativeWriter writer = GetNativeWriter(factory);
// Interfaces
if (_type.RuntimeInterfaces.Length > 0)
{
List implementedInterfacesList = new List();
foreach (TypeDesc iface in _type.RuntimeInterfaces)
{
implementedInterfacesList.Add(factory.NativeLayout.TypeSignatureVertex(iface));
}
NativeLayoutVertexNode implementedInterfaces = factory.NativeLayout.PlacedVertexSequence(implementedInterfacesList);
layoutInfo.Append(BagElementKind.ImplementedInterfaces, implementedInterfaces.WriteVertex(factory));
}
if (!(_isUniversalCanon || (factory.LazyGenericsPolicy.UsesLazyGenerics(_type)) )&& (templateLayout.Count > 0))
{
List dictionaryVertices = new List();
foreach (NativeLayoutVertexNode dictionaryEntry in templateLayout)
{
dictionaryEntry.CheckIfMarkedEnoughToWrite();
dictionaryVertices.Add(dictionaryEntry);
}
NativeLayoutVertexNode dictionaryLayout = factory.NativeLayout.PlacedVertexSequence(dictionaryVertices);
layoutInfo.Append(BagElementKind.DictionaryLayout, dictionaryLayout.WriteVertex(factory));
}
Internal.NativeFormat.TypeFlags typeFlags = default(Internal.NativeFormat.TypeFlags);
if (factory.TypeSystemContext.HasLazyStaticConstructor(_type))
{
MethodDesc cctorMethod = _type.GetStaticConstructor();
MethodDesc canonCctorMethod = cctorMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
ISymbolNode cctorSymbol = factory.MethodEntrypoint(canonCctorMethod);
uint cctorStaticsIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(cctorSymbol);
layoutInfo.AppendUnsigned(BagElementKind.ClassConstructorPointer, cctorStaticsIndex);
typeFlags = typeFlags | Internal.NativeFormat.TypeFlags.HasClassConstructor;
}
if (!_isUniversalCanon)
{
DefType closestDefType = _type.GetClosestDefType();
if (closestDefType.NonGCStaticFieldSize.AsInt != 0)
{
layoutInfo.AppendUnsigned(BagElementKind.NonGcStaticDataSize, checked((uint)closestDefType.NonGCStaticFieldSize.AsInt));
}
if (closestDefType.GCStaticFieldSize.AsInt != 0)
{
layoutInfo.AppendUnsigned(BagElementKind.GcStaticDataSize, checked((uint)closestDefType.GCStaticFieldSize.AsInt));
BagElementKind staticDescBagType;
ISymbolNode staticsDescSymbol = GetStaticsNode(factory, out staticDescBagType);
uint gcStaticsSymbolIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(staticsDescSymbol);
layoutInfo.AppendUnsigned(staticDescBagType, gcStaticsSymbolIndex);
}
if (closestDefType.ThreadGcStaticFieldSize.AsInt != 0)
{
layoutInfo.AppendUnsigned(BagElementKind.ThreadStaticDataSize, checked((uint)closestDefType.ThreadGcStaticFieldSize.AsInt));
BagElementKind threadStaticDescBagType;
ISymbolNode threadStaticsDescSymbol = GetThreadStaticsNode(factory, out threadStaticDescBagType);
uint threadStaticsSymbolIndex = factory.MetadataManager.NativeLayoutInfo.StaticsReferences.GetIndex(threadStaticsDescSymbol);
layoutInfo.AppendUnsigned(threadStaticDescBagType, threadStaticsSymbolIndex);
}
}
else
{
Debug.Assert(_isUniversalCanon);
// Determine if type has instantiation determined size
if (!_type.IsInterface && HasInstantiationDeterminedSize())
{
typeFlags = typeFlags | Internal.NativeFormat.TypeFlags.HasInstantiationDeterminedSize;
}
}
if (_type.BaseType != null && _type.BaseType.IsRuntimeDeterminedSubtype)
{
layoutInfo.Append(BagElementKind.BaseType, factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(_type.BaseType)).WriteVertex(factory));
}
else if (_type.IsDelegate && _isUniversalCanon)
{
// For USG delegate, we need to write the signature of the Invoke method to the native layout.
// This signature is used by the calling convention converter to marshal parameters during delegate calls.
MethodDesc delegateInvokeMethod = _type.GetMethod("Invoke", null).GetTypicalMethodDefinition();
NativeLayoutMethodSignatureVertexNode invokeSignatureVertexNode = factory.NativeLayout.MethodSignatureVertex(delegateInvokeMethod.Signature);
layoutInfo.Append(BagElementKind.DelegateInvokeSignature, invokeSignatureVertexNode.WriteVertex(factory));
}
if (typeFlags != default(Internal.NativeFormat.TypeFlags))
layoutInfo.AppendUnsigned(BagElementKind.TypeFlags, (uint)typeFlags);
if (!_type.IsArrayTypeWithoutGenericInterfaces() && ConstructedEETypeNode.CreationAllowed(_type))
{
SealedVTableNode sealedVTable = factory.SealedVTable(_type.ConvertToCanonForm(CanonicalFormKind.Specific));
sealedVTable.BuildSealedVTableSlots(factory, relocsOnly: false /* This is the final emission phase */);
if (sealedVTable.NumSealedVTableEntries > 0)
layoutInfo.AppendUnsigned(BagElementKind.SealedVTableEntries, (uint)sealedVTable.NumSealedVTableEntries);
}
if (_type.GetTypeDefinition().HasVariance || factory.TypeSystemContext.IsGenericArrayInterfaceType(_type))
{
// Runtime casting logic relies on all interface types implemented on arrays
// to have the variant flag set (even if all the arguments are non-variant).
// This supports e.g. casting uint[] to ICollection
List varianceFlags = new List();
foreach (GenericParameterDesc param in _type.GetTypeDefinition().Instantiation)
{
varianceFlags.Add((uint)param.Variance);
}
layoutInfo.Append(BagElementKind.GenericVarianceInfo, factory.NativeLayout.PlacedUIntVertexSequence(varianceFlags).WriteVertex(factory));
}
else if (_type.GetTypeDefinition() == factory.ArrayOfTEnumeratorType)
{
// Generic array enumerators use special variance rules recognized by the runtime
List varianceFlag = new List();
varianceFlag.Add((uint)Internal.Runtime.GenericVariance.ArrayCovariant);
layoutInfo.Append(BagElementKind.GenericVarianceInfo, factory.NativeLayout.PlacedUIntVertexSequence(varianceFlag).WriteVertex(factory));
}
if (_isUniversalCanon)
{
// For universal canonical template types, we need to write out field layout information so that we
// can correctly compute the type sizes for dynamically created types at runtime, and construct
// their GCDesc info
VertexSequence fieldsSequence = null;
foreach (FieldDesc field in _type.GetFields())
{
// If this field does contribute to layout, skip
if (field.HasRva || field.IsLiteral)
continue;
// NOTE: The order and contents of the signature vertices emitted here is what we consider a field ordinal for the
// purpose of NativeLayoutFieldOffsetGenericDictionarySlotNode.
FieldStorage fieldStorage = FieldStorage.Instance;
if (field.IsStatic)
{
if (field.IsThreadStatic)
fieldStorage = FieldStorage.TLSStatic;
else if (field.HasGCStaticBase)
fieldStorage = FieldStorage.GCStatic;
else
fieldStorage = FieldStorage.NonGCStatic;
}
NativeLayoutVertexNode fieldTypeSignature;
if (field.FieldType.IsGCPointer)
{
fieldTypeSignature = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(field.Context.GetWellKnownType(WellKnownType.Object)));
}
else if (field.FieldType.IsPointer || field.FieldType.IsFunctionPointer)
{
fieldTypeSignature = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(field.Context.GetWellKnownType(WellKnownType.IntPtr)));
}
else
{
fieldTypeSignature = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.TypeSignatureVertex(field.FieldType));
}
Vertex staticFieldVertexData = writer.GetTuple(fieldTypeSignature.WriteVertex(factory), writer.GetUnsignedConstant((uint)fieldStorage));
if (fieldsSequence == null)
fieldsSequence = new VertexSequence();
fieldsSequence.Append(staticFieldVertexData);
}
if (fieldsSequence != null)
{
Vertex placedFieldsLayout = factory.MetadataManager.NativeLayoutInfo.SignaturesSection.Place(fieldsSequence);
layoutInfo.Append(BagElementKind.FieldLayout, placedFieldsLayout);
}
// We also need to write out the signatures of interesting methods in the type's vtable, which
// will be needed by the calling convention translation logic at runtime, when the type's methods
// get invoked.
int currentVTableIndexUnused = 0;
VertexSequence vtableSignaturesSequence = null;
ProcessVTableEntriesForCallingConventionSignatureGeneration(factory, VTableEntriesToProcess.AllInVTable, ref currentVTableIndexUnused,
(int vtableIndex, bool isSealedVTableSlot, MethodDesc declMethod, MethodDesc implMethod) =>
{
if (implMethod.IsAbstract)
return;
if (UniversalGenericParameterLayout.VTableMethodRequiresCallingConventionConverter(implMethod))
{
if (vtableSignaturesSequence == null)
vtableSignaturesSequence = new VertexSequence();
NativeLayoutVertexNode methodSignature = factory.NativeLayout.MethodSignatureVertex(declMethod.GetTypicalMethodDefinition().Signature);
Vertex signatureVertex = GetNativeWriter(factory).GetRelativeOffsetSignature(methodSignature.WriteVertex(factory));
Vertex vtableSignatureEntry = writer.GetTuple(
writer.GetUnsignedConstant((uint)((vtableIndex << 1) | (isSealedVTableSlot ? 1 : 0))),
factory.MetadataManager.NativeLayoutInfo.TemplatesSection.Place(signatureVertex));
vtableSignaturesSequence.Append(vtableSignatureEntry);
}
}
, _type, _type, _type);
if (vtableSignaturesSequence != null)
{
Vertex placedVtableSigs = factory.MetadataManager.NativeLayoutInfo.TemplatesSection.Place(vtableSignaturesSequence);
layoutInfo.Append(BagElementKind.VTableMethodSignatures, placedVtableSigs);
}
}
factory.MetadataManager.NativeLayoutInfo.TemplatesSection.Place(layoutInfo);
return SetSavedVertex(layoutInfo);
}
private enum VTableEntriesToProcess
{
AllInVTable,
AllOnTypesThatShouldProduceFullVTables,
AllOnTypesThatProducePartialVTables
}
private static IEnumerable EnumVirtualSlotsDeclaredOnType(TypeDesc declType)
{
// VirtualMethodUse of Foo.Method will bring in VirtualMethodUse
// of Foo<__Canon>.Method. This in turn should bring in Foo.Method.
DefType defType = declType.GetClosestDefType();
Debug.Assert(!declType.IsInterface);
IEnumerable allSlots = defType.EnumAllVirtualSlots();
foreach (var method in allSlots)
{
// Generic virtual methods are tracked by an orthogonal mechanism.
if (method.HasInstantiation)
continue;
// Current type doesn't define this slot. Another VTableSlice will take care of this.
if (method.OwningType != defType)
continue;
yield return method;
}
}
///
/// Process the vtable entries of a type by calling operation with the vtable index, declaring method, and implementing method
/// Process them in order from 0th entry to last.
/// Skip generic virtual methods, as they are not present in the vtable itself
/// Do not adjust vtable index for generic dictionary slot
/// The vtable index is only actually valid if whichEntries is set to VTableEntriesToProcess.AllInVTable
///
private void ProcessVTableEntriesForCallingConventionSignatureGeneration(NodeFactory factory, VTableEntriesToProcess whichEntries, ref int currentVTableIndex, Action operation, TypeDesc implType, TypeDesc declType, TypeDesc templateType)
{
if (implType.IsInterface)
return;
declType = declType.GetClosestDefType();
templateType = templateType.ConvertToCanonForm(CanonicalFormKind.Specific);
bool canShareNormalCanonicalCode = declType != declType.ConvertToCanonForm(CanonicalFormKind.Specific);
var baseType = declType.BaseType;
if (baseType != null)
{
Debug.Assert(templateType.BaseType != null);
ProcessVTableEntriesForCallingConventionSignatureGeneration(factory, whichEntries, ref currentVTableIndex, operation, implType, baseType, templateType.BaseType);
}
IEnumerable vtableEntriesToProcess;
if (ConstructedEETypeNode.CreationAllowed(declType))
{
switch (whichEntries)
{
case VTableEntriesToProcess.AllInVTable:
vtableEntriesToProcess = factory.VTable(declType).Slots;
break;
case VTableEntriesToProcess.AllOnTypesThatShouldProduceFullVTables:
if (factory.VTable(declType).HasFixedSlots)
{
vtableEntriesToProcess = factory.VTable(declType).Slots;
}
else
{
vtableEntriesToProcess = Array.Empty();
}
break;
case VTableEntriesToProcess.AllOnTypesThatProducePartialVTables:
if (factory.VTable(declType).HasFixedSlots)
{
vtableEntriesToProcess = Array.Empty();
}
else
{
vtableEntriesToProcess = EnumVirtualSlotsDeclaredOnType(declType);
}
break;
default:
throw new Exception();
}
}
else
{
// If allocating an object of the EEType isn't permitted, don't process any vtable entries.
vtableEntriesToProcess = Array.Empty();
}
// Dictionary slot
if (declType.HasGenericDictionarySlot() || templateType.HasGenericDictionarySlot())
currentVTableIndex++;
int sealedVTableSlot = 0;
DefType closestDefType = implType.GetClosestDefType();
// Actual vtable slots follow
foreach (MethodDesc declMethod in vtableEntriesToProcess)
{
// No generic virtual methods can appear in the vtable!
Debug.Assert(!declMethod.HasInstantiation);
MethodDesc implMethod = closestDefType.FindVirtualFunctionTargetMethodOnObjectType(declMethod);
if (implMethod.CanMethodBeInSealedVTable() && !implType.IsArrayTypeWithoutGenericInterfaces())
{
// Sealed vtable entries on other types in the hierarchy should not be reported (types read entries
// from their own sealed vtables, and not from the sealed vtables of base types).
if (implMethod.OwningType == closestDefType)
operation(sealedVTableSlot++, true, declMethod, implMethod);
}
else
{
operation(currentVTableIndex++, false, declMethod, implMethod);
}
}
}
}
public abstract class NativeLayoutGenericDictionarySlotNode : NativeLayoutVertexNode
{
public abstract override IEnumerable GetStaticDependencies(NodeFactory context);
protected abstract Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory);
protected abstract FixupSignatureKind SignatureKind { get; }
public override Vertex WriteVertex(NodeFactory factory)
{
CheckIfMarkedEnoughToWrite();
NativeWriter writer = GetNativeWriter(factory);
return writer.GetFixupSignature(SignatureKind, WriteSignatureVertex(writer, factory));
}
}
public abstract class NativeLayoutTypeSignatureBasedGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
NativeLayoutTypeSignatureVertexNode _signature;
TypeDesc _type;
public NativeLayoutTypeSignatureBasedGenericDictionarySlotNode(NodeFactory factory, TypeDesc type)
{
_signature = factory.NativeLayout.TypeSignatureVertex(type);
_type = type;
}
protected abstract string NodeTypeName { get; }
protected sealed override string GetName(NodeFactory factory) => NodeTypeName + factory.NameMangler.GetMangledTypeName(_type);
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(_signature, "TypeSignature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_type))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return _signature.WriteVertex(factory);
}
}
public sealed class NativeLayoutTypeHandleGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutTypeHandleGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutTypeHandleGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.TypeHandle;
}
public sealed class NativeLayoutUnwrapNullableGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutUnwrapNullableGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutUnwrapNullableGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.UnwrapNullableType;
}
public sealed class NativeLayoutTypeSizeGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutTypeSizeGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutTypeSizeGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.TypeSize;
}
public sealed class NativeLayoutAllocateObjectGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutAllocateObjectGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutAllocateObjectGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.AllocateObject;
}
public sealed class NativeLayoutCastClassGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutCastClassGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutAllocateCastClassDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.CastClass;
}
public sealed class NativeLayoutIsInstGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutIsInstGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutIsInstGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.IsInst;
}
public sealed class NativeLayoutTlsIndexGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutTlsIndexGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutTlsIndexGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.TlsIndex;
}
public sealed class NativeLayoutTlsOffsetGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutTlsOffsetGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutTlsOffsetGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.TlsOffset;
}
public sealed class NativeLayoutDefaultConstructorGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutDefaultConstructorGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string NodeTypeName => "NativeLayoutDefaultConstructorGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.DefaultConstructor;
}
public sealed class NativeLayoutAllocateArrayGenericDictionarySlotNode : NativeLayoutTypeSignatureBasedGenericDictionarySlotNode
{
public NativeLayoutAllocateArrayGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
Debug.Assert(type.IsArray); // TODO! Verify that the passed in type is the array type and not the element type of the array.
}
protected override string NodeTypeName => "NativeLayoutAllocateArrayGenericDictionarySlotNode_";
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.AllocateArray;
}
public abstract class NativeLayoutStaticsGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
NativeLayoutTypeSignatureVertexNode _signature;
TypeDesc _type;
public NativeLayoutStaticsGenericDictionarySlotNode(NodeFactory factory, TypeDesc type)
{
_signature = factory.NativeLayout.TypeSignatureVertex(type);
_type = type;
}
protected abstract StaticDataKind StaticDataKindFlag { get; }
protected abstract string NodeTypeName { get; }
protected sealed override string GetName(NodeFactory factory) => NodeTypeName + factory.NameMangler.GetMangledTypeName(_type);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.StaticData;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(_signature, "TypeSignature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_type))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return writer.GetStaticDataSignature(_signature.WriteVertex(factory), StaticDataKindFlag);
}
}
public sealed class NativeLayoutGcStaticsGenericDictionarySlotNode : NativeLayoutStaticsGenericDictionarySlotNode
{
public NativeLayoutGcStaticsGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{ }
protected override StaticDataKind StaticDataKindFlag => StaticDataKind.Gc;
protected override string NodeTypeName => "NativeLayoutGcStaticsGenericDictionarySlotNode_";
}
public sealed class NativeLayoutNonGcStaticsGenericDictionarySlotNode : NativeLayoutStaticsGenericDictionarySlotNode
{
public NativeLayoutNonGcStaticsGenericDictionarySlotNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{ }
protected override StaticDataKind StaticDataKindFlag => StaticDataKind.NonGc;
protected override string NodeTypeName => "NativeLayoutNonGcStaticsGenericDictionarySlotNode_";
}
public sealed class NativeLayoutInterfaceDispatchGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
NativeLayoutTypeSignatureVertexNode _signature;
MethodDesc _method;
public NativeLayoutInterfaceDispatchGenericDictionarySlotNode(NodeFactory factory, MethodDesc method)
{
_signature = factory.NativeLayout.TypeSignatureVertex(method.OwningType);
_method = method;
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutInterfaceDispatchGenericDictionarySlotNode_" + factory.NameMangler.GetMangledMethodName(_method);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.InterfaceCall;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(_signature, "TypeSignature");
MethodDesc method = _method;
if (method.IsRuntimeDeterminedExactMethod)
method = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
if (!factory.VTable(method.OwningType).HasFixedSlots)
{
yield return new DependencyListEntry(factory.VirtualMethodUse(method), "Slot number");
}
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(method.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
MethodDesc method = _method;
if (method.IsRuntimeDeterminedExactMethod)
method = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, method, method.OwningType);
return writer.GetMethodSlotSignature(_signature.WriteVertex(factory), checked((uint)slot));
}
}
public sealed class NativeLayoutMethodDictionaryGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
MethodDesc _method;
WrappedMethodDictionaryVertexNode _wrappedNode;
private class WrappedMethodDictionaryVertexNode : NativeLayoutMethodEntryVertexNode
{
public WrappedMethodDictionaryVertexNode(NodeFactory factory, MethodDesc method) :
base(factory, method, default(MethodEntryFlags))
{
}
protected override IMethodNode GetMethodEntrypointNode(NodeFactory factory, out bool unboxingStub)
{
throw new NotSupportedException();
}
protected sealed override string GetName(NodeFactory factory) => "WrappedMethodEntryVertexNodeForDictionarySlot_" + factory.NameMangler.GetMangledMethodName(_method);
}
public NativeLayoutMethodDictionaryGenericDictionarySlotNode(NodeFactory factory, MethodDesc method)
{
Debug.Assert(method.HasInstantiation);
_method = method;
_wrappedNode = new WrappedMethodDictionaryVertexNode(factory, method);
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutMethodDictionaryGenericDictionarySlotNode_" + factory.NameMangler.GetMangledMethodName(_method);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.MethodDictionary;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_method.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency for method OwningType");
}
foreach (var type in _method.Instantiation)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(type))
yield return new DependencyListEntry(dependency, "template construction dependency for method Instantiation types");
}
yield return new DependencyListEntry(_wrappedNode, "wrappednode");
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return _wrappedNode.WriteVertex(factory);
}
}
public sealed class NativeLayoutFieldOffsetGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
FieldDesc _field;
public NativeLayoutFieldOffsetGenericDictionarySlotNode(FieldDesc field)
{
_field = field;
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutFieldOffsetGenericDictionarySlotNode_" + factory.NameMangler.GetMangledFieldName(_field);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.FieldOffset;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(factory.NativeLayout.TypeSignatureVertex(_field.OwningType), "Field Containing Type Signature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_field.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
NativeWriter nativeWriter = GetNativeWriter(factory);
// NOTE: The order and contents of the field ordinal emitted here is based on the order of emission for fields
// in the USG template generation.
Vertex typeVertex = factory.NativeLayout.TypeSignatureVertex(_field.OwningType).WriteVertex(factory);
return nativeWriter.GetTuple(typeVertex, nativeWriter.GetUnsignedConstant(checked((uint)_field.GetFieldOrdinal())));
}
}
public sealed class NativeLayoutFieldLdTokenGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
FieldDesc _field;
public NativeLayoutFieldLdTokenGenericDictionarySlotNode(FieldDesc field)
{
_field = field;
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutFieldLdTokenGenericDictionarySlotNode_" + factory.NameMangler.GetMangledFieldName(_field);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.FieldLdToken;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(factory.NativeLayout.FieldLdTokenVertex(_field), "Field Signature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_field.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
Vertex ldToken = factory.NativeLayout.FieldLdTokenVertex(_field).WriteVertex(factory);
return GetNativeWriter(factory).GetRelativeOffsetSignature(ldToken);
}
}
public sealed class NativeLayoutVTableOffsetGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
MethodDesc _method;
MethodDesc _slotDefiningMethod;
public NativeLayoutVTableOffsetGenericDictionarySlotNode(MethodDesc method)
{
_method = method;
MethodDesc typicalSlotDefiningMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(method.GetTypicalMethodDefinition());
_slotDefiningMethod = _method.OwningType.FindMethodOnTypeWithMatchingTypicalMethod(typicalSlotDefiningMethod);
Debug.Assert(method.IsRuntimeDeterminedExactMethod);
Debug.Assert(!method.HasInstantiation);
Debug.Assert(!method.OwningType.IsInterface);
Debug.Assert(method.OwningType.IsDefType);
Debug.Assert(method.IsVirtual);
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutVTableOffsetGenericDictionarySlotNode_" + factory.NameMangler.GetMangledMethodName(_method);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.VTableOffset;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(factory.NativeLayout.TypeSignatureVertex(_slotDefiningMethod.OwningType), "Method VTableOffset Containing Type Signature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_slotDefiningMethod.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
NativeWriter nativeWriter = GetNativeWriter(factory);
int slot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, _slotDefiningMethod, _slotDefiningMethod.OwningType);
Vertex typeVertex = factory.NativeLayout.TypeSignatureVertex(_slotDefiningMethod.OwningType).WriteVertex(factory);
return nativeWriter.GetTuple(typeVertex, nativeWriter.GetUnsignedConstant((uint)slot));
}
}
public sealed class NativeLayoutMethodLdTokenGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
MethodDesc _method;
public NativeLayoutMethodLdTokenGenericDictionarySlotNode(MethodDesc method)
{
_method = method;
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutMethodLdTokenGenericDictionarySlotNode_" + factory.NameMangler.GetMangledMethodName(_method);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.MethodLdToken;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(factory.NativeLayout.MethodLdTokenVertex(_method), "Method Signature");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_method.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency for method OwningType");
}
foreach (var type in _method.Instantiation)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(type))
yield return new DependencyListEntry(dependency, "template construction dependency for method Instantiation types");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
Vertex ldToken = factory.NativeLayout.MethodLdTokenVertex(_method).WriteVertex(factory);
return GetNativeWriter(factory).GetRelativeOffsetSignature(ldToken);
}
}
public sealed class NativeLayoutCallingConventionConverterGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
Internal.TypeSystem.MethodSignature _signature;
CallingConventionConverterKind _converterKind;
public NativeLayoutCallingConventionConverterGenericDictionarySlotNode(Internal.TypeSystem.MethodSignature signature, CallingConventionConverterKind converterKind)
{
_signature = signature;
_converterKind = converterKind;
}
protected sealed override string GetName(NodeFactory factory) =>
"NativeLayoutCallingConventionConverterGenericDictionarySlotNode" + _converterKind.ToString() +
_signature.GetName();
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.CallingConventionConverter;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
yield return new DependencyListEntry(factory.NativeLayout.MethodSignatureVertex(_signature), "Method Signature");
for (int i = 0; i < _signature.Length; i++)
{
foreach (var dep in factory.NativeLayout.UniversalTemplateConstructableTypes(_signature[i]))
{
yield return new DependencyListEntry(dep, "template construction dependency");
}
}
foreach (var dep in factory.NativeLayout.UniversalTemplateConstructableTypes(_signature.ReturnType))
{
yield return new DependencyListEntry(dep, "template construction dependency");
}
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
Vertex signatureStream = factory.NativeLayout.MethodSignatureVertex(_signature).WriteVertex(factory);
return GetNativeWriter(factory).GetCallingConventionConverterSignature((uint)_converterKind, signatureStream);
}
}
public sealed class NativeLayoutConstrainedMethodDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
MethodDesc _constrainedMethod;
TypeDesc _constraintType;
bool _directCall;
public NativeLayoutConstrainedMethodDictionarySlotNode(MethodDesc constrainedMethod, TypeDesc constraintType, bool directCall)
{
_constrainedMethod = constrainedMethod;
_constraintType = constraintType;
_directCall = directCall;
Debug.Assert(_constrainedMethod.OwningType.IsInterface);
Debug.Assert(!_constrainedMethod.HasInstantiation || !directCall);
}
protected sealed override string GetName(NodeFactory factory) =>
"NativeLayoutConstrainedMethodDictionarySlotNode_"
+ (_directCall ? "Direct" : "")
+ factory.NameMangler.GetMangledMethodName(_constrainedMethod)
+ ","
+ factory.NameMangler.GetMangledTypeName(_constraintType);
protected sealed override FixupSignatureKind SignatureKind => _constrainedMethod.HasInstantiation ? FixupSignatureKind.GenericConstrainedMethod :
(_directCall ? FixupSignatureKind.NonGenericDirectConstrainedMethod : FixupSignatureKind.NonGenericConstrainedMethod);
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
DependencyNodeCore constrainedMethodDescriptorNode;
if (_constrainedMethod.HasInstantiation)
{
constrainedMethodDescriptorNode = factory.NativeLayout.MethodLdTokenVertex(_constrainedMethod);
}
else
{
constrainedMethodDescriptorNode = factory.NativeLayout.TypeSignatureVertex(_constrainedMethod.OwningType);
}
yield return new DependencyListEntry(factory.NativeLayout.TypeSignatureVertex(_constraintType), "ConstraintType");
yield return new DependencyListEntry(constrainedMethodDescriptorNode, "ConstrainedMethodType");
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_constrainedMethod.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency constrainedMethod OwningType");
}
foreach (var type in _constrainedMethod.Instantiation)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(type))
yield return new DependencyListEntry(dependency, "template construction dependency constrainedMethod Instantiation type");
}
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_constraintType))
yield return new DependencyListEntry(dependency, "template construction dependency constraintType");
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
Vertex constraintType = factory.NativeLayout.TypeSignatureVertex(_constraintType).WriteVertex(factory);
if (_constrainedMethod.HasInstantiation)
{
Debug.Assert(SignatureKind == FixupSignatureKind.GenericConstrainedMethod);
Vertex constrainedMethodVertex = factory.NativeLayout.MethodLdTokenVertex(_constrainedMethod).WriteVertex(factory);
Vertex relativeOffsetVertex = GetNativeWriter(factory).GetRelativeOffsetSignature(constrainedMethodVertex);
return writer.GetTuple(constraintType, relativeOffsetVertex);
}
else
{
Debug.Assert((SignatureKind == FixupSignatureKind.NonGenericConstrainedMethod) || (SignatureKind == FixupSignatureKind.NonGenericDirectConstrainedMethod));
Vertex methodType = factory.NativeLayout.TypeSignatureVertex(_constrainedMethod.OwningType).WriteVertex(factory);
var canonConstrainedMethod = _constrainedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
int interfaceSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, canonConstrainedMethod, canonConstrainedMethod.OwningType);
Vertex interfaceSlotVertex = writer.GetUnsignedConstant(checked((uint)interfaceSlot));
return writer.GetTuple(constraintType, methodType, interfaceSlotVertex);
}
}
}
public sealed class NativeLayoutMethodEntrypointGenericDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
MethodDesc _method;
WrappedMethodEntryVertexNode _wrappedNode;
private class WrappedMethodEntryVertexNode : NativeLayoutMethodEntryVertexNode
{
public bool _unboxingStub;
public IMethodNode _functionPointerNode;
public WrappedMethodEntryVertexNode(NodeFactory factory, MethodDesc method, bool unboxingStub, IMethodNode functionPointerNode) :
base(factory, method, functionPointerNode != null ? MethodEntryFlags.SaveEntryPoint : default(MethodEntryFlags))
{
_unboxingStub = unboxingStub;
_functionPointerNode = functionPointerNode;
}
protected override IMethodNode GetMethodEntrypointNode(NodeFactory factory, out bool unboxingStub)
{
unboxingStub = _unboxingStub;
return _functionPointerNode;
}
protected sealed override string GetName(NodeFactory factory) => "WrappedMethodEntryVertexNodeForDictionarySlot_" + (_unboxingStub ? "Unboxing_" : "") + factory.NameMangler.GetMangledMethodName(_method);
}
public NativeLayoutMethodEntrypointGenericDictionarySlotNode(NodeFactory factory, MethodDesc method, IMethodNode functionPointerNode, bool unboxingStub)
{
_method = method;
_wrappedNode = new WrappedMethodEntryVertexNode(factory, method, unboxingStub, functionPointerNode);
}
protected sealed override string GetName(NodeFactory factory) => "NativeLayoutMethodEntrypointGenericDictionarySlotNode_" + (_wrappedNode._unboxingStub ? "Unboxing_" : "") + factory.NameMangler.GetMangledMethodName(_method);
protected sealed override FixupSignatureKind SignatureKind => FixupSignatureKind.Method;
public sealed override IEnumerable GetStaticDependencies(NodeFactory factory)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_method.OwningType))
{
yield return new DependencyListEntry(dependency, "template construction dependency for method OwningType");
}
foreach (var type in _method.Instantiation)
{
foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(type))
yield return new DependencyListEntry(dependency, "template construction dependency for method Instantiation types");
}
yield return new DependencyListEntry(_wrappedNode, "wrappednode");
}
protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return _wrappedNode.WriteVertex(factory);
}
}
public sealed class NativeLayoutIntegerDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
int _value;
public NativeLayoutIntegerDictionarySlotNode(int value)
{
_value = value;
}
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.IntValue;
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return null;
}
protected override string GetName(NodeFactory context) => "NativeLayoutIntegerDictionarySlotNode_" + _value.ToStringInvariant();
protected override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return writer.GetUnsignedConstant((uint)_value);
}
public override void CheckIfMarkedEnoughToWrite()
{
// Do nothing, this node does not need marking
}
}
public sealed class NativeLayoutPointerToOtherSlotDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
int _otherSlotIndex;
public NativeLayoutPointerToOtherSlotDictionarySlotNode(int otherSlotIndex)
{
_otherSlotIndex = otherSlotIndex;
}
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.PointerToOtherSlot;
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return null;
}
protected override string GetName(NodeFactory context) => "NativeLayoutPointerToOtherSlotDictionarySlotNode_" + _otherSlotIndex.ToStringInvariant();
protected override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return writer.GetUnsignedConstant((uint)_otherSlotIndex);
}
public override void CheckIfMarkedEnoughToWrite()
{
// Do nothing, this node does not need marking
}
}
public sealed class NativeLayoutNotSupportedDictionarySlotNode : NativeLayoutGenericDictionarySlotNode
{
protected override FixupSignatureKind SignatureKind => FixupSignatureKind.NotYetSupported;
public override IEnumerable GetStaticDependencies(NodeFactory context)
{
return null;
}
protected override string GetName(NodeFactory context) => "NativeLayoutNotSupportedDictionarySlotNode";
protected override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
{
return writer.GetUnsignedConstant(0xDEADBEEF);
}
}
}