aboutsummaryrefslogtreecommitdiff
path: root/src/ARMeilleure/Translation/DelegateHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ARMeilleure/Translation/DelegateHelper.cs')
-rw-r--r--src/ARMeilleure/Translation/DelegateHelper.cs104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/ARMeilleure/Translation/DelegateHelper.cs b/src/ARMeilleure/Translation/DelegateHelper.cs
new file mode 100644
index 00000000..43a39bab
--- /dev/null
+++ b/src/ARMeilleure/Translation/DelegateHelper.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace ARMeilleure.Translation
+{
+ static class DelegateHelper
+ {
+ private const string DelegateTypesAssemblyName = "JitDelegateTypes";
+
+ private static readonly ModuleBuilder _modBuilder;
+
+ private static readonly Dictionary<string, Type> _delegateTypesCache;
+
+ static DelegateHelper()
+ {
+ AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
+
+ _modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
+
+ _delegateTypesCache = new Dictionary<string, Type>();
+ }
+
+ public static Delegate GetDelegate(MethodInfo info)
+ {
+ ArgumentNullException.ThrowIfNull(info);
+
+ Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
+ Type returnType = info.ReturnType;
+
+ Type delegateType = GetDelegateType(parameters, returnType);
+
+ return Delegate.CreateDelegate(delegateType, info);
+ }
+
+ private static Type GetDelegateType(Type[] parameters, Type returnType)
+ {
+ string key = GetFunctionSignatureKey(parameters, returnType);
+
+ if (!_delegateTypesCache.TryGetValue(key, out Type delegateType))
+ {
+ delegateType = MakeDelegateType(parameters, returnType, key);
+
+ _delegateTypesCache.TryAdd(key, delegateType);
+ }
+
+ return delegateType;
+ }
+
+ private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
+ {
+ string sig = GetTypeName(returnType);
+
+ foreach (Type type in parameters)
+ {
+ sig += '_' + GetTypeName(type);
+ }
+
+ return sig;
+ }
+
+ private static string GetTypeName(Type type)
+ {
+ return type.FullName.Replace(".", string.Empty);
+ }
+
+ private const MethodAttributes CtorAttributes =
+ MethodAttributes.RTSpecialName |
+ MethodAttributes.HideBySig |
+ MethodAttributes.Public;
+
+ private const TypeAttributes DelegateTypeAttributes =
+ TypeAttributes.Class |
+ TypeAttributes.Public |
+ TypeAttributes.Sealed |
+ TypeAttributes.AnsiClass |
+ TypeAttributes.AutoClass;
+
+ private const MethodImplAttributes ImplAttributes =
+ MethodImplAttributes.Runtime |
+ MethodImplAttributes.Managed;
+
+ private const MethodAttributes InvokeAttributes =
+ MethodAttributes.Public |
+ MethodAttributes.HideBySig |
+ MethodAttributes.NewSlot |
+ MethodAttributes.Virtual;
+
+ private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
+
+ private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
+ {
+ TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
+
+ builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
+
+ builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
+
+ return builder.CreateTypeInfo();
+ }
+ }
+}