Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
DelegateHelpers.cs
Go to the documentation of this file.
4using System.Text;
6
8
9internal static class DelegateHelpers
10{
12
13 private static readonly MethodInfo s_FuncInvoke = typeof(Func<object[], object>).GetMethod("Invoke");
14
16
17 private static readonly MethodInfo[] s_ActionThunks = GetActionThunks();
18
19 private static readonly MethodInfo[] s_FuncThunks = GetFuncThunks();
20
21 private static int s_ThunksCreated;
22
23 internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func<object[], object> handler)
24 {
25 return CreateObjectArrayDelegateRefEmit(delegateType, handler);
26 }
27
28 public static void ActionThunk(Func<object[], object> handler)
29 {
30 handler(Array.Empty<object>());
31 }
32
33 public static void ActionThunk1<T1>(Func<object[], object> handler, T1 t1)
34 {
35 handler(new object[1] { t1 });
36 }
37
38 public static void ActionThunk2<T1, T2>(Func<object[], object> handler, T1 t1, T2 t2)
39 {
40 handler(new object[2] { t1, t2 });
41 }
42
43 public static TReturn FuncThunk<TReturn>(Func<object[], object> handler)
44 {
45 return (TReturn)handler(Array.Empty<object>());
46 }
47
48 public static TReturn FuncThunk1<T1, TReturn>(Func<object[], object> handler, T1 t1)
49 {
50 return (TReturn)handler(new object[1] { t1 });
51 }
52
53 public static TReturn FuncThunk2<T1, T2, TReturn>(Func<object[], object> handler, T1 t1, T2 t2)
54 {
55 return (TReturn)handler(new object[2] { t1, t2 });
56 }
57
59 {
60 return typeof(Array).GetMethod("Empty").MakeGenericMethod(typeof(object));
61 }
62
63 private static MethodInfo[] GetActionThunks()
64 {
65 Type typeFromHandle = typeof(DelegateHelpers);
66 return new MethodInfo[3]
67 {
68 typeFromHandle.GetMethod("ActionThunk"),
69 typeFromHandle.GetMethod("ActionThunk1"),
70 typeFromHandle.GetMethod("ActionThunk2")
71 };
72 }
73
74 private static MethodInfo[] GetFuncThunks()
75 {
76 Type typeFromHandle = typeof(DelegateHelpers);
77 return new MethodInfo[3]
78 {
79 typeFromHandle.GetMethod("FuncThunk"),
80 typeFromHandle.GetMethod("FuncThunk1"),
81 typeFromHandle.GetMethod("FuncThunk2")
82 };
83 }
84
85 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod", Justification = "The above ActionThunk and FuncThunk methods don't have trimming annotations.")]
86 private static MethodInfo GetCSharpThunk(Type returnType, bool hasReturnValue, ParameterInfo[] parameters)
87 {
88 try
89 {
90 if (parameters.Length > 2)
91 {
92 return null;
93 }
94 if (returnType.IsByRefLike || returnType.IsByRef || returnType.IsPointer)
95 {
96 return null;
97 }
98 foreach (ParameterInfo parameterInfo in parameters)
99 {
100 Type parameterType = parameterInfo.ParameterType;
101 if (parameterType.IsByRefLike || parameterType.IsByRef || parameterType.IsPointer)
102 {
103 return null;
104 }
105 }
106 int num = parameters.Length;
107 if (hasReturnValue)
108 {
109 num++;
110 }
111 Type[] array = ((num == 0) ? Type.EmptyTypes : new Type[num]);
112 for (int j = 0; j < parameters.Length; j++)
113 {
114 array[j] = parameters[j].ParameterType;
115 }
116 MethodInfo methodInfo;
117 if (hasReturnValue)
118 {
119 array[^1] = returnType;
120 methodInfo = s_FuncThunks[parameters.Length];
121 }
122 else
123 {
124 methodInfo = s_ActionThunks[parameters.Length];
125 }
126 return (array.Length != 0) ? methodInfo.MakeGenericMethod(array) : methodInfo;
127 }
128 catch
129 {
130 return null;
131 }
132 }
133
134 private static Delegate CreateObjectArrayDelegateRefEmit(Type delegateType, Func<object[], object> handler)
135 {
136 if (!s_thunks.TryGetValue(delegateType, out var value))
137 {
138 MethodInfo invokeMethod = delegateType.GetInvokeMethod();
139 Type returnType = invokeMethod.ReturnType;
140 bool flag = returnType != typeof(void);
141 ParameterInfo[] parametersCached = invokeMethod.GetParametersCached();
142 value = GetCSharpThunk(returnType, flag, parametersCached);
143 if (value == null)
144 {
145 int value2 = Interlocked.Increment(ref s_ThunksCreated);
146 Type[] array = new Type[parametersCached.Length + 1];
147 array[0] = typeof(Func<object[], object>);
148 StringBuilder stringBuilder = new StringBuilder();
149 stringBuilder.Append("Thunk");
150 stringBuilder.Append(value2);
151 if (flag)
152 {
153 stringBuilder.Append("ret_");
154 stringBuilder.Append(returnType.Name);
155 }
156 for (int i = 0; i < parametersCached.Length; i++)
157 {
158 stringBuilder.Append('_');
159 stringBuilder.Append(parametersCached[i].ParameterType.Name);
160 array[i + 1] = parametersCached[i].ParameterType;
161 }
162 DynamicMethod dynamicMethod = new DynamicMethod(stringBuilder.ToString(), returnType, array);
163 value = dynamicMethod;
164 ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
165 LocalBuilder local = iLGenerator.DeclareLocal(typeof(object[]));
166 LocalBuilder local2 = iLGenerator.DeclareLocal(typeof(object));
167 if (parametersCached.Length == 0)
168 {
169 iLGenerator.Emit(OpCodes.Call, s_ArrayEmpty);
170 }
171 else
172 {
173 iLGenerator.Emit(OpCodes.Ldc_I4, parametersCached.Length);
174 iLGenerator.Emit(OpCodes.Newarr, typeof(object));
175 }
176 iLGenerator.Emit(OpCodes.Stloc, local);
177 bool flag2 = false;
178 for (int j = 0; j < parametersCached.Length; j++)
179 {
180 bool isByRef = parametersCached[j].ParameterType.IsByRef;
181 Type type = parametersCached[j].ParameterType;
182 if (isByRef)
183 {
185 }
186 flag2 = flag2 || isByRef;
187 iLGenerator.Emit(OpCodes.Ldloc, local);
188 iLGenerator.Emit(OpCodes.Ldc_I4, j);
189 iLGenerator.Emit(OpCodes.Ldarg, j + 1);
190 if (isByRef)
191 {
192 iLGenerator.Emit(OpCodes.Ldobj, type);
193 }
195 iLGenerator.Emit(OpCodes.Box, cls);
196 iLGenerator.Emit(OpCodes.Stelem_Ref);
197 }
198 if (flag2)
199 {
200 iLGenerator.BeginExceptionBlock();
201 }
202 iLGenerator.Emit(OpCodes.Ldarg_0);
203 iLGenerator.Emit(OpCodes.Ldloc, local);
204 iLGenerator.Emit(OpCodes.Callvirt, s_FuncInvoke);
205 iLGenerator.Emit(OpCodes.Stloc, local2);
206 if (flag2)
207 {
208 iLGenerator.BeginFinallyBlock();
209 for (int k = 0; k < parametersCached.Length; k++)
210 {
211 if (parametersCached[k].ParameterType.IsByRef)
212 {
213 Type elementType = parametersCached[k].ParameterType.GetElementType();
214 iLGenerator.Emit(OpCodes.Ldarg, k + 1);
215 iLGenerator.Emit(OpCodes.Ldloc, local);
216 iLGenerator.Emit(OpCodes.Ldc_I4, k);
217 iLGenerator.Emit(OpCodes.Ldelem_Ref);
218 iLGenerator.Emit(OpCodes.Unbox_Any, elementType);
219 iLGenerator.Emit(OpCodes.Stobj, elementType);
220 }
221 }
222 iLGenerator.EndExceptionBlock();
223 }
224 if (flag)
225 {
226 iLGenerator.Emit(OpCodes.Ldloc, local2);
227 iLGenerator.Emit(OpCodes.Unbox_Any, ConvertToBoxableType(returnType));
228 }
229 iLGenerator.Emit(OpCodes.Ret);
230 }
231 s_thunks[delegateType] = value;
232 }
233 return value.CreateDelegate(delegateType, handler);
234 }
235
237 {
238 if (!t.IsPointer)
239 {
240 return t;
241 }
242 return typeof(IntPtr);
243 }
244}
static readonly MethodInfo[] s_ActionThunks
static TReturn FuncThunk< TReturn >(Func< object[], object > handler)
static MethodInfo GetCSharpThunk(Type returnType, bool hasReturnValue, ParameterInfo[] parameters)
static MethodInfo GetEmptyObjectArrayMethod()
static readonly MethodInfo[] s_FuncThunks
static readonly MethodInfo s_ArrayEmpty
static readonly CacheDict< Type, MethodInfo > s_thunks
static void ActionThunk2< T1, T2 >(Func< object[], object > handler, T1 t1, T2 t2)
static void ActionThunk(Func< object[], object > handler)
static TReturn FuncThunk1< T1, TReturn >(Func< object[], object > handler, T1 t1)
static Delegate CreateObjectArrayDelegateRefEmit(Type delegateType, Func< object[], object > handler)
static TReturn FuncThunk2< T1, T2, TReturn >(Func< object[], object > handler, T1 t1, T2 t2)
static readonly MethodInfo s_FuncInvoke
static Delegate CreateObjectArrayDelegate(Type delegateType, Func< object[], object > handler)
static void ActionThunk1< T1 >(Func< object[], object > handler, T1 t1)
virtual LocalBuilder DeclareLocal(Type localType)
virtual void Emit(OpCode opcode)
static readonly OpCode Unbox_Any
Definition OpCodes.cs:329
static readonly OpCode Callvirt
Definition OpCodes.cs:225
static readonly OpCode Stloc
Definition OpCodes.cs:429
static readonly OpCode Ldobj
Definition OpCodes.cs:229
static readonly OpCode Ldc_I4
Definition OpCodes.cs:69
static readonly OpCode Stelem_Ref
Definition OpCodes.cs:323
static readonly OpCode Ldelem_Ref
Definition OpCodes.cs:307
static readonly OpCode Stobj
Definition OpCodes.cs:257
static readonly OpCode Call
Definition OpCodes.cs:83
static readonly OpCode Ret
Definition OpCodes.cs:87
static readonly OpCode Ldloc
Definition OpCodes.cs:425
static readonly OpCode Box
Definition OpCodes.cs:279
static readonly OpCode Ldarg_0
Definition OpCodes.cs:9
static readonly OpCode Newarr
Definition OpCodes.cs:281
static readonly OpCode Ldarg
Definition OpCodes.cs:419
virtual MethodInfo MakeGenericMethod(params Type[] typeArguments)
Definition MethodInfo.cs:41
override string ToString()
StringBuilder Append(char value, int repeatCount)
static int Increment(ref int location)
Type? GetElementType()
bool IsPointer
Definition Type.cs:75
virtual bool IsByRefLike
Definition Type.cs:136
static readonly Type[] EmptyTypes
Definition Type.cs:19
MethodInfo? GetMethod(string name)
Definition Type.cs:675
bool IsByRef
Definition Type.cs:73