|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Internal.Text;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysisFramework;
namespace ILCompiler.DependencyAnalysis
{
public struct GenericLookupResultContext
{
private readonly TypeSystemEntity _canonicalOwner;
public readonly Instantiation TypeInstantiation;
public readonly Instantiation MethodInstantiation;
public TypeSystemEntity Context
{
get
{
if (_canonicalOwner is TypeDesc)
{
var owningTypeDefinition = (MetadataType)((TypeDesc)_canonicalOwner).GetTypeDefinition();
Debug.Assert(owningTypeDefinition.Instantiation.Length == TypeInstantiation.Length);
Debug.Assert(MethodInstantiation.IsNull || MethodInstantiation.Length == 0);
return owningTypeDefinition.MakeInstantiatedType(TypeInstantiation);
}
Debug.Assert(_canonicalOwner is MethodDesc);
MethodDesc owningMethodDefinition = ((MethodDesc)_canonicalOwner).GetTypicalMethodDefinition();
Debug.Assert(owningMethodDefinition.Instantiation.Length == MethodInstantiation.Length);
MethodDesc concreteMethod = owningMethodDefinition;
if (!TypeInstantiation.IsNull && TypeInstantiation.Length > 0)
{
TypeDesc owningType = owningMethodDefinition.OwningType;
Debug.Assert(owningType.Instantiation.Length == TypeInstantiation.Length);
concreteMethod = owningType.Context.GetMethodForInstantiatedType(owningMethodDefinition, ((MetadataType)owningType).MakeInstantiatedType(TypeInstantiation));
}
else
{
Debug.Assert(owningMethodDefinition.OwningType.Instantiation.IsNull
|| owningMethodDefinition.OwningType.Instantiation.Length == 0);
}
return concreteMethod.MakeInstantiatedMethod(MethodInstantiation);
}
}
public GenericLookupResultContext(TypeSystemEntity canonicalOwner, Instantiation typeInst, Instantiation methodInst)
{
_canonicalOwner = canonicalOwner;
TypeInstantiation = typeInst;
MethodInstantiation = methodInst;
}
}
/// <summary>
/// Represents the result of a generic lookup within a canonical method body.
/// The concrete artifact the generic lookup will result in can only be determined after substituting
/// runtime determined types with a concrete generic context. Use
/// <see cref="GetTarget(NodeFactory, Instantiation, Instantiation, GenericDictionaryNode)"/> to obtain the concrete
/// node the result points to.
/// </summary>
public abstract class GenericLookupResult
{
protected abstract int ClassCode { get; }
public abstract ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation);
public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb);
public abstract override string ToString();
protected abstract int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer);
protected abstract bool EqualsImpl(GenericLookupResult obj);
protected abstract int GetHashCodeImpl();
public sealed override bool Equals(object obj)
{
GenericLookupResult other = obj as GenericLookupResult;
if (other == null)
return false;
return ClassCode == other.ClassCode && EqualsImpl(other);
}
public sealed override int GetHashCode()
{
return ClassCode * 31 + GetHashCodeImpl();
}
private static bool InstantiationIsConcrete(Instantiation instantiation)
{
if (instantiation.IsNull || instantiation.Length == 0)
{
return true;
}
for (int i = 0; i < instantiation.Length; i++)
{
TypeDesc argument = instantiation[i];
if (argument.IsRuntimeDeterminedSubtype || argument.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return false;
}
}
return true;
}
public virtual void EmitDictionaryEntry(ref ObjectDataBuilder builder, NodeFactory factory, GenericLookupResultContext dictionary, GenericDictionaryNode dictionaryNode)
{
ISymbolNode target;
try
{
Debug.Assert(InstantiationIsConcrete(dictionary.TypeInstantiation));
Debug.Assert(InstantiationIsConcrete(dictionary.MethodInstantiation));
target = GetTarget(factory, dictionary, isConcreteInstantiation: true);
}
catch (TypeSystemException)
{
target = null;
}
if (target == null)
{
builder.EmitZeroPointer();
}
else
{
builder.EmitPointerReloc(target);
}
}
public abstract NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory);
// Call this api to get non-reloc dependencies that arise from use of a dictionary lookup
public virtual IEnumerable<DependencyNodeCore<NodeFactory>> NonRelocDependenciesFromUsage(NodeFactory factory)
{
return Array.Empty<DependencyNodeCore<NodeFactory>>();
}
public class Comparer : IComparer<GenericLookupResult>
{
private TypeSystemComparer _comparer;
public Comparer(TypeSystemComparer comparer)
{
_comparer = comparer;
}
public int Compare(GenericLookupResult x, GenericLookupResult y)
{
if (x == y)
{
return 0;
}
int codeX = x.ClassCode;
int codeY = y.ClassCode;
if (codeX == codeY)
{
Debug.Assert(x.GetType() == y.GetType());
int result = x.CompareToImpl(y, _comparer);
// We did a reference equality check above so an "Equal" result is not expected
Debug.Assert(result != 0);
return result;
}
else
{
Debug.Assert(x.GetType() != y.GetType());
return codeX > codeY ? -1 : 1;
}
}
}
}
/// <summary>
/// Generic lookup result that points to an MethodTable.
/// </summary>
public sealed class TypeHandleGenericLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => 1623839081;
public TypeHandleGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
// We are getting a maximally constructable type symbol because this might be something passed to newobj.
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedType);
return factory.MaximallyConstructableType(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("TypeHandle_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public TypeDesc Type => _type;
public override string ToString() => $"TypeHandle: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.TypeHandleDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((TypeHandleGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((TypeHandleGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to an MethodTable.
/// </summary>
public sealed class NecessaryTypeHandleGenericLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => -4882991;
public NecessaryTypeHandleGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedType);
return factory.NecessaryTypeSymbol(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("NecessaryTypeHandle_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public TypeDesc Type => _type;
public override string ToString() => $"NecessaryTypeHandle: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.TypeHandleDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((NecessaryTypeHandleGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((NecessaryTypeHandleGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to an MethodTable.
/// </summary>
public sealed class MetadataTypeHandleGenericLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => -4892308;
public MetadataTypeHandleGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedType);
return factory.MetadataTypeSymbol(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("MetadataTypeHandle_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public TypeDesc Type => _type;
public override string ToString() => $"MetadataTypeHandle: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.TypeHandleDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((MetadataTypeHandleGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((MetadataTypeHandleGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to an MethodTable where if the type is Nullable<X> the MethodTable is X
/// </summary>
public sealed class UnwrapNullableTypeHandleGenericLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => 53521918;
public UnwrapNullableTypeHandleGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
// Unwrap the nullable type if necessary
if (instantiatedType.IsNullable)
instantiatedType = instantiatedType.Instantiation[0];
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
// We are getting a constructed type symbol because this might be something passed to newobj.
return factory.ConstructedTypeSymbol(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("UnwrapNullable_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public TypeDesc Type => _type;
public override string ToString() => $"UnwrapNullable: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.UnwrapNullableTypeDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((UnwrapNullableTypeHandleGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((UnwrapNullableTypeHandleGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to a RuntimeMethodHandle.
/// </summary>
internal sealed class MethodHandleGenericLookupResult : GenericLookupResult
{
private MethodDesc _method;
protected override int ClassCode => 394272689;
public MethodHandleGenericLookupResult(MethodDesc method)
{
Debug.Assert(method.IsRuntimeDeterminedExactMethod, "Concrete method in a generic dictionary?");
_method = method;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (isConcreteInstantiation || !instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any))
{
return factory.RuntimeMethodHandle(instantiatedMethod);
}
else
{
Debug.Assert(instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
// The substituted method is still not concrete, but it may have concrete dependencies
// so we track it as a shadow node to ensure its dependencies are discovered.
if (!instantiatedMethod.IsAbstract)
{
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedMethod);
return factory.ShadowNonConcreteMethod(instantiatedMethod);
}
return null;
}
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("MethodHandle_"u8);
sb.Append(nameMangler.GetMangledMethodName(_method));
}
public override string ToString() => $"MethodHandle: {_method}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.MethodLdTokenDictionarySlot(_method);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_method, ((MethodHandleGenericLookupResult)other)._method);
}
protected override int GetHashCodeImpl()
{
return _method.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((MethodHandleGenericLookupResult)obj)._method == _method;
}
}
/// <summary>
/// Generic lookup result that points to a RuntimeFieldHandle.
/// </summary>
internal sealed class FieldHandleGenericLookupResult : GenericLookupResult
{
private FieldDesc _field;
protected override int ClassCode => -196995964;
public FieldHandleGenericLookupResult(FieldDesc field)
{
Debug.Assert(field.OwningType.IsRuntimeDeterminedSubtype, "Concrete field in a generic dictionary?");
_field = field;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
FieldDesc instantiatedField = _field.GetNonRuntimeDeterminedFieldFromRuntimeDeterminedFieldViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedField.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedField.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any));
return factory.RuntimeFieldHandle(instantiatedField);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("FieldHandle_"u8);
sb.Append(nameMangler.GetMangledFieldName(_field));
}
public override string ToString() => $"FieldHandle: {_field}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.FieldLdTokenDictionarySlot(_field);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_field, ((FieldHandleGenericLookupResult)other)._field);
}
protected override int GetHashCodeImpl()
{
return _field.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((FieldHandleGenericLookupResult)obj)._field == _field;
}
}
/// <summary>
/// Generic lookup result that points to a method dictionary.
/// </summary>
public sealed class MethodDictionaryGenericLookupResult : GenericLookupResult
{
private MethodDesc _method;
protected override int ClassCode => -467418176;
public MethodDictionaryGenericLookupResult(MethodDesc method)
{
Debug.Assert(method.IsRuntimeDeterminedExactMethod, "Concrete method in a generic dictionary?");
_method = method;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedMethod);
if (isConcreteInstantiation || !instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any))
{
return factory.MethodGenericDictionary(instantiatedMethod);
}
else
{
Debug.Assert(instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
if (!instantiatedMethod.IsAbstract)
{
return factory.ShadowNonConcreteMethod(instantiatedMethod);
}
return null;
}
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("MethodDictionary_"u8);
sb.Append(nameMangler.GetMangledMethodName(_method));
}
public MethodDesc Method => _method;
public override string ToString() => $"MethodDictionary: {_method}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.MethodDictionaryDictionarySlot(_method);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_method, ((MethodDictionaryGenericLookupResult)other)._method);
}
protected override int GetHashCodeImpl()
{
return _method.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((MethodDictionaryGenericLookupResult)obj)._method == _method;
}
}
/// <summary>
/// Generic lookup result that is a function pointer.
/// </summary>
internal sealed class MethodEntryGenericLookupResult : GenericLookupResult
{
private MethodDesc _method;
private bool _isUnboxingThunk;
protected override int ClassCode => 1572293098;
public MethodEntryGenericLookupResult(MethodDesc method, bool isUnboxingThunk)
{
Debug.Assert(method.IsRuntimeDeterminedExactMethod);
_method = method;
_isUnboxingThunk = isUnboxingThunk;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (isConcreteInstantiation || !instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any))
{
// TODO-SIZE: this is address taken only in the delegate target case
return factory.FatAddressTakenFunctionPointer(instantiatedMethod, _isUnboxingThunk);
}
else
{
Debug.Assert(instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
if (!instantiatedMethod.IsAbstract)
{
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedMethod);
return factory.ShadowNonConcreteMethod(instantiatedMethod);
}
return null;
}
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
if (!_isUnboxingThunk)
sb.Append("MethodEntry_"u8);
else
sb.Append("UnboxMethodEntry_"u8);
sb.Append(nameMangler.GetMangledMethodName(_method));
}
public override string ToString() => $"MethodEntry: {_method}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
MethodDesc canonMethod = _method.GetCanonMethodTarget(CanonicalFormKind.Specific);
// TODO-SIZE: this is address taken only in the delegate target case
return factory.NativeLayout.MethodEntrypointDictionarySlot(
_method,
_isUnboxingThunk,
factory.AddressTakenMethodEntrypoint(canonMethod, _isUnboxingThunk));
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
var otherEntry = (MethodEntryGenericLookupResult)other;
int result = (_isUnboxingThunk ? 1 : 0) - (otherEntry._isUnboxingThunk ? 1 : 0);
if (result != 0)
return result;
return comparer.Compare(_method, otherEntry._method);
}
protected override int GetHashCodeImpl()
{
return _method.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((MethodEntryGenericLookupResult)obj)._method == _method &&
((MethodEntryGenericLookupResult)obj)._isUnboxingThunk == _isUnboxingThunk;
}
}
/// <summary>
/// Generic lookup result that points to a dispatch cell.
/// </summary>
internal sealed class VirtualDispatchCellGenericLookupResult : GenericLookupResult
{
private MethodDesc _method;
protected override int ClassCode => 643566930;
public VirtualDispatchCellGenericLookupResult(MethodDesc method)
{
Debug.Assert(method.IsRuntimeDeterminedExactMethod);
Debug.Assert(method.IsVirtual);
Debug.Assert(method.OwningType.IsInterface);
_method = method;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext context, bool isConcreteInstantiation)
{
MethodDesc instantiatedMethod = _method.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(context.TypeInstantiation, context.MethodInstantiation);
if (isConcreteInstantiation || !instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any))
{
TypeSystemEntity contextOwner = context.Context;
GenericDictionaryNode dictionary;
if (isConcreteInstantiation)
{
dictionary = contextOwner is TypeDesc ?
(GenericDictionaryNode)factory.TypeGenericDictionary((TypeDesc)contextOwner) :
(GenericDictionaryNode)factory.MethodGenericDictionary((MethodDesc)contextOwner);
}
else
{
dictionary = null;
}
return factory.InterfaceDispatchCell(instantiatedMethod, dictionary);
}
else
{
Debug.Assert(instantiatedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
if (!instantiatedMethod.IsAbstract)
{
factory.TypeSystemContext.DetectGenericCycles(context.Context, instantiatedMethod);
return factory.ShadowNonConcreteMethod(instantiatedMethod);
}
return null;
}
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("DispatchCell_"u8);
sb.Append(nameMangler.GetMangledMethodName(_method));
}
public override string ToString() => $"DispatchCell: {_method}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.InterfaceCellDictionarySlot(_method);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_method, ((VirtualDispatchCellGenericLookupResult)other)._method);
}
protected override int GetHashCodeImpl()
{
return _method.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((VirtualDispatchCellGenericLookupResult)obj)._method == _method;
}
}
/// <summary>
/// Generic lookup result that points to the non-GC static base of a type.
/// </summary>
internal sealed class TypeNonGCStaticBaseGenericLookupResult : GenericLookupResult
{
private MetadataType _type;
protected override int ClassCode => -328863267;
public TypeNonGCStaticBaseGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete static base in a generic dictionary?");
Debug.Assert(type is MetadataType);
_type = (MetadataType)type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
var instantiatedType = (MetadataType)_type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
return factory.TypeNonGCStaticsSymbol(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("NonGCStaticBase_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public override string ToString() => $"NonGCStaticBase: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.NonGcStaticDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((TypeNonGCStaticBaseGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((TypeNonGCStaticBaseGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to the threadstatic base index of a type.
/// </summary>
internal sealed class TypeThreadStaticBaseIndexGenericLookupResult : GenericLookupResult
{
private MetadataType _type;
protected override int ClassCode => -177446371;
public TypeThreadStaticBaseIndexGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete static base in a generic dictionary?");
Debug.Assert(type is MetadataType);
_type = (MetadataType)type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
var instantiatedType = (MetadataType)_type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
return factory.TypeThreadStaticIndex(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("ThreadStaticBase_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public override string ToString() => $"ThreadStaticBase: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.ThreadStaticBaseIndexDictionarySlotNode(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((TypeThreadStaticBaseIndexGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((TypeThreadStaticBaseIndexGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to the GC static base of a type.
/// </summary>
public sealed class TypeGCStaticBaseGenericLookupResult : GenericLookupResult
{
private MetadataType _type;
protected override int ClassCode => 429225829;
public TypeGCStaticBaseGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete static base in a generic dictionary?");
Debug.Assert(type is MetadataType);
_type = (MetadataType)type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
var instantiatedType = (MetadataType)_type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
return factory.TypeGCStaticsSymbol(instantiatedType);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("GCStaticBase_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public MetadataType Type => _type;
public override string ToString() => $"GCStaticBase: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.GcStaticDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((TypeGCStaticBaseGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((TypeGCStaticBaseGenericLookupResult)obj)._type == _type;
}
}
/// <summary>
/// Generic lookup result that points to an object allocator.
/// </summary>
internal sealed class ObjectAllocatorGenericLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => -1671431655;
public ObjectAllocatorGenericLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
return factory.ExternFunctionSymbol(new Utf8String(JitHelper.GetNewObjectHelperForType(instantiatedType)));
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("AllocObject_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public override string ToString() => $"AllocObject: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.AllocateObjectDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((ObjectAllocatorGenericLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((ObjectAllocatorGenericLookupResult)obj)._type == _type;
}
}
internal sealed class DefaultConstructorLookupResult : GenericLookupResult
{
private TypeDesc _type;
protected override int ClassCode => -1391112482;
public DefaultConstructorLookupResult(TypeDesc type)
{
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
_type = type;
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation && instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any))
{
return null;
}
Debug.Assert(!instantiatedType.IsCanonicalSubtype(CanonicalFormKind.Any));
MethodDesc defaultCtor = Compilation.GetConstructorForCreateInstanceIntrinsic(instantiatedType);
return instantiatedType.IsValueType ? factory.ExactCallableAddress(defaultCtor) : factory.CanonicalEntrypoint(defaultCtor);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("DefaultCtor_"u8);
sb.Append(nameMangler.GetMangledTypeName(_type));
}
public override string ToString() => $"DefaultConstructor: {_type}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.DefaultConstructorDictionarySlot(_type);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
return comparer.Compare(_type, ((DefaultConstructorLookupResult)other)._type);
}
protected override int GetHashCodeImpl()
{
return _type.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
return ((DefaultConstructorLookupResult)obj)._type == _type;
}
}
internal sealed class ConstrainedMethodUseLookupResult : GenericLookupResult
{
private MethodDesc _constrainedMethod;
private TypeDesc _constraintType;
private bool _directCall;
protected override int ClassCode => -1525377658;
public ConstrainedMethodUseLookupResult(MethodDesc constrainedMethod, TypeDesc constraintType, bool directCall)
{
_constrainedMethod = constrainedMethod;
_constraintType = constraintType;
_directCall = directCall;
Debug.Assert(_constraintType.IsRuntimeDeterminedSubtype || _constrainedMethod.IsRuntimeDeterminedExactMethod, "Concrete type in a generic dictionary?");
Debug.Assert(!_constrainedMethod.HasInstantiation || !_directCall, "Direct call to constrained generic method isn't supported");
}
public override IEnumerable<DependencyNodeCore<NodeFactory>> NonRelocDependenciesFromUsage(NodeFactory factory)
{
MethodDesc canonMethod = _constrainedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
// If we're producing a full vtable for the type, we don't need to report virtual method use.
// We also don't report virtual method use for generic virtual methods - tracking those is orthogonal.
if (!canonMethod.HasInstantiation && !factory.VTable(canonMethod.OwningType).HasKnownVirtualMethodUse)
{
// Report the method as virtually used so that types that could be used here at runtime
// have the appropriate implementations generated.
// This covers instantiations created at runtime (MakeGeneric*). The statically present generic dictionaries
// are already covered by the dependency analysis within the compiler because we call GetTarget for those.
yield return factory.VirtualMethodUse(canonMethod);
}
}
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary, bool isConcreteInstantiation)
{
MethodDesc instantiatedConstrainedMethod = _constrainedMethod.GetNonRuntimeDeterminedMethodFromRuntimeDeterminedMethodViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
TypeDesc instantiatedConstraintType = _constraintType.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
if (!isConcreteInstantiation &&
(instantiatedConstrainedMethod.IsCanonicalMethod(CanonicalFormKind.Any) ||
instantiatedConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any)))
{
return null;
}
Debug.Assert(!instantiatedConstrainedMethod.IsCanonicalMethod(CanonicalFormKind.Any));
Debug.Assert(!instantiatedConstraintType.IsCanonicalSubtype(CanonicalFormKind.Any));
MethodDesc implMethod;
MethodDesc instantiatedConstrainedMethodDefinition = instantiatedConstrainedMethod.GetMethodDefinition();
if (instantiatedConstrainedMethod.OwningType.IsInterface)
{
if (instantiatedConstrainedMethod.Signature.IsStatic)
{
implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToStaticVirtualMethodOnType(instantiatedConstrainedMethodDefinition);
}
else
{
implMethod = instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToVirtualMethodOnType(instantiatedConstrainedMethodDefinition);
}
if (implMethod == null)
{
DefaultInterfaceMethodResolution resolution =
instantiatedConstraintType.GetClosestDefType().ResolveVariantInterfaceMethodToDefaultImplementationOnType(instantiatedConstrainedMethodDefinition, out implMethod);
if (resolution != DefaultInterfaceMethodResolution.DefaultImplementation)
{
// TODO: diamond/reabstraction: https://github.com/dotnet/runtime/issues/72589
ThrowHelper.ThrowInvalidProgramException();
}
}
}
else
{
implMethod = instantiatedConstraintType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(instantiatedConstrainedMethodDefinition);
}
if (instantiatedConstrainedMethod != instantiatedConstrainedMethodDefinition)
{
implMethod = implMethod.MakeInstantiatedMethod(instantiatedConstrainedMethod.Instantiation);
}
// AOT use of this generic lookup is restricted to finding methods on valuetypes (runtime usage of this slot in universal generics is more flexible)
Debug.Assert(instantiatedConstraintType.IsValueType || (instantiatedConstrainedMethod.OwningType.IsInterface && instantiatedConstrainedMethod.Signature.IsStatic));
factory.MetadataManager.NoteOverridingMethod(_constrainedMethod, implMethod);
// TODO-SIZE: this is address taken only in the delegate target case
if (implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).IsSharedByGenericInstantiations)
return factory.ExactCallableAddressTakenAddress(implMethod);
else
return factory.AddressTakenMethodEntrypoint(implMethod);
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("ConstrainedMethodUseLookupResult_"u8);
sb.Append(nameMangler.GetMangledTypeName(_constraintType));
sb.Append(nameMangler.GetMangledMethodName(_constrainedMethod));
if (_directCall)
sb.Append("Direct"u8);
}
public override string ToString() => $"ConstrainedMethodUseLookupResult: {_constraintType} {_constrainedMethod} {_directCall}";
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
{
return factory.NativeLayout.ConstrainedMethodUse(_constrainedMethod, _constraintType, _directCall);
}
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
{
var otherResult = (ConstrainedMethodUseLookupResult)other;
int result = (_directCall ? 1 : 0) - (otherResult._directCall ? 1 : 0);
if (result != 0)
return result;
result = comparer.Compare(_constraintType, otherResult._constraintType);
if (result != 0)
return result;
return comparer.Compare(_constrainedMethod, otherResult._constrainedMethod);
}
protected override int GetHashCodeImpl()
{
return _constrainedMethod.GetHashCode() * 13 + _constraintType.GetHashCode();
}
protected override bool EqualsImpl(GenericLookupResult obj)
{
var other = (ConstrainedMethodUseLookupResult)obj;
return _constrainedMethod == other._constrainedMethod &&
_constraintType == other._constraintType &&
_directCall == other._directCall;
}
}
}
|