153e4f3ab238392d4af6ae96cd05ff0811ab44f9
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics.CodeAnalysis;
7 using System.Linq;
8 using System.Reflection;
9 using System.Runtime.CompilerServices;
10 using System.Runtime.Serialization;
11 using System.Runtime.Serialization.DataContracts;
12 using System.Text;
13 using System.Threading.Tasks;
14
15 namespace System.Runtime.Serialization
16 {
17     internal static class FastInvokerBuilder
18     {
19         public delegate void Setter(ref object obj, object? value);
20         public delegate object? Getter(object obj);
21
22         private delegate void StructSetDelegate<T, TArg>(ref T obj, TArg value);
23         private delegate TResult StructGetDelegate<T, out TResult>(ref T obj);
24
25         private static readonly MethodInfo s_createGetterInternal = typeof(FastInvokerBuilder).GetMethod(nameof(CreateGetterInternal), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
26         private static readonly MethodInfo s_createSetterInternal = typeof(FastInvokerBuilder).GetMethod(nameof(CreateSetterInternal), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
27         private static readonly MethodInfo s_make = typeof(FastInvokerBuilder).GetMethod(nameof(Make), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
28
29         [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
30         [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
31             Justification = "The call to MakeGenericMethod is safe due to the fact that we are preserving the constructors of type which is what Make() is doing.")]
32         public static Func<object> GetMakeNewInstanceFunc(
33             [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
34             Type type)
35         {
36             Func<object> make = s_make.MakeGenericMethod(type).CreateDelegate<Func<object>>();
37             return make;
38         }
39
40         [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
41             Justification = "The call to MakeGenericMethod is safe due to the fact that FastInvokerBuilder.CreateGetterInternal<T, T1> is not annotated.")]
42         public static Getter CreateGetter(MemberInfo memberInfo)
43         {
44             if (memberInfo is PropertyInfo propInfo)
45             {
46                 Type declaringType = propInfo.DeclaringType!;
47                 Type propertyType = propInfo.PropertyType!;
48
49                 if (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(KeyValue<,>))
50                 {
51                     if (propInfo.Name == "Key")
52                     {
53                         return (obj) =>
54                         {
55                             return ((IKeyValue)obj).Key;
56                         };
57                     }
58                     else
59                     {
60                         return (obj) =>
61                         {
62                             return ((IKeyValue)obj).Value;
63                         };
64                     }
65                 }
66
67                 // If either of the arguments to MakeGenericMethod is a valuetype, this is going to cause JITting.
68                 // Only JIT if dynamic code is supported.
69                 if (RuntimeFeature.IsDynamicCodeSupported || (!declaringType.IsValueType && !propertyType.IsValueType))
70                 {
71 #pragma warning disable IL3050 // AOT compiling should recognize that this call is gated by RuntimeFeature.IsDynamicCodeSupported.
72                     var createGetterGeneric = s_createGetterInternal.MakeGenericMethod(declaringType, propertyType).CreateDelegate<Func<PropertyInfo, Getter>>();
73 #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
74                     return createGetterGeneric(propInfo);
75                 }
76                 else
77                 {
78                     return propInfo.GetValue;
79                 }
80             }
81             else if (memberInfo is FieldInfo fieldInfo)
82             {
83                 return (obj) =>
84                 {
85                     var value = fieldInfo.GetValue(obj);
86                     return value;
87                 };
88             }
89             else
90             {
91                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.InvalidMember, DataContract.GetClrTypeFullName(memberInfo.DeclaringType!), memberInfo.Name)));
92             }
93         }
94
95         [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
96             Justification = "The call to MakeGenericMethod is safe due to the fact that FastInvokerBuilder.CreateSetterInternal<T, T1> is not annotated.")]
97         public static Setter CreateSetter(MemberInfo memberInfo)
98         {
99             if (memberInfo is PropertyInfo propInfo)
100             {
101                 if (propInfo.CanWrite)
102                 {
103                     Type declaringType = propInfo.DeclaringType!;
104                     Type propertyType = propInfo.PropertyType!;
105
106                     if (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(KeyValue<,>))
107                     {
108                         if (propInfo.Name == "Key")
109                         {
110                             return (ref object obj, object? val) =>
111                             {
112                                 ((IKeyValue)obj).Key = val;
113                             };
114                         }
115                         else
116                         {
117                             return (ref object obj, object? val) =>
118                             {
119                                 ((IKeyValue)obj).Value = val;
120                             };
121                         }
122                     }
123
124                     // If either of the arguments to MakeGenericMethod is a valuetype, this is going to cause JITting.
125                     // Only JIT if dynamic code is supported.
126                     if (RuntimeFeature.IsDynamicCodeSupported || (!declaringType.IsValueType && !propertyType.IsValueType))
127                     {
128 #pragma warning disable IL3050 // AOT compiling should recognize that this call is gated by RuntimeFeature.IsDynamicCodeSupported.
129                         var createSetterGeneric = s_createSetterInternal.MakeGenericMethod(propInfo.DeclaringType!, propInfo.PropertyType).CreateDelegate<Func<PropertyInfo, Setter>>();
130 #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
131                         return createSetterGeneric(propInfo);
132                     }
133                     else
134                     {
135                         return (ref object obj, object? val) =>
136                         {
137                             propInfo.SetValue(obj, val);
138                         };
139                     }
140                 }
141                 else
142                 {
143                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.NoSetMethodForProperty, propInfo.DeclaringType, propInfo.Name)));
144                 }
145             }
146             else if (memberInfo is FieldInfo fieldInfo)
147             {
148                 return (ref object obj, object? val) =>
149                 {
150                     fieldInfo.SetValue(obj, val);
151                 };
152             }
153             else
154             {
155                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.InvalidMember, DataContract.GetClrTypeFullName(memberInfo.DeclaringType!), memberInfo.Name)));
156             }
157         }
158
159         private static object Make<T>() where T : new()
160         {
161             var t = new T();
162             return t;
163         }
164
165         private static Getter CreateGetterInternal<DeclaringType, PropertyType>(PropertyInfo propInfo)
166         {
167             if (typeof(DeclaringType).IsValueType)
168             {
169                 var getMethod = propInfo.GetMethod!.CreateDelegate<StructGetDelegate<DeclaringType, PropertyType>>();
170
171                 return (obj) =>
172                 {
173                     var unboxed = (DeclaringType)obj;
174                     return getMethod(ref unboxed);
175                 };
176             }
177             else
178             {
179                 var getMethod = propInfo.GetMethod!.CreateDelegate<Func<DeclaringType, PropertyType>>();
180
181                 return (obj) =>
182                 {
183                     return getMethod((DeclaringType)obj);
184                 };
185             }
186         }
187
188         private static Setter CreateSetterInternal<DeclaringType, PropertyType>(PropertyInfo propInfo)
189         {
190             if (typeof(DeclaringType).IsValueType)
191             {
192                 var setMethod = propInfo.SetMethod!.CreateDelegate<StructSetDelegate<DeclaringType, PropertyType>>();
193
194                 return (ref object obj, object? val) =>
195                 {
196                     var unboxed = (DeclaringType)obj;
197                     setMethod(ref unboxed, (PropertyType)val!);
198                     obj = unboxed!;
199                 };
200             }
201             else
202             {
203                 var setMethod = propInfo.SetMethod!.CreateDelegate<Action<DeclaringType, PropertyType>>();
204
205                 return (ref object obj, object? val) =>
206                 {
207                     setMethod((DeclaringType)obj, (PropertyType)val!);
208                 };
209             }
210         }
211     }
212 }