/* * Copyright (c), 2009 Sigbjorn Finne * * The HsDelegateGen class handles the creation of wrapper types * for native function pointers (hiding pure Haskell code..honest!) * * Uses System.Reflection.Emit * */ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; // type synonym, C# style. using TypePair = Pair; namespace HsInvoker { [ComVisible(false)] public class HsDelegateGen { private static ModuleBuilder m_moduleBuilder; private static AssemblyBuilder m_aBuilder; private static int m_uniq; private static String m_dynName = "HsNetBridgeDynAssembly"; private static String m_modName = "HsNetBridgeDynModule"; private static String m_typeName = "DynDelegator"; private static String m_dllName; private static Dictionary m_tyMap; static HsDelegateGen() { m_uniq = 0; m_moduleBuilder=null; m_aBuilder = null; m_dllName = null; // enable when debugging generated IL: // m_dllName = "DynNetBridgeDbg.dll"; } // // Method: LookupDelegateType(String) // // By maintaining a map from the type signature of the // delegate types generated, to their actual implementation, // sharing is straightforward to implement. // // LookupDelegateType() takes the signature string as argument and returns // the corresponding TypePair, if any. // public static TypePair LookupDelegateType(String s) { if ( m_tyMap==null ) { m_tyMap = new Dictionary(); } if ( m_tyMap.ContainsKey(s) ) { return m_tyMap[s]; } else { return null; } } // // Method: AddDelegateType(String,TypePair) // // For a newly generated delegator type, extend the map // associating its method/type signature with the new types. // public static void AddDelegateType(String s, TypePair p) { if ( m_tyMap==null ) { m_tyMap = new Dictionary(); } m_tyMap[s] = p; } // // Define a new unique dynamic type for a delegate, reusing // types already generated if at all possible. // // Called by the interop layer when wrapping up Haskell function values. // public static Object DefineDelegate(Type delType, String methodName, IntPtr ffiPtr) { #if false if ( delType.IsSubclassOf( typeof(System.MulticastDelegate) ) { try { Object nDel = Marshal.GetDelegateForFunctionPointer(ffiPtr, delType); return nDel; } catch (Exception e) { Console.WriteLine("DefineDelegate: {0}", e); return e; } } #endif /* Set up dynamic assembly, so as to have a place to emit the new type into */ CreateDynAssembly(); String theTypeName = m_typeName; String tyStr= ""; Type resTy = null; ParameterInfo[] ps = GetParamTypes(delType, ref resTy); Type[] ts = new Type[ps.Length]; int i = 0; Type delTy; Type dTy; TypePair genPair; /* Construct a signature string, =[arg]+, which is used * to have isomorphic delegators (i.e., same function-pointer signature) * share the underlying, dynamic class. Essential to make this * dynamic-delegate story of practical use. */ if ( resTy!=null ) { tyStr = resTy.ToString() + "="; } for(i=0;i>(); } if ( m_aBuilder==null ) { InitDynAssembly(); } } private static void InitDynAssembly() { AssemblyName aName = new AssemblyName(); aName.Name = m_dynName; AppDomain aDom = System.Threading.Thread.GetDomain(); bool saveDll = m_dllName!=null && m_dllName != ""; m_aBuilder = aDom.DefineDynamicAssembly(aName,( saveDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run)); if ( saveDll ) { m_moduleBuilder = m_aBuilder.DefineDynamicModule(m_modName, m_dllName, true); } else { m_moduleBuilder = m_aBuilder.DefineDynamicModule(m_modName); } } private static void ResetGenAssembly(String dllName) { if ( m_dllName!=null ) { m_aBuilder.Save(m_dllName); } m_dllName = dllName; m_aBuilder=null; } private static TypeBuilder GenType(String ty, TypeAttributes attrs) { TypeBuilder typeBuilder; String theTypeName = ty; while (true) { try { // Console.WriteLine("Attempting to create type {0}..",theTypeName); typeBuilder = m_moduleBuilder.DefineType(theTypeName, attrs); break; } catch (ArgumentException) { m_uniq++; theTypeName = String.Format("{0}{1}",m_typeName,m_uniq); } } // Console.WriteLine("Succeeded creating {0} type", theTypeName); return typeBuilder; } private static ParameterInfo[] GetParamTypes(Type delTy, ref Type resTy) { if ( delTy.IsSubclassOf(typeof(System.Delegate)) ) { MethodInfo mi = delTy.GetMethod("Invoke"); resTy = mi.ReturnType; return mi.GetParameters(); } else { resTy = null; return new ParameterInfo[0]; } } }; } /* namespace */