Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
DispatchProxyGenerator.cs
Go to the documentation of this file.
3using System.Linq;
7
8namespace System.Reflection;
9
10internal static class DispatchProxyGenerator
11{
25
26 private sealed class ProxyAssembly
27 {
28 private readonly AssemblyBuilder _ab;
29
30 private readonly ModuleBuilder _mb;
31
32 private int _typeId;
33
35
37
49
51 {
53 _mb = _ab.DefineDynamicModule("testmod");
54 }
55
56 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", Justification = "Only the parameterless ctor is referenced on proxyBaseType. Other members can be trimmed if unused.")]
58 {
60 TypeBuilder tb = _mb.DefineType(name + "_" + num, TypeAttributes.Public, proxyBaseType);
61 return new ProxyBuilder(this, tb, proxyBaseType);
62 }
63
70
72 {
73 if (!type.IsVisible)
74 {
75 string name = type.Assembly.GetName().Name;
77 {
80 }
81 }
82 }
83 }
84
85 private sealed class ProxyBuilder
86 {
87 private sealed class ParametersArray
88 {
89 private readonly ILGenerator _il;
90
91 private readonly Type[] _paramTypes;
92
98
99 internal void Get(int i)
100 {
101 _il.Emit(OpCodes.Ldarg, i + 1);
102 }
103
104 internal void BeginSet(int i)
105 {
106 _il.Emit(OpCodes.Ldarg, i + 1);
107 }
108
109 internal void EndSet(int i, Type stackType)
110 {
114 }
115 }
116
117 private sealed class GenericArray<T>
118 {
119 private readonly ILGenerator _il;
120
121 private readonly LocalBuilder _lb;
122
124 {
125 _il = il;
126 _lb = il.DeclareLocal(typeof(T[]));
127 il.Emit(OpCodes.Ldc_I4, len);
128 il.Emit(OpCodes.Newarr, typeof(T));
129 il.Emit(OpCodes.Stloc, _lb);
130 }
131
132 internal void Load()
133 {
135 }
136
137 internal void Get(int i)
138 {
142 }
143
144 internal void BeginSet(int i)
145 {
148 }
149
150 internal void EndSet(Type stackType)
151 {
152 Convert(_il, stackType, typeof(T), isAddress: false);
154 }
155 }
156
174
197
198 private readonly ProxyAssembly _assembly;
199
200 private readonly TypeBuilder _tb;
201
202 [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
203 private readonly Type _proxyBaseType;
204
205 private readonly List<FieldBuilder> _fields;
206
208
209 private static readonly OpCode[] s_convOpCodes = new OpCode[19]
210 {
211 OpCodes.Nop,
212 OpCodes.Nop,
213 OpCodes.Nop,
226 OpCodes.Nop,
227 OpCodes.Nop,
228 OpCodes.Nop,
229 OpCodes.Nop
230 };
231
232 private static readonly OpCode[] s_ldindOpCodes = new OpCode[19]
233 {
234 OpCodes.Nop,
235 OpCodes.Nop,
236 OpCodes.Nop,
249 OpCodes.Nop,
250 OpCodes.Nop,
251 OpCodes.Nop,
252 OpCodes.Ldind_Ref
253 };
254
255 private static readonly OpCode[] s_stindOpCodes = new OpCode[19]
256 {
257 OpCodes.Nop,
258 OpCodes.Nop,
259 OpCodes.Nop,
272 OpCodes.Nop,
273 OpCodes.Nop,
274 OpCodes.Nop,
275 OpCodes.Stind_Ref
276 };
277
288
289 private void Complete()
290 {
291 Type[] array = new Type[_fields.Count];
292 for (int i = 0; i < array.Length; i++)
293 {
294 array[i] = _fields[i].FieldType;
295 }
297 ILGenerator iLGenerator = constructorBuilder.GetILGenerator();
301 for (int j = 0; j < array.Length; j++)
302 {
304 iLGenerator.Emit(OpCodes.Ldarg, j + 1);
306 }
307 iLGenerator.Emit(OpCodes.Ret);
308 }
309
311 {
312 Complete();
314 }
315
317 {
321 foreach (PropertyInfo runtimeProperty in iface.GetRuntimeProperties())
322 {
324 if (runtimeProperty.GetMethod != null)
325 {
326 dictionary[runtimeProperty.GetMethod] = value;
327 }
328 if (runtimeProperty.SetMethod != null)
329 {
330 dictionary[runtimeProperty.SetMethod] = value;
331 }
332 }
334 foreach (EventInfo runtimeEvent in iface.GetRuntimeEvents())
335 {
336 EventAccessorInfo value2 = new EventAccessorInfo(runtimeEvent.AddMethod, runtimeEvent.RemoveMethod, runtimeEvent.RaiseMethod);
337 if (runtimeEvent.AddMethod != null)
338 {
339 dictionary2[runtimeEvent.AddMethod] = value2;
340 }
341 if (runtimeEvent.RemoveMethod != null)
342 {
343 dictionary2[runtimeEvent.RemoveMethod] = value2;
344 }
345 if (runtimeEvent.RaiseMethod != null)
346 {
347 dictionary2[runtimeEvent.RaiseMethod] = value2;
348 }
349 }
350 foreach (MethodInfo runtimeMethod in iface.GetRuntimeMethods())
351 {
352 if (!runtimeMethod.IsVirtual || runtimeMethod.IsFinal)
353 {
354 continue;
355 }
359 if (dictionary.TryGetValue(runtimeMethod, out var value3))
360 {
361 if (runtimeMethod.Equals(value3.InterfaceGetMethod))
362 {
363 value3.GetMethodBuilder = methodBuilder;
364 }
365 else
366 {
367 value3.SetMethodBuilder = methodBuilder;
368 }
369 }
371 {
372 if (runtimeMethod.Equals(value4.InterfaceAddMethod))
373 {
374 value4.AddMethodBuilder = methodBuilder;
375 }
376 else if (runtimeMethod.Equals(value4.InterfaceRemoveMethod))
377 {
378 value4.RemoveMethodBuilder = methodBuilder;
379 }
380 else
381 {
382 value4.RaiseMethodBuilder = methodBuilder;
383 }
384 }
385 }
386 foreach (PropertyInfo runtimeProperty2 in iface.GetRuntimeProperties())
387 {
388 PropertyAccessorInfo propertyAccessorInfo = dictionary[runtimeProperty2.GetMethod ?? runtimeProperty2.SetMethod];
389 if (!(propertyAccessorInfo.GetMethodBuilder == null) || !(propertyAccessorInfo.SetMethodBuilder == null))
390 {
392 select p.ParameterType).ToArray());
393 if (propertyAccessorInfo.GetMethodBuilder != null)
394 {
395 propertyBuilder.SetGetMethod(propertyAccessorInfo.GetMethodBuilder);
396 }
397 if (propertyAccessorInfo.SetMethodBuilder != null)
398 {
399 propertyBuilder.SetSetMethod(propertyAccessorInfo.SetMethodBuilder);
400 }
401 }
402 }
403 foreach (EventInfo runtimeEvent2 in iface.GetRuntimeEvents())
404 {
405 EventAccessorInfo eventAccessorInfo = dictionary2[runtimeEvent2.AddMethod ?? runtimeEvent2.RemoveMethod];
406 if (!(eventAccessorInfo.AddMethodBuilder == null) || !(eventAccessorInfo.RemoveMethodBuilder == null) || !(eventAccessorInfo.RaiseMethodBuilder == null))
407 {
409 if (eventAccessorInfo.AddMethodBuilder != null)
410 {
411 eventBuilder.SetAddOnMethod(eventAccessorInfo.AddMethodBuilder);
412 }
413 if (eventAccessorInfo.RemoveMethodBuilder != null)
414 {
415 eventBuilder.SetRemoveOnMethod(eventAccessorInfo.RemoveMethodBuilder);
416 }
417 if (eventAccessorInfo.RaiseMethodBuilder != null)
418 {
419 eventBuilder.SetRaiseMethod(eventAccessorInfo.RaiseMethodBuilder);
420 }
421 }
422 }
423 }
424
426 {
427 ParameterInfo[] parameters = mi.GetParameters();
428 Type[] array = new Type[parameters.Length];
429 Type[][] array2 = new Type[array.Length][];
430 for (int i = 0; i < parameters.Length; i++)
431 {
432 array[i] = parameters[i].ParameterType;
433 array2[i] = parameters[i].GetRequiredCustomModifiers();
434 }
435 MethodBuilder methodBuilder = _tb.DefineMethod(mi.Name, MethodAttributes.Public | MethodAttributes.Virtual, CallingConventions.Standard, mi.ReturnType, null, null, array, array2, null);
436 if (mi.ContainsGenericParameters)
437 {
438 Type[] genericArguments = mi.GetGenericArguments();
439 string[] array3 = new string[genericArguments.Length];
440 for (int j = 0; j < genericArguments.Length; j++)
441 {
442 array3[j] = genericArguments[j].Name;
443 }
444 GenericTypeParameterBuilder[] array4 = methodBuilder.DefineGenericParameters(array3);
445 for (int k = 0; k < array4.Length; k++)
446 {
447 array4[k].SetGenericParameterAttributes(genericArguments[k].GenericParameterAttributes);
448 }
449 }
450 ILGenerator iLGenerator = methodBuilder.GetILGenerator();
452 iLGenerator.Emit(OpCodes.Nop);
454 for (int l = 0; l < parameters.Length; l++)
455 {
456 if (!parameters[l].IsOut || !parameters[l].ParameterType.IsByRef || parameters[l].IsIn)
457 {
458 genericArray.BeginSet(l);
459 parametersArray.Get(l);
460 genericArray.EndSet(parameters[l].ParameterType);
461 }
462 }
469 if (mi.ContainsGenericParameters)
470 {
472 Type[] genericArguments2 = mi.GetGenericArguments();
474 for (int m = 0; m < genericArguments2.Length; m++)
475 {
476 genericArray2.BeginSet(m);
479 genericArray2.EndSet(typeof(Type));
480 }
481 genericArray2.Load();
484 }
485 LocalBuilder localBuilder = ((mi.ReturnType != typeof(void)) ? iLGenerator.DeclareLocal(typeof(object)) : null);
488 genericArray.Load();
490 if (localBuilder != null)
491 {
493 }
494 else
495 {
496 iLGenerator.Emit(OpCodes.Pop);
497 }
498 for (int n = 0; n < parameters.Length; n++)
499 {
500 if (parameters[n].ParameterType.IsByRef)
501 {
502 parametersArray.BeginSet(n);
503 genericArray.Get(n);
504 parametersArray.EndSet(n, typeof(object));
505 }
506 }
507 if (localBuilder != null)
508 {
510 Convert(iLGenerator, typeof(object), mi.ReturnType, isAddress: false);
511 }
512 iLGenerator.Emit(OpCodes.Ret);
514 return methodBuilder;
515 }
516
517 private static int GetTypeCode(Type type)
518 {
519 if (type == null)
520 {
521 return 0;
522 }
523 if (type == typeof(bool))
524 {
525 return 3;
526 }
527 if (type == typeof(char))
528 {
529 return 4;
530 }
531 if (type == typeof(sbyte))
532 {
533 return 5;
534 }
535 if (type == typeof(byte))
536 {
537 return 6;
538 }
539 if (type == typeof(short))
540 {
541 return 7;
542 }
543 if (type == typeof(ushort))
544 {
545 return 8;
546 }
547 if (type == typeof(int))
548 {
549 return 9;
550 }
551 if (type == typeof(uint))
552 {
553 return 10;
554 }
555 if (type == typeof(long))
556 {
557 return 11;
558 }
559 if (type == typeof(ulong))
560 {
561 return 12;
562 }
563 if (type == typeof(float))
564 {
565 return 13;
566 }
567 if (type == typeof(double))
568 {
569 return 14;
570 }
571 if (type == typeof(decimal))
572 {
573 return 15;
574 }
575 if (type == typeof(DateTime))
576 {
577 return 16;
578 }
579 if (type == typeof(string))
580 {
581 return 18;
582 }
583 if (type.IsEnum)
584 {
586 }
587 return 1;
588 }
589
590 private static void Convert(ILGenerator il, Type source, Type target, bool isAddress)
591 {
592 if (target == source)
593 {
594 return;
595 }
596 if (source.IsByRef)
597 {
600 Convert(il, elementType, target, isAddress);
601 }
602 else if (target.IsValueType)
603 {
604 if (source.IsValueType)
605 {
606 OpCode opcode = s_convOpCodes[GetTypeCode(target)];
607 il.Emit(opcode);
608 return;
609 }
610 il.Emit(OpCodes.Unbox, target);
611 if (!isAddress)
612 {
613 Ldind(il, target);
614 }
615 }
616 else if (target.IsAssignableFrom(source))
617 {
618 if (source.IsValueType || source.IsGenericParameter)
619 {
620 if (isAddress)
621 {
622 Ldind(il, source);
623 }
624 il.Emit(OpCodes.Box, source);
625 }
626 }
627 else if (target.IsGenericParameter)
628 {
629 il.Emit(OpCodes.Unbox_Any, target);
630 }
631 else
632 {
633 il.Emit(OpCodes.Castclass, target);
634 }
635 }
636
637 private static void Ldind(ILGenerator il, Type type)
638 {
640 if (!opcode.Equals(OpCodes.Nop))
641 {
642 il.Emit(opcode);
643 }
644 else
645 {
646 il.Emit(OpCodes.Ldobj, type);
647 }
648 }
649
650 private static void Stind(ILGenerator il, Type type)
651 {
653 if (!opcode.Equals(OpCodes.Nop))
654 {
655 il.Emit(opcode);
656 }
657 else
658 {
659 il.Emit(OpCodes.Stobj, type);
660 }
661 }
662 }
663
665
666 private static readonly ProxyAssembly s_proxyAssembly = new ProxyAssembly();
667
668 private static readonly MethodInfo s_dispatchProxyInvokeMethod = typeof(DispatchProxy).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.NonPublic);
669
670 private static readonly MethodInfo s_getTypeFromHandleMethod = typeof(Type).GetRuntimeMethod("GetTypeFromHandle", new Type[1] { typeof(RuntimeTypeHandle) });
671
673
674 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "MakeGenericMethod is safe here because the user code invoking the generic method will reference the GenericTypes being used, which will guarantee the requirements of the generic method.")]
676 {
677 return typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[1] { typeof(Type[]) });
678 }
679
681 {
683 return Activator.CreateInstance(proxyType.GeneratedType, new object[1] { proxyType.MethodInfos });
684 }
685
702
703 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2062:UnrecognizedReflectionPattern", Justification = "interfaceType is annotated as preserve All members, so any Types returned from GetInterfaces should be preserved as well once https://github.com/mono/linker/issues/1731 is fixed.")]
705 {
706 if (!interfaceType.IsInterface)
707 {
709 }
710 if (baseType.IsSealed)
711 {
713 }
714 if (baseType.IsAbstract)
715 {
717 }
718 if (baseType.GetConstructor(Type.EmptyTypes) == null)
719 {
721 }
722 ProxyBuilder proxyBuilder = s_proxyAssembly.CreateProxy("generatedProxy", baseType);
723 Type[] interfaces = interfaceType.GetInterfaces();
724 foreach (Type iface in interfaces)
725 {
726 proxyBuilder.AddInterfaceImpl(iface);
727 }
728 proxyBuilder.AddInterfaceImpl(interfaceType);
729 return proxyBuilder.CreateType();
730 }
731}
static ? object CreateInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors|DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture)
Definition Activator.cs:17
bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
void ICollection< T >. Add(T item)
Definition HashSet.cs:225
static Type GetUnderlyingType(Type enumType)
Definition Enum.cs:309
GeneratedTypeInfo([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type generatedType, MethodInfo[] methodInfos)
ProxyBuilder CreateProxy(string name, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type proxyBaseType)
EventAccessorInfo(MethodInfo interfaceAddMethod, MethodInfo interfaceRemoveMethod, MethodInfo interfaceRaiseMethod)
PropertyAccessorInfo(MethodInfo interfaceGetMethod, MethodInfo interfaceSetMethod)
static void Convert(ILGenerator il, Type source, Type target, bool isAddress)
void AddInterfaceImpl([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iface)
MethodBuilder AddMethodImpl(MethodInfo mi, int methodInfoIndex)
ProxyBuilder(ProxyAssembly assembly, TypeBuilder tb, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type proxyBaseType)
static GeneratedTypeInfo GetProxyType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type baseType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
static readonly MethodInfo s_dispatchProxyInvokeMethod
static object CreateProxyInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type baseType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
static GeneratedTypeInfo GenerateProxyType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type baseType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
static readonly Dictionary< Type, Dictionary< Type, GeneratedTypeInfo > > s_baseTypeAndInterfaceToGeneratedProxyType
void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access)
ModuleBuilder DefineDynamicModule(string name)
virtual void Emit(OpCode opcode)
TypeBuilder DefineType(string name)
static readonly OpCode Castclass
Definition OpCodes.cs:235
static readonly OpCode Unbox
Definition OpCodes.cs:241
static readonly OpCode Stind_R8
Definition OpCodes.cs:177
static readonly OpCode Conv_I4
Definition OpCodes.cs:213
static readonly OpCode Stind_I1
Definition OpCodes.cs:167
static readonly OpCode Unbox_Any
Definition OpCodes.cs:329
static readonly OpCode Callvirt
Definition OpCodes.cs:225
static readonly OpCode Ldind_I1
Definition OpCodes.cs:143
static readonly OpCode Conv_I2
Definition OpCodes.cs:211
static readonly OpCode Stind_I2
Definition OpCodes.cs:169
static readonly OpCode Stloc
Definition OpCodes.cs:429
static readonly OpCode Ldind_R4
Definition OpCodes.cs:159
static readonly OpCode Ldind_I2
Definition OpCodes.cs:147
static readonly OpCode Ldind_I4
Definition OpCodes.cs:151
static readonly OpCode Ldind_U2
Definition OpCodes.cs:149
static readonly OpCode Conv_I1
Definition OpCodes.cs:209
static readonly OpCode Ldind_U4
Definition OpCodes.cs:153
static readonly OpCode Ldind_R8
Definition OpCodes.cs:161
static readonly OpCode Ldind_I8
Definition OpCodes.cs:155
static readonly OpCode Stind_I8
Definition OpCodes.cs:173
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 Conv_U1
Definition OpCodes.cs:357
static readonly OpCode Ldfld
Definition OpCodes.cs:245
static readonly OpCode Stind_I4
Definition OpCodes.cs:171
static readonly OpCode Conv_U4
Definition OpCodes.cs:221
static readonly OpCode Ldelem_Ref
Definition OpCodes.cs:307
static readonly OpCode Conv_R4
Definition OpCodes.cs:217
static readonly OpCode Pop
Definition OpCodes.cs:79
static readonly OpCode Conv_U2
Definition OpCodes.cs:355
static readonly OpCode Stobj
Definition OpCodes.cs:257
static readonly OpCode Ldind_U1
Definition OpCodes.cs:145
static readonly OpCode Ldtoken
Definition OpCodes.cs:353
static readonly OpCode Call
Definition OpCodes.cs:83
static readonly OpCode Conv_R8
Definition OpCodes.cs:219
static readonly OpCode Nop
Definition OpCodes.cs:5
static readonly OpCode Ret
Definition OpCodes.cs:87
static readonly OpCode Ldloc
Definition OpCodes.cs:425
static readonly OpCode Stind_R4
Definition OpCodes.cs:175
static readonly OpCode Box
Definition OpCodes.cs:279
static readonly OpCode Ldarg_0
Definition OpCodes.cs:9
static readonly OpCode Conv_U8
Definition OpCodes.cs:223
static readonly OpCode Stfld
Definition OpCodes.cs:249
static readonly OpCode Newarr
Definition OpCodes.cs:281
static readonly OpCode Ldarg
Definition OpCodes.cs:419
static readonly OpCode Conv_I8
Definition OpCodes.cs:215
static int DefineMethod(QCallModule module, int tkParent, string name, byte[] signature, int sigLength, MethodAttributes attributes)
ConstructorBuilder DefineConstructor(MethodAttributes attributes, CallingConventions callingConvention, Type[]? parameterTypes)
void DefineMethodOverride(MethodInfo methodInfoBody, MethodInfo methodInfoDeclaration)
static int DefineProperty(QCallModule module, int tkParent, string name, PropertyAttributes attributes, byte[] signature, int sigLength)
static int DefineEvent(QCallModule module, int tkParent, string name, EventAttributes attributes, int tkEventType)
void AddInterfaceImplementation([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
virtual Type[] GetRequiredCustomModifiers()
static string BaseType_Cannot_Be_Abstract
Definition SR.cs:20
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string InterfaceType_Must_Be_Interface
Definition SR.cs:18
static string BaseType_Must_Have_Default_Ctor
Definition SR.cs:16
static string BaseType_Cannot_Be_Sealed
Definition SR.cs:14
Definition SR.cs:7
static int Increment(ref int location)
Type? GetElementType()
virtual bool IsAssignableFrom([NotNullWhen(true)] Type? c)
Definition Type.cs:1561
bool IsValueType
Definition Type.cs:234
virtual bool IsGenericParameter
Definition Type.cs:85
ConstructorInfo? GetConstructor(Type[] types)
Definition Type.cs:542
static readonly Type[] EmptyTypes
Definition Type.cs:19
override bool Equals([NotNullWhen(true)] object? obj)
Definition OpCode.cs:78