123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- using System.Diagnostics;
- using Mono.Cecil;
- using Mono.Cecil.Rocks;
-
- namespace Burst.Compiler.IL.Syntax
- {
- /// <summary>
- /// A generic context contains a mapping between GenericParameter ({T}) and resolved TypeReference (int, float, MyStruct<float>)
- /// </summary>
- #if BURST_INTERNAL || BURST_COMPILER_SHARED
- public
- #else
- internal
- #endif
- readonly struct GenericContext
- {
- private readonly GenericInstanceType _typeContext;
- private readonly GenericInstanceMethod _methodContext;
-
- /// <summary>
- /// An empty <see cref="GenericContext"/>
- /// </summary>
- public static readonly GenericContext None = new GenericContext();
-
- /// <summary>
- /// Initializes a new instance of the <see cref="GenericContext"/> class.
- /// </summary>
- /// <param name="genericMethod">The generic method instance.</param>
- private GenericContext(GenericInstanceMethod genericMethod, GenericInstanceType genericType)
- {
- _methodContext = genericMethod;
- _typeContext = genericType;
- }
-
- /// <summary>
- /// Is there no generics in this context?
- /// </summary>
- /// <returns></returns>
- public bool IsEmpty()
- {
- return _typeContext == null && _methodContext == null;
- }
-
- /// <summary>
- /// Resolve the generics of the given <see cref="T:Mono.Cecil.MethodReference"/>
- /// </summary>
- /// <param name="unresolvedMethod"></param>
- /// <returns></returns>
- public MethodReference Resolve(MethodReference unresolvedMethod)
- {
- Debug.Assert(unresolvedMethod != null);
-
- // The following code was originally derived from IL2CPP.
- var resolvedMethod = unresolvedMethod;
-
- if (IsEmpty())
- {
- return resolvedMethod;
- }
-
- var declaringType = Resolve(unresolvedMethod.DeclaringType);
-
- if (unresolvedMethod is GenericInstanceMethod genericInstanceMethod)
- {
- resolvedMethod = new MethodReference(unresolvedMethod.Name, unresolvedMethod.ReturnType, declaringType);
-
- foreach (var p in unresolvedMethod.Parameters)
- {
- resolvedMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, p.ParameterType));
- }
-
- foreach (var gp in genericInstanceMethod.ElementMethod.GenericParameters)
- {
- resolvedMethod.GenericParameters.Add(new GenericParameter(gp.Name, resolvedMethod));
- }
-
- resolvedMethod.HasThis = unresolvedMethod.HasThis;
-
- var m = new GenericInstanceMethod(resolvedMethod);
-
- foreach (var ga in genericInstanceMethod.GenericArguments)
- {
- m.GenericArguments.Add(Resolve(ga));
- }
-
- resolvedMethod = m;
- }
- else
- {
- if (unresolvedMethod.HasGenericParameters)
- {
- var newGenericInstanceMethod = new GenericInstanceMethod(unresolvedMethod);
-
- foreach (var gp in unresolvedMethod.GenericParameters)
- {
- newGenericInstanceMethod.GenericArguments.Add(Resolve(gp));
- }
-
- resolvedMethod = newGenericInstanceMethod;
- }
- else
- {
- resolvedMethod = new MethodReference(unresolvedMethod.Name, unresolvedMethod.ReturnType, declaringType);
-
- foreach (var p in unresolvedMethod.Parameters)
- {
- resolvedMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, p.ParameterType));
- }
-
- resolvedMethod.HasThis = unresolvedMethod.HasThis;
- resolvedMethod.MetadataToken = unresolvedMethod.MetadataToken;
- }
- }
-
- return resolvedMethod;
- }
-
- /// <summary>
- /// Expands the specified <see cref="T:Mono.Cecil.TypeReference"/> if it is either a <see cref="T:Mono.Cecil.GenericParameter"/> or a partially expanded <see cref="T:Mono.Cecil.GenericInstanceType"/>
- /// </summary>
- /// <param name="typeReference">The type reference.</param>
- /// <returns>TypeReference.</returns>
- public TypeReference Resolve(TypeReference typeReference)
- {
- Debug.Assert(typeReference != null);
-
- if (IsEmpty())
- {
- return typeReference;
- }
-
- switch (typeReference)
- {
- case GenericParameter genericParam:
- Debug.Assert(genericParam.Owner != null);
-
- if (genericParam.Owner.GenericParameterType == GenericParameterType.Type)
- {
- Debug.Assert(_typeContext != null);
- return _typeContext.GenericArguments[genericParam.Position];
- }
- else
- {
- Debug.Assert(_methodContext != null);
- return _methodContext.GenericArguments[genericParam.Position];
- }
- case ArrayType arrayType:
- return new ArrayType(Resolve(arrayType.ElementType), arrayType.Rank);
- case PointerType pointerType:
- return Resolve(pointerType.ElementType).MakePointerType();
- case PinnedType pinnedType:
- return Resolve(pinnedType.ElementType).MakePointerType();
- case ByReferenceType byRefType:
- return Resolve(byRefType.ElementType).MakeByReferenceType();
- case RequiredModifierType requiredModType:
- return new RequiredModifierType(requiredModType.ModifierType, Resolve(requiredModType.ElementType));
- case OptionalModifierType optionalModType:
- return Resolve(optionalModType.ElementType);
- }
-
- if (ContainsGenericParameters(typeReference))
- {
- if (typeReference is GenericInstanceType partialGenericInstance)
- {
- // TODO: Ideally, we should cache this GenericInstanceType once it has been resolved
- var genericInstance = new GenericInstanceType(partialGenericInstance.ElementType);
- foreach (var genericArgument in partialGenericInstance.GenericArguments)
- {
- genericInstance.GenericArguments.Add(Resolve(genericArgument));
- }
- return genericInstance;
- }
- else
- {
- // Sometimes we can have a TypeDefinition with HasGenericParameters false, but GenericParameters.Count > 0
- var typeDefinition = typeReference as TypeDefinition;
- if (typeDefinition?.GenericParameters.Count > 0)
- {
- var genericInstance = new GenericInstanceType(typeDefinition);
- foreach (var genericArgument in typeDefinition.GenericParameters)
- {
- genericInstance.GenericArguments.Add(Resolve(genericArgument));
- }
- return genericInstance;
- }
- }
- }
-
- return typeReference;
- }
-
- /// <summary>
- /// If the given type is a reference or pointer type, the underlying type is returned
- /// </summary>
- /// <param name="typeReference"></param>
- /// <returns></returns>
- public static TypeReference GetTypeReferenceForPointerOrReference(TypeReference typeReference)
- {
- while (true)
- {
- switch (typeReference)
- {
- case PointerType pointerType:
- typeReference = pointerType.ElementType;
- break;
- case ByReferenceType byRefType:
- typeReference = byRefType.ElementType;
- break;
- default:
- return typeReference;
- }
- }
- }
-
- /// <summary>
- /// Create <see cref="GenericContext"/> from a <see cref="T:Mono.Cecil.TypeReference"/>
- /// </summary>
- /// <param name="typeReference"></param>
- /// <returns></returns>
- public static GenericContext From(TypeReference typeReference)
- {
- Debug.Assert(typeReference != null);
-
- if (typeReference is PinnedType pinnedType)
- {
- typeReference = pinnedType.ElementType;
- }
-
- typeReference = GetTypeReferenceForPointerOrReference(typeReference);
-
- if (typeReference is ArrayType arrayType)
- {
- typeReference = arrayType.ElementType;
- }
-
- return new GenericContext(null, typeReference as GenericInstanceType);
- }
-
- /// <summary>
- /// Create <see cref="GenericContext"/> from a <see cref="T:Mono.Cecil.MethodReference"/> and a <see cref="T:Mono.Cecil.TypeReference"/>
- /// </summary>
- /// <param name="methodReference"></param>
- /// <param name="typeReference"></param>
- /// <returns></returns>
- public static GenericContext From(MethodReference methodReference, TypeReference typeReference)
- {
- Debug.Assert(methodReference != null);
- Debug.Assert(typeReference != null);
-
- typeReference = GetTypeReferenceForPointerOrReference(typeReference);
-
- return new GenericContext(methodReference as GenericInstanceMethod, typeReference as GenericInstanceType);
- }
-
- /// <summary>
- /// Checks if the specified TypeReference contains generic parameters that need type expansion
- /// </summary>
- /// <param name="typeReference">The type reference.</param>
- /// <returns><c>true</c> if the specified TypeReference contains generic arguments that need type expansion, <c>false</c> otherwise.</returns>
- public static bool ContainsGenericParameters(TypeReference typeReference)
- {
- switch (typeReference)
- {
- case GenericParameter genericParam:
- return true;
- case ArrayType arrayType:
- return ContainsGenericParameters(arrayType.ElementType);
- case PointerType pointerType:
- return ContainsGenericParameters(pointerType.ElementType);
- case PinnedType pinnedType:
- return ContainsGenericParameters(pinnedType.ElementType);
- case ByReferenceType byRefType:
- return ContainsGenericParameters(byRefType.ElementType);
- case RequiredModifierType requiredModType:
- return ContainsGenericParameters(requiredModType.ModifierType);
- case OptionalModifierType optionalModType:
- return ContainsGenericParameters(optionalModType.ElementType);
- case GenericInstanceType partialGenericInstance:
- {
- foreach (var genericArgument in partialGenericInstance.GenericArguments)
- {
- if (ContainsGenericParameters(genericArgument))
- {
- return true;
- }
- }
-
- break;
- }
-
- case TypeDefinition typeDefinition:
- {
- // Sometimes we can have a TypeDefinition with HasGenericParameters false, but GenericParameters.Count > 0
- return typeDefinition.GenericParameters.Count > 0;
- }
- }
-
- return false;
- }
- }
- }
|