public static EmbeddedSignatureData[] EncodeAsEmbeddedSignatureData(this UnmanagedCallingConventions callingConventions, TypeSystemContext context)
        {
            UnmanagedCallingConventions convention = (callingConventions & UnmanagedCallingConventions.CallingConventionMask);
            UnmanagedCallingConventions modifiers  = (callingConventions & UnmanagedCallingConventions.ModifiersMask);

            UnmanagedCallingConventions platformDefault = GetPlatformDefaultUnmanagedCallingConvention(context);

            int count = ((convention != platformDefault) ? 1 : 0) + BitOperations.PopCount((uint)modifiers);

            if (count == 0)
            {
                return(null);
            }

            EmbeddedSignatureData[] ret = new EmbeddedSignatureData[count];

            int index = 0;

            if (convention != platformDefault)
            {
                ret[index++] = CreateCallConvEmbeddedSignatureData(context, convention switch
                {
                    UnmanagedCallingConventions.Cdecl => "CallConvCdecl",
                    UnmanagedCallingConventions.Stdcall => "CallConvStdcall",
                    UnmanagedCallingConventions.Fastcall => "CallConvFastcall",
                    UnmanagedCallingConventions.Thiscall => "CallConvThiscall",
                    _ => throw new InvalidProgramException()
                });
        private static UnmanagedCallingConventions AccumulateCallingConventions(UnmanagedCallingConventions existing, MetadataType newConvention)
        {
            if (newConvention.Namespace != "System.Runtime.CompilerServices")
            {
                return(existing);
            }

            UnmanagedCallingConventions?addedCallConv = newConvention.Name switch
            {
                "CallConvCdecl" => UnmanagedCallingConventions.Cdecl,
                "CallConvStdcall" => UnmanagedCallingConventions.Stdcall,
                "CallConvFastcall" => UnmanagedCallingConventions.Fastcall,
                "CallConvThiscall" => UnmanagedCallingConventions.Thiscall,
                "CallConvSuppressGCTransition" => UnmanagedCallingConventions.IsSuppressGcTransition,
                "CallConvMemberFunction" => UnmanagedCallingConventions.IsMemberFunction,
                _ => null
            };

            if (addedCallConv == null)
            {
                return(existing);
            }

            // Do not allow accumulating additional calling conventions - only modifiers are allowed
            if ((addedCallConv.Value & UnmanagedCallingConventions.CallingConventionMask) != 0 && (existing & UnmanagedCallingConventions.CallingConventionMask) != 0)
            {
                ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramMultipleCallConv);
            }

            return(existing | addedCallConv.Value);
        }
        private static UnmanagedCallingConventions GetUnmanagedCallingConventionFromAttribute(CustomAttributeValue <TypeDesc> attributeWithCallConvsArray, TypeSystemContext context)
        {
            ImmutableArray <CustomAttributeTypedArgument <TypeDesc> > callConvArray = default;

            foreach (var arg in attributeWithCallConvsArray.NamedArguments)
            {
                if (arg.Name == "CallConvs")
                {
                    callConvArray = (ImmutableArray <CustomAttributeTypedArgument <TypeDesc> >)arg.Value;
                }
            }

            UnmanagedCallingConventions result = 0;

            if (!callConvArray.IsDefault)
            {
                foreach (CustomAttributeTypedArgument <TypeDesc> type in callConvArray)
                {
                    if (type.Value is not MetadataType mdType)
                    {
                        continue;
                    }

                    result = AccumulateCallingConventions(result, mdType);
                }
            }

            // If we haven't found a calling convention in the attribute, the calling convention is 'unmanaged'.
            if ((result & UnmanagedCallingConventions.CallingConventionMask) == 0)
            {
                result |= GetPlatformDefaultUnmanagedCallingConvention(context);
            }

            return(result);
        }
        /// <summary>
        /// Gets calling conventions for a standalone ('calli') method signature.
        /// </summary>
        public static UnmanagedCallingConventions GetStandaloneMethodSignatureCallingConventions(this MethodSignature signature)
        {
            // If calling convention is anything but 'unmanaged', or there's no modifiers, we can bitcast to our enum and we're done.
            MethodSignatureFlags unmanagedCallconv = signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask;

            if (unmanagedCallconv != MethodSignatureFlags.UnmanagedCallingConvention)
            {
                Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConventionCdecl == (int)UnmanagedCallingConventions.Cdecl &&
                             (int)MethodSignatureFlags.UnmanagedCallingConventionStdCall == (int)UnmanagedCallingConventions.Stdcall &&
                             (int)MethodSignatureFlags.UnmanagedCallingConventionThisCall == (int)UnmanagedCallingConventions.Thiscall);
                Debug.Assert(unmanagedCallconv != 0);
                return((UnmanagedCallingConventions)unmanagedCallconv);
            }

            // If calling convention is 'unmanaged', there might be more metadata in the custom modifiers.
            UnmanagedCallingConventions result = 0;

            if (signature.HasEmbeddedSignatureData)
            {
                foreach (EmbeddedSignatureData data in signature.GetEmbeddedSignatureData())
                {
                    if (data.kind != EmbeddedSignatureDataKind.OptionalCustomModifier)
                    {
                        continue;
                    }

                    // We only care about the modifiers for the return type. These will be at the start of
                    // the signature, so will be first in the array of embedded signature data.
                    if (data.index != MethodSignature.IndexOfCustomModifiersOnReturnType)
                    {
                        break;
                    }

                    if (data.type is not MetadataType mdType)
                    {
                        continue;
                    }

                    result = AccumulateCallingConventions(result, mdType);
                }
            }

            // If we haven't found a calling convention in the modifiers, the calling convention is 'unmanaged'.
            if ((result & UnmanagedCallingConventions.CallingConventionMask) == 0)
            {
                result |= GetPlatformDefaultUnmanagedCallingConvention(signature.Context);
            }

            return(result);
        }
    /// <summary>
    /// Creates a new <see cref="CILMethodSignature"/> which has all its information specified from the parameters of this method.
    /// </summary>
    /// <param name="ctx">The current <see cref="CILReflectionContext"/>.</param>
    /// <param name="currentModule">The current <see cref="CILModule"/>.</param>
    /// <param name="callingConventions">The <see cref="UnmanagedCallingConventions"/> for the method signature.</param>
    /// <param name="returnType">The return type for the method signature.</param>
    /// <param name="returnParamMods">The <see cref="CILCustomModifier"/>s for the method signature. May be <c>null</c> if no modifiers should be used.</param>
    /// <param name="parameters">The parameter information for the method signature. Each element is a tuple containing <see cref="CILCustomModifier"/>s and type for the parameter. Custom modifiers array may be <c>null</c> if no modifiers should be used.</param>
    /// <returns>A new <see cref="CILMethodSignature"/>.</returns>
    /// <exception cref="NullReferenceException">If <paramref name="ctx"/> is <c>null</c>.</exception>
    /// <exception cref="ArgumentNullException">If <paramref name="currentModule"/>, <paramref name="returnType"/> or any of the types within <paramref name="parameters"/> is <c>null</c>.</exception>
    /// <seealso cref="CILMethodSignature"/>
    public static CILMethodSignature NewMethodSignature(this CILReflectionContext ctx, CILModule currentModule, UnmanagedCallingConventions callingConventions, CILTypeBase returnType, CILCustomModifier[] returnParamMods, params Tuple <CILCustomModifier[], CILTypeBase>[] parameters)
    {
        if (ctx == null)
        {
            // Throw nullref explicitly for consistency (since it is 'this' parameter)
            // Because CILMethodSignatureImpl ctor throws ArgumentNullException
            throw new NullReferenceException();
        }
        var cctx = (CILReflectionContextImpl)ctx;

        return(new CILMethodSignatureImpl(ctx, currentModule, callingConventions, returnParamMods == null ? null : cctx.CollectionsFactory.NewListProxyFromParams(returnParamMods), returnType, parameters.Select(t => Tuple.Create(t.Item1 == null ? null : cctx.CollectionsFactory.NewListProxyFromParams(t.Item1), t.Item2)).ToList(), null));
    }
 /// <summary>
 /// Creates a new <see cref="CILMethodSignature"/> which has all its information specified from the parameters of this method.
 /// </summary>
 /// <param name="ctx">The current <see cref="CILReflectionContext"/>.</param>
 /// <param name="currentModule">The current <see cref="CILModule"/>.</param>
 /// <param name="callingConventions">The <see cref="UnmanagedCallingConventions"/> for the method signature.</param>
 /// <param name="returnType">The return type for the method signature.</param>
 /// <param name="paramTypes">The types of the parameters.</param>
 /// <returns>A new <see cref="CILMethodSignature"/>.</returns>
 /// <exception cref="NullReferenceException">If <paramref name="ctx"/> is <c>null</c>.</exception>
 /// <exception cref="ArgumentNullException">If <paramref name="currentModule"/>, <paramref name="returnType"/> or any of the types within <paramref name="paramTypes"/> is <c>null</c>.</exception>
 /// <seealso cref="CILMethodSignature"/>
 public static CILMethodSignature NewMethodSignature(this CILReflectionContext ctx, CILModule currentModule, UnmanagedCallingConventions callingConventions, CILTypeBase returnType, params CILTypeBase[] paramTypes)
 {
     return(NewMethodSignature(ctx, currentModule, callingConventions, returnType, null, paramTypes.Select(pt => Tuple.Create((CILCustomModifier[])null, pt)).ToArray()));
 }
Example #7
0
 /// <summary>
 /// Creates a new <see cref="CILMethodSignature"/> that captures the signature of the current method.
 /// </summary>
 /// <param name="method">The <see cref="CILMethodBase"/>.</param>
 /// <param name="callConventions">The <see cref="UnmanagedCallingConventions"/> for the resulting <see cref="CILMethodSignature"/>.</param>
 /// <returns>The new <see cref="CILMethodSignature"/> that captures the signature of the <paramref name="method"/>.</returns>
 /// <exception cref="NullReferenceException">If <paramref name="method"/> is <c>null</c>.</exception>
 /// <exception cref="ArgumentNullException">If any type of parameters is <c>null</c>.</exception>
 public static CILMethodSignature CreateMethodSignature(this CILMethodBase method, UnmanagedCallingConventions callConventions = UnmanagedCallingConventions.C)
 {
     return(new CILMethodSignatureImpl(
                method.ReflectionContext,
                method.DeclaringType.Module,
                callConventions | (UnmanagedCallingConventions)(method.CallingConvention & CallingConventions.HasThis & CallingConventions.ExplicitThis),
                MethodKind.Method == method.MethodKind ?
                ((CILReflectionContextImpl)method.ReflectionContext).CollectionsFactory.NewListProxyFromParams(((CILMethod)method).ReturnParameter.CustomModifiers.ToArray()) :
                null,
                MethodKind.Method == method.MethodKind ?
                ((CILMethod)method).ReturnParameter.ParameterType :
                method.DeclaringType.Module.AssociatedMSCorLibModule.GetTypeByName("System.Void"),
                method.Parameters.Select(param => Tuple.Create(((CILReflectionContextImpl)method.ReflectionContext).CollectionsFactory.NewListProxyFromParams(param.CustomModifiers.ToArray()), param.ParameterType)).ToList(),
                method
                ));
 }