1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
}
}
|