diff options
Diffstat (limited to 'src/ARMeilleure/Translation/DelegateHelper.cs')
-rw-r--r-- | src/ARMeilleure/Translation/DelegateHelper.cs | 104 |
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(); + } + } +} |