From ed0031b621c6cf8824a9a3e588426907244aeb7e Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 18 Apr 2006 01:38:08 +0000 Subject: implemented class-based method management very fast native-to-managed transition most of the logic transferred to the CLR side svn path=/trunk/externals/clr/; revision=4931 --- PureData/DynamicMethod.cs | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 PureData/DynamicMethod.cs (limited to 'PureData/DynamicMethod.cs') diff --git a/PureData/DynamicMethod.cs b/PureData/DynamicMethod.cs new file mode 100644 index 0000000..749bb1a --- /dev/null +++ b/PureData/DynamicMethod.cs @@ -0,0 +1,101 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace PureData +{ + public delegate void DynamicMethodBang(External target); + public delegate void DynamicMethodFloat(External target,float f); + public delegate void DynamicMethodSymbol(External target,Symbol s); + public delegate void DynamicMethodPointer(External target,Pointer p); + public delegate void DynamicMethodList(External target,Atom[] l); + public delegate void DynamicMethodAnything(External target,int i,Symbol s,Atom[] l); + public delegate void DynamicMethodObject(External target,int i,object o); + + class DynamicMethods + { + private static Delegate CreateIntern(Delegate del, Type dyntype) + { + MethodInfo dynmethod = dyntype.GetMethod("Invoke"); + ParameterInfo[] dynparms = dynmethod.GetParameters(); + MethodInfo method = del.Method; + +#if DEBUG + if (dynmethod.ReturnType != typeof(void)) throw new ArgumentException("Return type must be void"); + + ParameterInfo[] parms = method.GetParameters(); + int numparms = parms.Length; + + if (dynparms.Length != numparms + 1) throw new ArgumentException("Number of parameters don't match"); + + for (int i = 0; i < numparms; ++i) + if (dynparms[i + 1].ParameterType != parms[i].ParameterType) throw new ArgumentException("Parameter types don't match"); +#endif + + Type[] argtypes = new Type[dynparms.Length]; + for (int i = 0; i < dynparms.Length; ++i) + argtypes[i] = dynparms[i].ParameterType; + + // Create dynamic method and obtain its IL generator to inject code. + DynamicMethod dynam = new DynamicMethod("dummy", typeof(void), argtypes, typeof(DynamicMethods)); + ILGenerator il = dynam.GetILGenerator(); + + #region IL Code generation + // If method isn't static push target instance on top of stack. + if (!method.IsStatic) + // Argument 0 of dynamic method is target instance. + il.Emit(OpCodes.Ldarg_0); + + // Push parameters onto the stack + for (int i = 0; i < dynparms.Length - 1; ++i) + il.Emit(OpCodes.Ldarg, i + 1); + + // Perform actual call. + // If method is not final a callvirt is required otherwise a normal call will be emitted. + il.Emit(method.IsFinal ? OpCodes.Call : OpCodes.Callvirt, method); + + // Emit return opcode. + il.Emit(OpCodes.Ret); + #endregion + + return dynam.CreateDelegate(dyntype); + } + + #region Specialized DynamicMethod makers + public static DynamicMethodBang Create(Public.MethodBang method) + { + return (DynamicMethodBang)CreateIntern(method, typeof(DynamicMethodBang)); + } + + public static DynamicMethodFloat Create(Public.MethodFloat method) + { + return (DynamicMethodFloat)CreateIntern(method,typeof(DynamicMethodFloat)); + } + + public static DynamicMethodSymbol Create(Public.MethodSymbol method) + { + return (DynamicMethodSymbol)CreateIntern(method,typeof(DynamicMethodSymbol)); + } + + public static DynamicMethodPointer Create(Public.MethodPointer method) + { + return (DynamicMethodPointer)CreateIntern(method,typeof(DynamicMethodPointer)); + } + + public static DynamicMethodList Create(Public.MethodList method) + { + return (DynamicMethodList)CreateIntern(method,typeof(DynamicMethodList)); + } + + public static DynamicMethodAnything Create(Public.MethodAnything method) + { + return (DynamicMethodAnything)CreateIntern(method,typeof(DynamicMethodAnything)); + } + + public static DynamicMethodObject Create(Public.MethodObject method) + { + return (DynamicMethodObject)CreateIntern(method, typeof(DynamicMethodObject)); + } + #endregion + } +} -- cgit v1.2.1