1 //
2 // System.Reflection.Emit.DynamicMethod.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //   Zoltan Varga (vargaz@freemail.hu)
7 //
8 // (C) 2003 Ximian, Inc.  http://www.ximian.com
9 //
10 
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
34 #if !FULL_AOT_RUNTIME
35 
36 using System;
37 using System.Reflection;
38 using System.Reflection.Emit;
39 using System.Globalization;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42 
43 namespace System.Reflection.Emit {
44 
45 	[ComVisible (true)]
46 	[StructLayout (LayoutKind.Sequential)]
47 	public sealed class DynamicMethod : MethodInfo {
48 
49 #pragma warning disable 169, 414, 649
50 		#region Sync with reflection.h
51 		private RuntimeMethodHandle mhandle;
52 		private string name;
53 		private Type returnType;
54 		private Type[] parameters;
55 		private MethodAttributes attributes;
56 		private CallingConventions callingConvention;
57 		private Module module;
58 		private bool skipVisibility;
59 		private bool init_locals = true;
60 		private ILGenerator ilgen;
61 		private int nrefs;
62 		private object[] refs;
63 		private IntPtr referenced_by;
64 		private Type owner;
65 		#endregion
66 #pragma warning restore 169, 414, 649
67 
68 		private Delegate deleg;
69 		private MonoMethod method;
70 		private ParameterBuilder[] pinfo;
71 		internal bool creating;
72 		private DynamicILInfo il_info;
73 
DynamicMethod(string name, Type returnType, Type[] parameterTypes, Module m)74 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m) : this (name, returnType, parameterTypes, m, false) {
75 		}
76 
DynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner)77 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner) : this (name, returnType, parameterTypes, owner, false) {
78 		}
79 
DynamicMethod(string name, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility)80 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, m, skipVisibility) {
81 		}
82 
DynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility)83 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, owner, skipVisibility) {
84 		}
85 
DynamicMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility)86 		public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, attributes, callingConvention, returnType, parameterTypes, owner, owner.Module, skipVisibility, false) {
87 		}
88 
DynamicMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility)89 		public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) : this (name, attributes, callingConvention, returnType, parameterTypes, null, m, skipVisibility, false) {
90 		}
91 
DynamicMethod(string name, Type returnType, Type[] parameterTypes)92 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes) : this (name, returnType, parameterTypes, false) {
93 		}
94 
95 		[MonoTODO ("Visibility is not restricted")]
DynamicMethod(string name, Type returnType, Type[] parameterTypes, bool restrictedSkipVisibility)96 		public DynamicMethod (string name, Type returnType, Type[] parameterTypes, bool restrictedSkipVisibility)
97 			: this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, null, null, restrictedSkipVisibility, true)
98 		{
99 		}
100 
DynamicMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type [] parameterTypes, Type owner, Module m, bool skipVisibility, bool anonHosted)101 		DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type [] parameterTypes, Type owner, Module m, bool skipVisibility, bool anonHosted)
102 		{
103 			if (name == null)
104 				throw new ArgumentNullException ("name");
105 			if (returnType == null)
106 				returnType = typeof (void);
107 			if ((m == null) && !anonHosted)
108 				throw new ArgumentNullException ("m");
109 			if (returnType.IsByRef)
110 				throw new ArgumentException ("Return type can't be a byref type", "returnType");
111 			if (parameterTypes != null) {
112 				for (int i = 0; i < parameterTypes.Length; ++i)
113 					if (parameterTypes [i] == null)
114 						throw new ArgumentException ("Parameter " + i + " is null", "parameterTypes");
115 			}
116 			if (owner != null && (owner.IsArray || owner.IsInterface)) {
117 				throw new ArgumentException ("Owner can't be an array or an interface.");
118 			}
119 
120 			if (m == null)
121 				m = AnonHostModuleHolder.AnonHostModule;
122 
123 			this.name = name;
124 			this.attributes = attributes | MethodAttributes.Static;
125 			this.callingConvention = callingConvention;
126 			this.returnType = returnType;
127 			this.parameters = parameterTypes;
128 			this.owner = owner;
129 			this.module = m;
130 			this.skipVisibility = skipVisibility;
131 		}
132 
133 		[MethodImplAttribute(MethodImplOptions.InternalCall)]
create_dynamic_method(DynamicMethod m)134 		private static extern void create_dynamic_method (DynamicMethod m);
135 
CreateDynMethod()136 		private void CreateDynMethod () {
137 			if (mhandle.Value == IntPtr.Zero) {
138 				if (ilgen == null || ilgen.ILOffset == 0)
139 					throw new InvalidOperationException ("Method '" + name + "' does not have a method body.");
140 
141 				ilgen.label_fixup (this);
142 
143 				// Have to create all DynamicMethods referenced by this one
144 				try {
145 					// Used to avoid cycles
146 					creating = true;
147 					if (refs != null) {
148 						for (int i = 0; i < refs.Length; ++i) {
149 							if (refs [i] is DynamicMethod) {
150 								DynamicMethod m = (DynamicMethod)refs [i];
151 								if (!m.creating)
152 									m.CreateDynMethod ();
153 							}
154 						}
155 					}
156 				} finally {
157 					creating = false;
158 				}
159 
160 				create_dynamic_method (this);
161 			}
162 		}
163 
164 		[ComVisible (true)]
165 		sealed override
CreateDelegate(Type delegateType)166 		public Delegate CreateDelegate (Type delegateType)
167 		{
168 			if (delegateType == null)
169 				throw new ArgumentNullException ("delegateType");
170 			if (deleg != null)
171 				return deleg;
172 
173 			CreateDynMethod ();
174 
175 			deleg = Delegate.CreateDelegate (delegateType, this);
176 			return deleg;
177 		}
178 
179 		[ComVisible (true)]
180 		sealed override
CreateDelegate(Type delegateType, object target)181 		public Delegate CreateDelegate (Type delegateType, object target)
182 		{
183 			if (delegateType == null)
184 				throw new ArgumentNullException ("delegateType");
185 
186 			CreateDynMethod ();
187 
188 			/* Can't cache the delegate since it is different for each target */
189 			return Delegate.CreateDelegate (delegateType, target, this);
190 		}
191 
DefineParameter(int position, ParameterAttributes attributes, string parameterName)192 		public ParameterBuilder DefineParameter (int position, ParameterAttributes attributes, string parameterName)
193 		{
194 			//
195 			// Extension: Mono allows position == 0 for the return attribute
196 			//
197 			if ((position < 0) || (position > parameters.Length))
198 				throw new ArgumentOutOfRangeException ("position");
199 
200 			RejectIfCreated ();
201 
202 			ParameterBuilder pb = new ParameterBuilder (this, position, attributes, parameterName);
203 			if (pinfo == null)
204 				pinfo = new ParameterBuilder [parameters.Length + 1];
205 			pinfo [position] = pb;
206 			return pb;
207 		}
208 
GetBaseDefinition()209 		public override MethodInfo GetBaseDefinition () {
210 			return this;
211 		}
212 
GetCustomAttributes(bool inherit)213 		public override object[] GetCustomAttributes (bool inherit) {
214 			// support for MethodImplAttribute PCA
215 			return new Object[] { new MethodImplAttribute(GetMethodImplementationFlags()) };
216 		}
217 
GetCustomAttributes(Type attributeType, bool inherit)218 		public override object[] GetCustomAttributes (Type attributeType,
219 							      bool inherit) {
220 			if (attributeType == null)
221 				throw new ArgumentNullException ("attributeType");
222 
223 			if (attributeType.IsAssignableFrom (typeof (MethodImplAttribute)))
224 				return new Object[] { new MethodImplAttribute (GetMethodImplementationFlags()) };
225 			else
226 				return EmptyArray<Object>.Value;
227 		}
228 
GetDynamicILInfo()229 		public DynamicILInfo GetDynamicILInfo () {
230 			if (il_info == null)
231 				il_info = new DynamicILInfo (this);
232 			return il_info;
233 		}
234 
GetILGenerator()235 		public ILGenerator GetILGenerator () {
236 			return GetILGenerator (64);
237 		}
238 
GetILGenerator(int streamSize)239 		public ILGenerator GetILGenerator (int streamSize) {
240 			if (((GetMethodImplementationFlags () & MethodImplAttributes.CodeTypeMask) !=
241 				 MethodImplAttributes.IL) ||
242 				((GetMethodImplementationFlags () & MethodImplAttributes.ManagedMask) !=
243 				 MethodImplAttributes.Managed))
244 				throw new InvalidOperationException ("Method body should not exist.");
245 			if (ilgen != null)
246 				return ilgen;
247 			ilgen = new ILGenerator (Module, new DynamicMethodTokenGenerator (this), streamSize);
248 			return ilgen;
249 		}
250 
GetMethodImplementationFlags()251 		public override MethodImplAttributes GetMethodImplementationFlags () {
252 			return MethodImplAttributes.IL | MethodImplAttributes.Managed | MethodImplAttributes.NoInlining;
253 		}
254 
GetParameters()255 		public override ParameterInfo[] GetParameters ()
256 		{
257 			return GetParametersInternal ();
258 		}
259 
GetParametersInternal()260 		internal override ParameterInfo[] GetParametersInternal ()
261 		{
262 			if (parameters == null)
263 				return EmptyArray<ParameterInfo>.Value;
264 
265 			ParameterInfo[] retval = new ParameterInfo [parameters.Length];
266 			for (int i = 0; i < parameters.Length; i++) {
267 				retval [i] = ParameterInfo.New (pinfo == null ? null : pinfo [i + 1], parameters [i], this, i + 1);
268 			}
269 			return retval;
270 		}
271 
GetParametersCount()272 		internal override int GetParametersCount ()
273 		{
274 			return parameters == null ? 0 : parameters.Length;
275 		}
276 
GetParameterType(int pos)277 		internal override Type GetParameterType (int pos) {
278 			return parameters [pos];
279 		}
280 
281 		/*
282 		public override object Invoke (object obj, object[] parameters) {
283 			CreateDynMethod ();
284 			if (method == null)
285 				method = new MonoMethod (mhandle);
286 			return method.Invoke (obj, parameters);
287 		}
288 		*/
289 
Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)290 		public override object Invoke (object obj, BindingFlags invokeAttr,
291 									   Binder binder, object[] parameters,
292 									   CultureInfo culture)
293 		{
294 			try {
295 				CreateDynMethod ();
296 				if (method == null)
297 					method = new MonoMethod (mhandle);
298 
299 				return method.Invoke (obj, parameters);
300 			}
301 			catch (MethodAccessException mae) {
302 				throw new TargetInvocationException ("Method cannot be invoked.", mae);
303 			}
304 		}
305 
IsDefined(Type attributeType, bool inherit)306 		public override bool IsDefined (Type attributeType, bool inherit) {
307 			if (attributeType == null)
308 				throw new ArgumentNullException ("attributeType");
309 
310 			if (attributeType.IsAssignableFrom (typeof (MethodImplAttribute)))
311 				return true;
312 			else
313 				return false;
314 		}
315 
ToString()316 		public override string ToString () {
317 			string parms = String.Empty;
318 			ParameterInfo[] p = GetParametersInternal ();
319 			for (int i = 0; i < p.Length; ++i) {
320 				if (i > 0)
321 					parms = parms + ", ";
322 				parms = parms + p [i].ParameterType.Name;
323 			}
324 			return ReturnType.Name+" "+Name+"("+parms+")";
325 		}
326 
327 		public override MethodAttributes Attributes {
328 			get {
329 				return attributes;
330 			}
331 		}
332 
333 		public override CallingConventions CallingConvention {
334 			get {
335 				return callingConvention;
336 			}
337 		}
338 
339 		public override Type DeclaringType {
340 			get {
341 				return null;
342 			}
343 		}
344 
345 		public bool InitLocals {
346 			get {
347 				return init_locals;
348 			}
349 			set {
350 				init_locals = value;
351 			}
352 		}
353 
354 		public override RuntimeMethodHandle MethodHandle {
355 			get {
356 				return mhandle;
357 			}
358 		}
359 
360 		public override Module Module {
361 			get {
362 				return module;
363 			}
364 		}
365 
366 		public override string Name {
367 			get {
368 				return name;
369 			}
370 		}
371 
372 		public override Type ReflectedType {
373 			get {
374 				return null;
375 			}
376 		}
377 
378 		[MonoTODO("Not implemented")]
379 		public override ParameterInfo ReturnParameter {
380 			get {
381 				throw new NotImplementedException ();
382 			}
383 		}
384 
385 		public override Type ReturnType {
386 			get {
387 				return returnType;
388 			}
389 		}
390 
391 		[MonoTODO("Not implemented")]
392 		public override ICustomAttributeProvider ReturnTypeCustomAttributes {
393 			get {
394 				throw new NotImplementedException ();
395 			}
396 		}
397 
398 /*
399 		public override int MetadataToken {
400 			get {
401 				return 0;
402 			}
403 		}
404 */
405 
RejectIfCreated()406 		private void RejectIfCreated () {
407 			if (mhandle.Value != IntPtr.Zero)
408 				throw new InvalidOperationException ("Type definition of the method is complete.");
409 		}
410 
AddRef(object reference)411 		internal int AddRef (object reference) {
412 			if (refs == null)
413 				refs = new object [4];
414 			if (nrefs >= refs.Length - 1) {
415 				object [] new_refs = new object [refs.Length * 2];
416 				System.Array.Copy (refs, new_refs, refs.Length);
417 				refs = new_refs;
418 			}
419 			refs [nrefs] = reference;
420 			/* Reserved by the runtime */
421 			refs [nrefs + 1] = null;
422 			nrefs += 2;
423 			return nrefs - 1;
424 		}
425 
426 		// This class takes care of constructing the module in a thread safe manner
427 		class AnonHostModuleHolder {
428 			public static Module anon_host_module;
429 
AnonHostModuleHolder()430 			static AnonHostModuleHolder () {
431 				AssemblyName aname = new AssemblyName ();
432 				aname.Name = "Anonymously Hosted DynamicMethods Assembly";
433 				AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
434 
435 				anon_host_module = ab.GetManifestModule ();
436 			}
437 
438 			public static Module AnonHostModule {
439 				get {
440 					return anon_host_module;
441 				}
442 			}
443 		}
444 	}
445 
446 	internal class DynamicMethodTokenGenerator : TokenGenerator {
447 
448 		private DynamicMethod m;
449 
DynamicMethodTokenGenerator(DynamicMethod m)450 		public DynamicMethodTokenGenerator (DynamicMethod m) {
451 			this.m = m;
452 		}
453 
GetToken(string str)454 		public int GetToken (string str) {
455 			return m.AddRef (str);
456 		}
457 
GetToken(MethodBase method, Type[] opt_param_types)458 		public int GetToken (MethodBase method, Type[] opt_param_types) {
459 			throw new InvalidOperationException ();
460 		}
461 
GetToken(MemberInfo member, bool create_open_instance)462 		public int GetToken (MemberInfo member, bool create_open_instance) {
463 			return m.AddRef (member);
464 		}
465 
GetToken(SignatureHelper helper)466 		public int GetToken (SignatureHelper helper) {
467 			return m.AddRef (helper);
468 		}
469 	}
470 }
471 
472 #endif
473