Merge pull request #2964 from ludovic-henry/sgen-monocontext
[mono.git] / mcs / class / referencesource / System.Web / Util / ArglessEventHandlerProxy.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="ArglessEventHandlerProxy.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Util {
8     using System;
9     using System.Reflection;
10     using System.Reflection.Emit;
11     using System.Security.Permissions;
12     using System.Security;
13
14 /*
15  * Proxy that provides EventHandler and redirects it to arg-less method on the given object
16  */
17     internal class ArglessEventHandlerProxy {
18         private Object _target;
19         private MethodInfo _arglessMethod;
20
21         internal ArglessEventHandlerProxy(Object target, MethodInfo arglessMethod) {
22             Debug.Assert(arglessMethod.GetParameters().Length == 0);
23
24             _target = target;
25             _arglessMethod = arglessMethod;
26         }
27
28         [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.RestrictedMemberAccess)]
29         internal void Callback(Object sender, EventArgs e) {
30             _arglessMethod.Invoke(_target, new Object[0]);
31         }
32
33         internal EventHandler Handler {
34             get {
35                 return new EventHandler(Callback);
36             }
37         }
38     }
39
40     internal delegate void VoidMethod();
41
42     internal class CalliEventHandlerDelegateProxy {
43         private delegate void ParameterlessDelegate();
44         private delegate void ParameterfulDelegate(object sender, EventArgs e);
45
46         private IntPtr _functionPointer;
47         private Object _target;
48         private bool _argless;
49
50         internal CalliEventHandlerDelegateProxy(Object target, IntPtr functionPointer, bool argless) {
51             _argless = argless;
52             _target = target;
53             _functionPointer = functionPointer;
54         }
55
56         internal void Callback(Object sender, EventArgs e) {
57             if (_argless) {
58                 ParameterlessDelegate del = FastDelegateCreator<ParameterlessDelegate>.BindTo(_target, _functionPointer);
59                 del();
60             }
61             else {
62                 ParameterfulDelegate del = FastDelegateCreator<ParameterfulDelegate>.BindTo(_target, _functionPointer);
63                 del(sender, e);
64             }
65         }
66
67         internal EventHandler Handler {
68             get {
69                 return new EventHandler(Callback);
70             }
71         }
72     }
73
74 #if LCG_Implementation
75     internal delegate void ArglessMethod(IntPtr methodPtr, Object target);
76     internal delegate void EventArgMethod(IntPtr methodPtr, Object target, Object source, EventArgs e);
77
78     internal class CalliHelper {
79         internal static ArglessMethod ArglessFunctionCaller;
80         internal static EventArgMethod EventArgFunctionCaller;
81
82         // Make sure we have reflection permission to use ReflectionEmit and access method
83         [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.ReflectionEmit | ReflectionPermissionFlag.MemberAccess)]
84         static CalliHelper() {
85             // generate void(void) calli
86             DynamicMethod dm = new DynamicMethod("void_calli",
87                                                     typeof(void),
88                                                     new Type[] { typeof(IntPtr) /* function ptr */, typeof(Object) /* target */},
89                                                     typeof(CalliHelper).Module);
90             ILGenerator ilg = dm.GetILGenerator();
91
92             ilg.Emit(OpCodes.Ldarg_1);
93             ilg.Emit(OpCodes.Ldarg_0);
94             ilg.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, typeof(void), new Type[0], null);
95             ilg.Emit(OpCodes.Ret);
96             ArglessFunctionCaller = (ArglessMethod)dm.CreateDelegate(typeof(ArglessMethod));
97
98             // generate void(Object, EventArgs) calli
99             dm = new DynamicMethod("eventarg_calli",
100                                     typeof(void),
101                                     new Type[] { typeof(IntPtr) /* function ptr */, typeof(Object) /* target */, typeof(Object) /* sender */, typeof(EventArgs) },
102                                     typeof(CalliHelper).Module);
103             ilg = dm.GetILGenerator();
104
105             ilg.Emit(OpCodes.Ldarg_1);
106             ilg.Emit(OpCodes.Ldarg_2);
107             ilg.Emit(OpCodes.Ldarg_3);
108             ilg.Emit(OpCodes.Ldarg_0);
109             ilg.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, typeof(void), new Type[] { typeof(object) /* sender */, typeof(EventArgs) }, null);
110             ilg.Emit(OpCodes.Ret);
111             EventArgFunctionCaller = (EventArgMethod)dm.CreateDelegate(typeof(EventArgMethod));
112         }
113     }
114 #endif //LCG_Implementation
115
116 #if  Reflection_Emit_Implementation
117     internal delegate void ArglessMethod(IntPtr methodPtr, Object target);
118     internal delegate void EventArgMethod(IntPtr methodPtr, Object target, Object source, EventArgs e);
119
120     internal class CalliHelper {
121
122         internal static ArglessMethod ArglessFunctionCaller;
123         internal static EventArgMethod EventArgFunctionCaller;
124
125         // Make sure we have reflection permission to use ReflectionEmit and access method
126         [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.ReflectionEmit | ReflectionPermissionFlag.MemberAccess)]
127         static CalliHelper() {
128
129             AssemblyName an = new AssemblyName("CalliHelper");
130             AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
131             ModuleBuilder mb = ab.DefineDynamicModule("CalliHelper.dll");
132
133             ConstructorInfo ci = typeof(CLSCompliantAttribute).GetConstructor(new Type[] { typeof(bool) });
134             CustomAttributeBuilder cb = new CustomAttributeBuilder(ci, new object[] { true });
135             mb.SetCustomAttribute(cb);
136
137             TypeBuilder tb = mb.DefineType("System.Web.Util.CalliHelper", TypeAttributes.NotPublic | TypeAttributes.Sealed);
138             MethodBuilder methb = tb.DefineMethod("EventArgMethod", MethodAttributes.Assembly | MethodAttributes.Static, typeof(void), new Type[] { typeof(IntPtr), typeof(object), typeof(object), typeof(EventArgs) });
139             ILGenerator ilg = methb.GetILGenerator();
140
141             ilg.Emit(OpCodes.Ldarg_1);
142             ilg.Emit(OpCodes.Ldarg_2);
143             ilg.Emit(OpCodes.Ldarg_3);
144             ilg.Emit(OpCodes.Ldarg_0);
145             ilg.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, typeof(void), new Type[] { typeof(object), typeof(EventArgs) }, null);
146             ilg.Emit(OpCodes.Ret);
147
148             methb = tb.DefineMethod("ArglessMethod", MethodAttributes.Assembly | MethodAttributes.Static, typeof(void), new Type[] { typeof (IntPtr), typeof(object) });
149             ilg = methb.GetILGenerator();
150
151             ilg.Emit(OpCodes.Ldarg_1);
152             ilg.Emit(OpCodes.Ldarg_0);
153             ilg.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, typeof(void), new Type[0], null);
154             ilg.Emit(OpCodes.Ret);
155
156             Type t = tb.CreateType();
157             ArglessFunctionCaller = (ArglessMethod)Delegate.CreateDelegate(typeof(ArglessMethod), t, "ArglessMethod", true);
158             EventArgFunctionCaller = (EventArgMethod)Delegate.CreateDelegate(typeof(EventArgMethod), t, "EventArgMethod", true);
159
160             //ab.Save("CalliHelper.dll");
161         }
162     }
163 #endif // Reflection_Emit_Implementation
164 }