/// <summary> /// Returns a native function pointer to a stub method that sets the value /// of the given static or instance field. /// </summary> /// <remarks> /// The returned function pointer should be freed with 'FreeDotNetFunPtr'. /// </remarks> public static IntPtr GenerateFieldSetStub(FieldInfo field) { // Signature of the stub method returned (as a delegate) by this function DelegateSignature methodSignature = new DelegateSignature( typeof(void), field.IsStatic ? new Type[] { ConvertToStubType(field.FieldType) } : new Type[] { ConvertToStubType(field.DeclaringType), ConvertToStubType(field.FieldType) }); return(GenerateDynamicMethod(field.DeclaringType.Name + "_field_set_" + field.Name, methodSignature, delegate(ILGenerator ilg) { if (field.IsStatic) { // Load (and unmarshal) the field value from the stub call EmitParameterLoading(ilg, 0, field.FieldType); ilg.Emit(OpCodes.Stsfld, field); } else { // Load (and unmarshal) the instance argument and field value from the stub call EmitParameterLoading(ilg, 0, field.DeclaringType); EmitParameterLoading(ilg, 1, field.FieldType); ilg.Emit(OpCodes.Stfld, field); } ilg.Emit(OpCodes.Ret); })); }
/// <summary> /// Returns a native function pointer to a wrapper stub that accepts foreign /// parameters, marshals them, calls the indicated constructor, and returns the /// resulting object instance (marshaled as necessary). /// </summary> /// <remarks> /// The returned function pointer should be freed with 'FreeDotNetFunPtr'. /// When used to construct a value type, 'con' may be null, in which case /// no constructor is called (the value is just initialised to zero). /// </remarks> public static IntPtr GenerateConstructorStub(ConstructorInfo con) { Type type = con.DeclaringType; if (!type.IsValueType && con == null) { throw new ArgumentNullException("'con' cannot be null if creating a reference type."); } // Generate a dynamic method that does the following: // // Int32 [classType]New([args...]) // { // [classType] o = new [classType]([args... using GetObject ... ]); // (box o if it is a value type) // return Driver.RegisterObject(o); // } // Signature of the stub method returned (as a delegate) by this function DelegateSignature methodSignature = new DelegateSignature( typeof(Int32), con == null ? Type.EmptyTypes : ConvertToStubTypes(Util.MapParametersToTypes(con.GetParameters()))); return(GenerateDynamicMethod(type.Name + "New", methodSignature, delegate(ILGenerator ilg) { if (con == null) // Initialise object to zero? { // Initialise the object in a local variable ilg.DeclareLocal(type); ilg.Emit(OpCodes.Ldloca_S, (byte)0); ilg.Emit(OpCodes.Initobj, type); // Load the object onto the stack ilg.Emit(OpCodes.Ldloc_0); } else // Call object constructor: { // Load (and unmarshal), the arguments to the constructor stub EmitParameterLoading(ilg, 0, con.GetParameters()); // Call the constructor, i.e. 'o = new [classType]([unmarshaled args])' ilg.Emit(OpCodes.Newobj, con); } // Return the new object (marshaled as an index) EmitToStub(ilg, type); ilg.Emit(OpCodes.Ret); })); }
/// <summary> /// Returns a native function pointer to a stub method that calls the given /// method, marshaling arguments as necessary. /// </summary> /// <remarks> /// The returned function pointer should be freed with 'FreeDotNetFunPtr'. /// </remarks> public static IntPtr GenerateMethodStub(MethodInfo meth) { Type classType = meth.DeclaringType; // Generate a dynamic method that does the following: // // [stubReturnType] [classType]_[methodName]([classType] this, [args...]) // OR (if a static method) // [stubReturnType] [classType]_[methodName]([args...]) // { // [resultType] r = this.[methodName]([marshaledThis], [marshaled args]); // OR (if a static method) // [resultType] r = [className].[methodName]([marshaled args]); // // return r; OR return Driver.RegisterObject(r); // } // Signature of the stub method returned (as a delegate) by this function DelegateSignature methodSignature = new DelegateSignature( ConvertToStubType(meth.ReturnParameter.ParameterType), meth.IsStatic ? ConvertToStubTypes(Util.MapParametersToTypes(meth.GetParameters())) : Util.ConcatArray <Type>( ConvertToStubType(meth.DeclaringType), ConvertToStubTypes(Util.MapParametersToTypes(meth.GetParameters())))); return(GenerateDynamicMethod(classType.Name + "_" + meth.Name, methodSignature, delegate(ILGenerator ilg) { // Load (and unmarshal), the arguments to the method stub, then call the real method if (meth.IsStatic) { EmitParameterLoading(ilg, 0, meth.GetParameters()); ilg.Emit(OpCodes.Call, meth); } else { EmitParameterLoading(ilg, 0, meth.DeclaringType); EmitParameterLoading(ilg, 1, meth.GetParameters()); ilg.Emit(OpCodes.Callvirt, meth); } // Unmarshal and return the result EmitMarshaledReturn(ilg, meth.ReturnParameter); })); }
public void Initialize(DelegateSignature func, bool showButtons) { if (minusButton != null) { minusButton.onClick.AddListener(MinusCallback); minusButton.gameObject.SetActive(false); } if (plusButton != null) { plusButton.onClick.AddListener(PlusCallback); if (showButtons) { plusButton.gameObject.SetActive(false); } } buttonsDelegate = func; }
/// <summary> /// Returns a native function pointer to a stub method that retrieves the value /// of the given static or instance field. /// </summary> /// <remarks> /// The returned function pointer should be freed with 'FreeDotNetFunPtr'. /// </remarks> public static IntPtr GenerateFieldGetStub(FieldInfo field) { // Signature of the stub method returned (as a delegate) by this function DelegateSignature methodSignature = new DelegateSignature( ConvertToStubType(field.FieldType), field.IsStatic ? Type.EmptyTypes : new Type[] { ConvertToStubType(field.DeclaringType) }); return(GenerateDynamicMethod(field.DeclaringType.Name + "_field_get_" + field.Name, methodSignature, delegate(ILGenerator ilg) { if (field.IsStatic) { if (field.IsLiteral) { // FIXME: Move literal calculation to the generator, and add // support for literal values in the bridge (i.e. // values other than 'Obj ObjectId's object literalValue = field.GetRawConstantValue(); if (literalValue is Int32) { ilg.Emit(OpCodes.Ldc_I4, (Int32)literalValue); } } else { ilg.Emit(OpCodes.Ldsfld, field); } } else { // Load (and unmarshal) the argument to the method stub, then load the field value EmitParameterLoading(ilg, 0, field.DeclaringType); ilg.Emit(OpCodes.Ldfld, field); } // Unmarshal and return the result EmitToStub(ilg, field.FieldType); ilg.Emit(OpCodes.Ret); })); }
/// <summary> /// Instantiates a delegate that, given an IntPtr to a Haskell function, returns a /// delegate instance (of the given delegate type) that wraps this native function /// (and deals with parameter value marshaling and finalization). /// </summary> /// <param name="delegateType">Type of delegate returned by the returned delegate.</param> /// <returns> /// Wrapper delegate that accepts an IntPtr and returns a delegate of the /// indicated type. /// </returns> public static IntPtr GenerateDelegateConstructorStub(Type delegateType) { // Obtain (creating, if necessary) the type of a wrapper class for the delegate Type wrapperType = GetDelegateWrapperType(delegateType); DelegateSignature delegateSignature = DelegateSignature.FromDelegateType(delegateType); // Generate a dynamic method that does the following: // // Int32 [delegateType]New(IntPtr funPtr) // { // [wrapperType] wrapper = new [wrapperType](funPtr); // Delegate d = new [delegateType](wrapper.Invoke); // return Driver.RegisterObject(d); // } // Signature of the method returned (as a delegate) by this function (the // method accepts an IntPtr to a Haskell function and returns an instantiated // .NET delegate for it) DelegateSignature methodSignature = new DelegateSignature( typeof(Int32), new Type[] { typeof(IntPtr) }); return(GenerateDynamicMethod(delegateType.Name + "New", methodSignature, delegate(ILGenerator ilg) { // wrapper = new [wrapperType](funPtr): ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Newobj, wrapperType.GetConstructor(new Type[] { typeof(IntPtr) })); // Obtain wrapper.Invoke ilg.Emit(OpCodes.Ldftn, wrapperType.GetMethod("Invoke")); // Delegate d = new [delegateType](wrapper.Invoke): ilg.Emit(OpCodes.Newobj, delegateType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })); // return Driver.RegisterObject(d): ilg.Emit(OpCodes.Call, MemberInfos.Driver_RegisterObject); ilg.Emit(OpCodes.Ret); })); }
/// <summary> /// Returns a native function pointer to a stub method that returns a /// reference to the given value (boxing value types as necessary). /// </summary> /// <remarks> /// The returned function pointer should be freed with 'FreeDotNetFunPtr'. /// </remarks> public static IntPtr GenerateBoxStub(Type typeToBox) { // Signature of the stub method returned (as a delegate) by this function DelegateSignature methodSignature = new DelegateSignature( typeof(Int32), new Type[] { ConvertToStubType(typeToBox) }); return(GenerateDynamicMethod("box_" + typeToBox.Name, methodSignature, delegate(ILGenerator ilg) { // Load the (unboxed) value EmitParameterLoading(ilg, 0, typeToBox); if (typeToBox.IsValueType) { // Box the type value to as an object ilg.Emit(OpCodes.Box, typeToBox); } // Marshal the object instance out as an object index EmitToStub(ilg, typeof(object)); ilg.Emit(OpCodes.Ret); })); }
/// <summary> /// Generates a dynamic method of the given name and signature, containing the instructions /// produced by 'ilWriter'. A delegate to the method, is returned to the caller as a native /// function pointer. /// </summary> /// <remarks> /// This method also writes the method to the 'Stubs' class in 'Dynamic.dll' for debugging /// purposes. /// </remarks> private static IntPtr GenerateDynamicMethod(string methodName, DelegateSignature methodSignature, ILWriterDelegate ilWriter) { if (true) { // Optional: generate an implementation of the stub method inside the 'Stubs' // class (which is saved to 'Dynamic.dll') for debugging purposes. MethodBuilder savedMethod = _stubsTypeBuilder.DefineMethod(methodName, MethodAttributes.Public, methodSignature.ReturnType, methodSignature.ParameterTypes); ilWriter(savedMethod.GetILGenerator()); } // Generate a dynamic method of the given name and signature, and the // IL instructions given by 'ilWriter', then return a delegate to the // method as a function pointer. // [stubReturnType] [classType]_[methodname]([classType] this, [args...]): DynamicMethod method = new DynamicMethod(methodName, methodSignature.ReturnType, methodSignature.ParameterTypes, typeof(Driver)); ilWriter(method.GetILGenerator()); return(GetDotNetFunPtrForDelegate(method.CreateDelegate(methodSignature.ToDelegateType()))); }
public static void Main(string[] argv) { DelegateSignature delegateSignature = new DelegateSignature(DelegateFunction); delegateSignature(); }
/// <summary> /// Creates (and returns the type of) a class that wraps a pointer to a /// Haskell function as a .NET delegate. The class ensures that the /// wrapper function pointer is freed when the delegate is no longer being /// used by .NET. It also performs any translation from .NET values to /// interop values (object references are converted to object identifiers). /// </summary> /// <param name="delegateType">Type of delegate produced by the wrapper</param> private static Type CreateDelegateWrapperType(string name, Type delegateType) { // Obtain the signature of the delegate being produced DelegateSignature delegateSignature = DelegateSignature.FromDelegateType(delegateType); // Obtain the delegate type of the associated thunk for calling into Haskell Type thunkDelegateType = new DelegateSignature( ConvertToStubType(delegateSignature.ReturnType), ConvertToStubTypes(delegateSignature.ParameterTypes)).ToDelegateType(); TypeBuilder typeBuilder = _dynamicModuleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Sealed); // Define the _thunkDelegate field FieldBuilder thunkDelegateField = typeBuilder.DefineField("_thunkDelegate", thunkDelegateType, FieldAttributes.Private); { // Define the constructor for the wrapper type: // // public DelegateWrapper(IntPtr funPtrToWrap) // { // _thunkDelegate = (ThunkDelegate) // Marshal.GetDelegateForFunctionPointer( // funPtrToWrap, typeof(ThunkDelegate)); // } ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(IntPtr) }); ILGenerator ilg = constructorBuilder.GetILGenerator(); // Call Object's constructor ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Call, MemberInfos.Object_ctor); ilg.Emit(OpCodes.Ldarg_0); // Load this (for the 'stfld' below) ilg.Emit(OpCodes.Ldarg_1); // Load funPtrToWrap ilg.Emit(OpCodes.Ldtoken, thunkDelegateType); // Load typeof(ThunkDelegate) ilg.Emit(OpCodes.Call, MemberInfos.Type_GetTypeFromHandle); // Call (ThunkDelegate)Marshal.GetDelegateForFunctionPointer( // funPtrToWrap, typeof(ThunkDelegate)) ilg.Emit(OpCodes.Call, MemberInfos.Marshal_GetDelegateForFunctionPointer); ilg.Emit(OpCodes.Castclass, thunkDelegateType); // Store in _thunkDelegate ilg.Emit(OpCodes.Stfld, thunkDelegateField); ilg.Emit(OpCodes.Ret); } { // Define a Finalize method for the wrapper class: // // ~Delegate() // { // if (Driver.FreeHaskellFunPtr != null) // Driver.FreeHaskellFunPtr(Marshal.GetFunctionPointerForDelegate( // _thunkDelegate)); // } MethodBuilder finalizeMethod = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual); finalizeMethod.SetImplementationFlags(MethodImplAttributes.IL | MethodImplAttributes.Managed); ILGenerator ilg = finalizeMethod.GetILGenerator(); Label endLabel = ilg.DefineLabel(); // Obtain the freeHaskellFunPtr delegate ilg.Emit(OpCodes.Ldsfld, MemberInfos.Driver_FreeHaskellFunPtr); // Return immediately if the delegate is null ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Beq, endLabel); // Obtain the freeHaskellFunPtr delegate (again) ilg.Emit(OpCodes.Ldsfld, MemberInfos.Driver_FreeHaskellFunPtr); // Load _thunkDelegate ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Ldfld, thunkDelegateField); // Call Marshal.GetFunctionPointerForDelegate to obtain the original function pointerusing ilg.Emit(OpCodes.Call, MemberInfos.Marshal_GetFunctionPointerForDelegate); // Invoke freeHaskellFunPtr on this function pointer ilg.Emit(OpCodes.Call, MemberInfos.FreeHaskellFunPtrDelegate_Invoke); ilg.MarkLabel(endLabel); ilg.Emit(OpCodes.Ret); } { // Define an Invoke method that calls _thunkDelegate after marshaling // the arguments as necessary: // // private void Invoke(...) // { // _thunkDelegate(... using RegisterObject as appropriate ...); // } MethodBuilder invokeMethod = typeBuilder.DefineMethod("Invoke", MethodAttributes.Public, delegateSignature.ReturnType, delegateSignature.ParameterTypes); ILGenerator ilg = invokeMethod.GetILGenerator(); // Load _thunkDelegate (for calling it later) ilg.Emit(OpCodes.Ldarg_0); ilg.Emit(OpCodes.Ldfld, thunkDelegateField); // Load the parameters (and marshal according to type) for (int i = 0; i < delegateSignature.ParameterTypes.Length; i++) { Util.EmitLdarg(ilg, i + 1); EmitToStub(ilg, delegateSignature.ParameterTypes[i]); } ilg.Emit(OpCodes.Callvirt, thunkDelegateType.GetMethod("Invoke")); EmitFromStub(ilg, delegateSignature.ReturnType); ilg.Emit(OpCodes.Ret); } return(typeBuilder.CreateType()); }
public static void Main() { DelegateSignature delegateSignature = new DelegateSignature(DelegateFunction); delegateSignature(); }