System.Reflection: Replicate custom modifiers of method parameters in MemberRef signa...
authorstakx <stakx@eml.cc>
Wed, 16 May 2018 22:48:40 +0000 (00:48 +0200)
committerAtsushi Kanamori <AtsushiKan@users.noreply.github.com>
Wed, 16 May 2018 22:48:40 +0000 (15:48 -0700)
* Include cmods in `ModuleBuilder.GetMemberRefToken`

This method reproduces a method's signature for use in a MethodRef
metadata entry, but currently ignores custom modifiers placed in the
method's parameters. Add additional parameters for those.

* Add parameter cmod params for other code paths

This lets the change from the previous commit "bubble up" towards the
public API by adding support for parameter cmods in more places.

* Reduce code duplication

In several places, `ParameterInfo[]` is converted to three matching
arrays for parameter types and their modreqs and modpts, because that
is what `SignatureHelper` requires. Extract this duplicated logic
into a single method. Also, optimize it to reduce array allocations.

src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs
src/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs
src/System.Private.CoreLib/src/System/Reflection/Emit/SignatureHelper.cs

index 5ecf0bef8037e0f819fafe170062a393bc1ff0a7..d4ce4a9f5e1dd895eb6714a5ea4e9b47ce7cd842 100644 (file)
@@ -216,6 +216,8 @@ namespace System.Reflection.Emit
             sig = GetMemberRefSignature(callingConvention,
                                         returnType,
                                         parameterTypes,
+                                        null,
+                                        null,
                                         optionalParameterTypes);
 
             EnsureCapacity(7);
@@ -440,8 +442,6 @@ namespace System.Reflection.Emit
 
         private int GetMemberRefToken(MethodBase methodInfo, Type[] optionalParameterTypes)
         {
-            Type[] parameterTypes;
-
             if (optionalParameterTypes != null && (methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
                 throw new InvalidOperationException(SR.InvalidOperation_NotAVarArgCallingConvention);
 
@@ -451,21 +451,17 @@ namespace System.Reflection.Emit
             if (rtMeth == null && dm == null)
                 throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(methodInfo));
 
-            ParameterInfo[] paramInfo = methodInfo.GetParametersNoCopy();
-            if (paramInfo != null && paramInfo.Length != 0)
-            {
-                parameterTypes = new Type[paramInfo.Length];
-                for (int i = 0; i < paramInfo.Length; i++)
-                    parameterTypes[i] = paramInfo[i].ParameterType;
-            }
-            else
-            {
-                parameterTypes = null;
-            }
+            SignatureHelper.ExtractParametersTypeArrays(
+                methodInfo.GetParametersNoCopy(),
+                out Type[] parameterTypes,
+                out Type[][] parameterTypeRequiredCustomModifiers,
+                out Type[][] parameterTypeOptionalCustomModifiers);
 
             SignatureHelper sig = GetMemberRefSignature(methodInfo.CallingConvention,
                                                      MethodBuilder.GetMethodBaseReturnType(methodInfo),
                                                      parameterTypes,
+                                                     parameterTypeRequiredCustomModifiers,
+                                                     parameterTypeOptionalCustomModifiers,
                                                      optionalParameterTypes);
 
             if (rtMeth != null)
@@ -478,13 +474,24 @@ namespace System.Reflection.Emit
                                                 CallingConventions call,
                                                 Type returnType,
                                                 Type[] parameterTypes,
+                                                Type[][] parameterTypeRequiredCustomModifiers,
+                                                Type[][] parameterTypeOptionalCustomModifiers,
                                                 Type[] optionalParameterTypes)
         {
             SignatureHelper sig = SignatureHelper.GetMethodSigHelper(call, returnType);
+
+            Debug.Assert(parameterTypeRequiredCustomModifiers == null
+                     || (parameterTypeRequiredCustomModifiers.Length == (parameterTypes?.Length ?? 0)));
+
+            Debug.Assert(parameterTypeOptionalCustomModifiers == null
+                     || (parameterTypeOptionalCustomModifiers.Length == (parameterTypes?.Length ?? 0)));
+
             if (parameterTypes != null)
             {
-                foreach (Type t in parameterTypes)
-                    sig.AddArgument(t);
+                for (int i = 0; i < parameterTypes.Length; i++)
+                {
+                    sig.AddArgument(parameterTypes[i], parameterTypeRequiredCustomModifiers?[i], parameterTypeOptionalCustomModifiers?[i]);
+                }
             }
             if (optionalParameterTypes != null && optionalParameterTypes.Length != 0)
             {
index a1cee10ba3cd477395e373fd5f3fd7cf85f984c5..610d8db4eaafbca16a0aeba5e1ba16303cb8da1f 100644 (file)
@@ -207,15 +207,17 @@ namespace System.Reflection.Emit
         }
 
         internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType,
-            Type[] parameterTypes, Type[] optionalParameterTypes)
+            Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers,
+            Type[] optionalParameterTypes)
         {
-            return GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, 0);
+            return GetMemberRefSignature(call, returnType, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers, optionalParameterTypes, 0);
         }
 
         private SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType,
-            Type[] parameterTypes, Type[] optionalParameterTypes, int cGenericParameters)
+            Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers,
+            Type[] optionalParameterTypes, int cGenericParameters)
         {
-            return ((ModuleBuilder)m_methodBuilder.Module).GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, cGenericParameters);
+            return ((ModuleBuilder)m_methodBuilder.Module).GetMemberRefSignature(call, returnType, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers, optionalParameterTypes, cGenericParameters);
         }
 
         internal byte[] BakeByteArray()
@@ -506,6 +508,8 @@ namespace System.Reflection.Emit
             sig = GetMemberRefSignature(callingConvention,
                                         returnType,
                                         parameterTypes,
+                                        null,
+                                        null,
                                         optionalParameterTypes);
 
             EnsureCapacity(7);
index 9b2d878d3898a28465f8968648de18516085134a..5456881ffe5739449a39ea7a631d8ffc919c8890 100644 (file)
@@ -298,21 +298,18 @@ namespace System.Reflection.Emit
                 ParameterInfo[] parameters = con.GetParameters();
                 if (parameters == null)
                     throw new ArgumentException(SR.Argument_InvalidConstructorInfo);
-
-                Type[] parameterTypes = new Type[parameters.Length];
-                Type[][] requiredCustomModifiers = new Type[parameters.Length][];
-                Type[][] optionalCustomModifiers = new Type[parameters.Length][];
-
                 for (int i = 0; i < parameters.Length; i++)
                 {
                     if (parameters[i] == null)
                         throw new ArgumentException(SR.Argument_InvalidConstructorInfo);
-
-                    parameterTypes[i] = parameters[i].ParameterType;
-                    requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers();
-                    optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers();
                 }
 
+                SignatureHelper.ExtractParametersTypeArrays(
+                    parameters,
+                    out Type[] parameterTypes,
+                    out Type[][] requiredCustomModifiers,
+                    out Type[][] optionalCustomModifiers);
+
                 tr = GetTypeTokenInternal(con.ReflectedType).Token;
 
                 SignatureHelper sigHelp = SignatureHelper.GetMethodSigHelper(this, con.CallingConvention, null, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
@@ -380,7 +377,7 @@ namespace System.Reflection.Emit
 
         private int GetMemberRefToken(MethodBase method, IEnumerable<Type> optionalParameterTypes)
         {
-            Type[] parameterTypes;
+            ParameterInfo[] parameters;
             Type returnType;
             int tkParent;
             int cGenericParameters = 0;
@@ -447,17 +444,24 @@ namespace System.Reflection.Emit
                     }
                 }
 
-                parameterTypes = methDef.GetParameterTypes();
+                parameters = methDef.GetParameters();
                 returnType = MethodBuilder.GetMethodBaseReturnType(methDef);
             }
             else
             {
-                parameterTypes = method.GetParameterTypes();
+                parameters = method.GetParameters();
                 returnType = MethodBuilder.GetMethodBaseReturnType(method);
             }
 
+            SignatureHelper.ExtractParametersTypeArrays(
+                parameters,
+                out Type[] parameterTypes,
+                out Type[][] parameterTypeRequiredCustomModifiers,
+                out Type[][] parameterTypeOptionalCustomModifiers);
+
             int sigLength;
             byte[] sigBytes = GetMemberRefSignature(method.CallingConvention, returnType, parameterTypes,
+                parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers,
                 optionalParameterTypes, cGenericParameters).InternalGetSignature(out sigLength);
 
             if (method.DeclaringType.IsGenericType)
@@ -484,15 +488,22 @@ namespace System.Reflection.Emit
         }
 
         internal SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType,
-            Type[] parameterTypes, IEnumerable<Type> optionalParameterTypes, int cGenericParameters)
+            Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers,
+            IEnumerable<Type> optionalParameterTypes, int cGenericParameters)
         {
             SignatureHelper sig = SignatureHelper.GetMethodSigHelper(this, call, returnType, cGenericParameters);
 
+            Debug.Assert(parameterTypeRequiredCustomModifiers == null
+                     || (parameterTypeRequiredCustomModifiers.Length == (parameterTypes?.Length ?? 0)));
+
+            Debug.Assert(parameterTypeOptionalCustomModifiers == null
+                     || (parameterTypeOptionalCustomModifiers.Length == (parameterTypes?.Length ?? 0)));
+
             if (parameterTypes != null)
             {
-                foreach (Type t in parameterTypes)
+                for (int i = 0; i < parameterTypes.Length; i++)
                 {
-                    sig.AddArgument(t);
+                    sig.AddArgument(parameterTypes[i], parameterTypeRequiredCustomModifiers?[i], parameterTypeOptionalCustomModifiers?[i]);
                 }
             }
 
@@ -1268,16 +1279,11 @@ namespace System.Reflection.Emit
                     // go through the slower code path, i.e. retrieve parameters and form signature helper.
                     ParameterInfo[] parameters = method.GetParameters();
 
-                    Type[] parameterTypes = new Type[parameters.Length];
-                    Type[][] requiredCustomModifiers = new Type[parameterTypes.Length][];
-                    Type[][] optionalCustomModifiers = new Type[parameterTypes.Length][];
-
-                    for (int i = 0; i < parameters.Length; i++)
-                    {
-                        parameterTypes[i] = parameters[i].ParameterType;
-                        requiredCustomModifiers[i] = parameters[i].GetRequiredCustomModifiers();
-                        optionalCustomModifiers[i] = parameters[i].GetOptionalCustomModifiers();
-                    }
+                    SignatureHelper.ExtractParametersTypeArrays(
+                        parameters,
+                        out Type[] parameterTypes,
+                        out Type[][] requiredCustomModifiers,
+                        out Type[][] optionalCustomModifiers);
 
                     tr = getGenericTypeDefinition ? GetTypeToken(method.DeclaringType).Token : GetTypeTokenInternal(method.DeclaringType).Token;
 
index d9490838aa58381c43029f7df3a21726ef450e95..8b99f74d0adba53f0e0e70c5081a42ae567fdd5b 100644 (file)
@@ -191,6 +191,58 @@ namespace System.Reflection.Emit
 
             return new SignatureHelper(module, type);
         }
+
+        internal static void ExtractParametersTypeArrays(ParameterInfo[] parameters,
+                                                         out Type[] parameterTypes,
+                                                         out Type[][] parameterTypeRequiredCustomModifiers,
+                                                         out Type[][] parameterTypeOptionalCustomModifiers)
+        {
+            // This method tries to allocate as few arrays as possible. In the absence of parameters or
+            // custom modifiers, arrays or single items will default to null. The returned arrays will
+            // generally be fed back to a `SignatureHelper` which must perform null checks where necessary.
+
+            Type[] types = null;
+            Type[][] requiredCustomModifiers = null;
+            Type[][] optionalCustomModifiers = null;
+
+            Debug.Assert(parameters != null);
+
+            if (parameters.Length > 0)
+            {
+                types = new Type[parameters.Length];
+                for (int i = 0; i < parameters.Length; i++)
+                {
+                    Debug.Assert(parameters[i] != null);
+
+                    types[i] = parameters[i].ParameterType;
+
+                    Type[] rcms = parameters[i].GetRequiredCustomModifiers();
+                    if (rcms.Length > 0)
+                    {
+                        if (requiredCustomModifiers == null)
+                        {
+                            requiredCustomModifiers = new Type[parameters.Length][];
+                        }
+                        requiredCustomModifiers[i] = rcms;
+                    }
+
+                    Type[] ocms = parameters[i].GetOptionalCustomModifiers();
+                    if (ocms.Length > 0)
+                    {
+                        if (optionalCustomModifiers == null)
+                        {
+                            optionalCustomModifiers = new Type[parameters.Length][];
+                        }
+                        optionalCustomModifiers[i] = ocms;
+                    }
+                }
+            }
+
+            parameterTypes = types;
+            parameterTypeRequiredCustomModifiers = requiredCustomModifiers;
+            parameterTypeOptionalCustomModifiers = optionalCustomModifiers;
+        }
+
         #endregion
 
         #region Private Data Members