2 // DynamicMethodTest.cs - NUnit Test Cases for the DynamicMethod class
4 // Gert Driesen (drieseng@users.sourceforge.net)
11 using System.Reflection;
12 using System.Reflection.Emit;
13 using System.Runtime.InteropServices;
14 using System.Runtime.CompilerServices;
16 using System.Diagnostics;
17 using System.Runtime.ExceptionServices;
20 using NUnit.Framework;
22 namespace MonoTests.System.Reflection.Emit
25 public class DynamicMethodTest
27 private delegate int HelloInvoker (string msg);
30 public void Constructor1_Name_Null ()
33 new DynamicMethod (null,
35 new Type[] { typeof (string) },
36 typeof (DynamicMethodTest).Module);
38 } catch (ArgumentNullException ex) {
39 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
40 Assert.AreEqual ("name", ex.ParamName, "#3");
41 Assert.IsNull (ex.InnerException, "#4");
46 public void Constructor2_Name_Null ()
49 new DynamicMethod (null,
51 new Type[] { typeof (string) },
52 typeof (DynamicMethodTest));
54 } catch (ArgumentNullException ex) {
55 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
56 Assert.AreEqual ("name", ex.ParamName, "#3");
57 Assert.IsNull (ex.InnerException, "#4");
62 public void Constructor3_Name_Null ()
65 new DynamicMethod (null,
67 new Type[] { typeof (string) },
68 typeof (DynamicMethodTest).Module, true);
70 } catch (ArgumentNullException ex) {
71 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
72 Assert.AreEqual ("name", ex.ParamName, "#3");
73 Assert.IsNull (ex.InnerException, "#4");
78 public void Constructor4_Name_Null ()
81 new DynamicMethod (null,
83 new Type[] { typeof (string) },
84 typeof (DynamicMethodTest), true);
86 } catch (ArgumentNullException ex) {
87 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
88 Assert.AreEqual ("name", ex.ParamName, "#3");
89 Assert.IsNull (ex.InnerException, "#4");
94 public void Constructor5_Name_Null ()
97 new DynamicMethod (null,
98 MethodAttributes.Public | MethodAttributes.Static,
99 CallingConventions.Standard,
101 new Type[] { typeof (string) },
102 typeof (DynamicMethodTest).Module, true);
104 } catch (ArgumentNullException ex) {
105 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
106 Assert.AreEqual ("name", ex.ParamName, "#3");
107 Assert.IsNull (ex.InnerException, "#4");
112 public void Constructor6_Name_Null ()
115 new DynamicMethod (null,
116 MethodAttributes.Public | MethodAttributes.Static,
117 CallingConventions.Standard,
119 new Type[] { typeof (string) },
120 typeof (DynamicMethodTest), true);
122 } catch (ArgumentNullException ex) {
123 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
124 Assert.AreEqual ("name", ex.ParamName, "#3");
125 Assert.IsNull (ex.InnerException, "#4");
130 public void OwnerCantBeArray ()
132 TestOwner (typeof (int[]));
136 public void OwnerCantBeInterface ()
138 TestOwner (typeof (global::System.Collections.IEnumerable));
141 private void TestOwner (Type owner)
144 new DynamicMethod ("Name", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
145 typeof(void), new Type[] { }, owner, true);
146 Assert.Fail (string.Format ("Created dynamic method with owner being {0}.", owner));
147 } catch (ArgumentException) {
152 public void DynamicMethodReference ()
154 DynamicMethod hello = new DynamicMethod ("Hello",
156 new Type[] { typeof (string) },
157 typeof (DynamicMethodTest).Module);
158 Assert.IsNull (hello.DeclaringType, "#1");
160 DynamicMethod write = new DynamicMethod ("Write",
162 new Type[] { typeof (string) },
163 typeof (DynamicMethodTest));
164 Assert.IsNull (hello.DeclaringType, "#2");
166 MethodInfo invokeWrite = write.GetBaseDefinition ();
168 ILGenerator helloIL = hello.GetILGenerator ();
169 helloIL.Emit (OpCodes.Ldarg_0);
170 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
171 helloIL.Emit (OpCodes.Ret);
173 ILGenerator writeIL = write.GetILGenerator ();
174 writeIL.Emit (OpCodes.Ldc_I4_2);
175 writeIL.Emit (OpCodes.Ret);
178 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
179 int ret = hi ("Hello, World!");
180 Assert.AreEqual (2, ret, "#3");
182 object[] invokeArgs = { "Hello, World!" };
183 object objRet = hello.Invoke (null, invokeArgs);
184 Assert.AreEqual (2, objRet, "#4");
188 public void EmptyMethodBody ()
190 DynamicMethod hello = new DynamicMethod ("Hello",
192 new Type[] { typeof (string) },
193 typeof (DynamicMethodTest).Module);
194 object[] invokeArgs = { "Hello, World!" };
198 hello.Invoke (null, invokeArgs);
200 } catch (InvalidOperationException) {
204 hello.GetILGenerator ();
206 hello.Invoke (null, invokeArgs);
208 } catch (InvalidOperationException) {
212 private delegate string ReturnString (string msg);
213 private delegate void DoNothing (string msg);
215 private static string private_method (string s) {
220 public void SkipVisibility ()
222 DynamicMethod hello = new DynamicMethod ("Hello",
224 new Type[] { typeof (string) },
225 typeof (DynamicMethodTest).Module, true);
227 ILGenerator helloIL = hello.GetILGenerator ();
228 helloIL.Emit (OpCodes.Ldarg_0);
229 helloIL.EmitCall (OpCodes.Call, typeof (DynamicMethodTest).GetMethod ("private_method", BindingFlags.Static|BindingFlags.NonPublic), null);
230 helloIL.Emit (OpCodes.Ret);
233 (ReturnString) hello.CreateDelegate (typeof (ReturnString));
234 Assert.AreEqual ("ABCD", del ("ABCD"));
238 public void ReturnType_Null ()
240 DynamicMethod hello = new DynamicMethod ("Hello",
242 new Type[] { typeof (string) },
243 typeof (DynamicMethodTest).Module, true);
244 Assert.AreEqual (typeof (void), hello.ReturnType, "#1");
246 ILGenerator helloIL = hello.GetILGenerator ();
247 helloIL.Emit (OpCodes.Ret);
249 DoNothing dn = (DoNothing) hello.CreateDelegate (typeof (DoNothing));
252 object[] invokeArgs = { "Hello, World!" };
253 object objRet = hello.Invoke (null, invokeArgs);
254 Assert.IsNull (objRet, "#2");
258 public void Name_Empty ()
260 DynamicMethod hello = new DynamicMethod (string.Empty,
262 new Type[] { typeof (string) },
263 typeof (DynamicMethodTest).Module);
264 Assert.AreEqual (string.Empty, hello.Name, "#1");
266 DynamicMethod write = new DynamicMethod ("Write",
268 new Type[] { typeof (string) },
269 typeof (DynamicMethodTest));
271 MethodInfo invokeWrite = write.GetBaseDefinition ();
273 ILGenerator helloIL = hello.GetILGenerator ();
274 helloIL.Emit (OpCodes.Ldarg_0);
275 helloIL.EmitCall (OpCodes.Call, invokeWrite, null);
276 helloIL.Emit (OpCodes.Ret);
278 ILGenerator writeIL = write.GetILGenerator ();
279 writeIL.Emit (OpCodes.Ldc_I4_2);
280 writeIL.Emit (OpCodes.Ret);
283 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
284 int ret = hi ("Hello, World!");
285 Assert.AreEqual (2, ret, "#2");
287 object[] invokeArgs = { "Hello, World!" };
288 object objRet = hello.Invoke (null, invokeArgs);
289 Assert.AreEqual (2, objRet, "#3");
293 public void Circular_Refs () {
294 DynamicMethod m1 = new DynamicMethod("f1", typeof(int), new Type[] { typeof (int) },
296 DynamicMethod m2 = new DynamicMethod("f2", typeof(int), new Type[] { typeof (int) },
299 ILGenerator il1 = m1.GetILGenerator();
300 ILGenerator il2 = m2.GetILGenerator();
302 Label l = il1.DefineLabel ();
303 //il1.EmitWriteLine ("f1");
304 il1.Emit (OpCodes.Ldarg_0);
305 il1.Emit (OpCodes.Ldc_I4_0);
306 il1.Emit (OpCodes.Bne_Un, l);
307 il1.Emit (OpCodes.Ldarg_0);
308 il1.Emit (OpCodes.Ret);
310 il1.Emit (OpCodes.Ldarg_0);
311 il1.Emit (OpCodes.Ldc_I4_1);
312 il1.Emit (OpCodes.Sub);
313 il1.Emit (OpCodes.Call, m2);
314 il1.Emit (OpCodes.Ret);
316 //il2.EmitWriteLine("f2");
317 il2.Emit(OpCodes.Ldarg_0);
318 il2.Emit(OpCodes.Call, m1);
319 il2.Emit(OpCodes.Ret);
321 m1.Invoke(null, new object[] { 5 });
324 // Disabl known warning, the Field is never used directly from C#
325 #pragma warning disable 414
327 static string Field = "foo";
329 #pragma warning restore 414
331 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=297416
332 public void TestOwnerMemberAccess ()
334 DynamicMethod method = new DynamicMethod ("GetField",
335 typeof (string), new Type [0], typeof (Host));
337 ILGenerator il = method.GetILGenerator ();
338 il.Emit (OpCodes.Ldsfld, typeof (Host).GetField (
339 "Field", BindingFlags.Static | BindingFlags.NonPublic));
340 il.Emit (OpCodes.Ret);
342 string ret = (string) method.Invoke (null, new object [] {});
343 Assert.AreEqual ("foo", ret, "#1");
347 public void AnonHosted ()
349 DynamicMethod hello = new DynamicMethod ("Hello",
351 new Type[] { typeof (string) });
352 ILGenerator helloIL = hello.GetILGenerator ();
353 helloIL.Emit (OpCodes.Ldc_I4_2);
354 helloIL.Emit (OpCodes.Ret);
357 (HelloInvoker) hello.CreateDelegate (typeof (HelloInvoker));
358 int ret = hi ("Hello, World!");
359 Assert.AreEqual (2, ret);
361 object[] invokeArgs = { "Hello, World!" };
362 object objRet = hello.Invoke (null, invokeArgs);
363 Assert.AreEqual (2, objRet);
366 public delegate int IntInvoker();
368 public class Foo<T> {
369 public virtual int Test () { return 99; }
373 public void ConstrainedPrexixDoesntCrash () //bug #529238
375 Type foo = typeof (Foo<int>);
377 DynamicMethod dm = new DynamicMethod ("Hello", typeof (int), null);
378 ILGenerator ilgen = dm.GetILGenerator ();
379 ilgen.DeclareLocal (foo);
380 ilgen.Emit (OpCodes.Newobj, foo.GetConstructor (new Type [0]));
381 ilgen.Emit (OpCodes.Stloc_0);
382 ilgen.Emit (OpCodes.Ldloca_S, 0);
383 ilgen.Emit (OpCodes.Constrained, foo);
384 ilgen.Emit (OpCodes.Callvirt, foo.GetMethod ("Test"));
385 ilgen.Emit (OpCodes.Ret);
387 IntInvoker hi = (IntInvoker) dm.CreateDelegate (typeof (IntInvoker));
388 Assert.AreEqual (99, hi (), "#1");
393 public void Module_GetMethod () {
394 AssemblyName assemblyName = new AssemblyName ();
395 assemblyName.Name = "foo";
397 AssemblyBuilder assembly =
398 AppDomain.CurrentDomain.DefineDynamicAssembly (
399 assemblyName, AssemblyBuilderAccess.RunAndSave);
401 ModuleBuilder module = assembly.DefineDynamicModule ("foo.dll");
403 var d = new DynamicMethod ("foo", typeof (int), new Type [] { typeof (int[,]) }, module);
404 var ig = d.GetILGenerator ();
405 ig.Emit (OpCodes.Ldarg_0);
406 ig.Emit (OpCodes.Ldc_I4, 1);
407 ig.Emit (OpCodes.Ldc_I4, 1);
408 ig.Emit (OpCodes.Call, module.GetArrayMethod (typeof (int[,]), "Get", CallingConventions.Standard, typeof (int), new Type [] { typeof (int), typeof (int) }));
409 ig.Emit (OpCodes.Ret);
411 var del = (Func<int[,], int>)d.CreateDelegate (typeof (Func<int[,], int>));
412 int[,] arr = new int [10, 10];
414 Assert.AreEqual (5, del (arr));
418 [Category ("NotWorking")]
419 public void InvalidUnicodeName ()
421 var name = new StringBuilder ().Append ('\udf45').Append ('\ud808');
422 var method = new DynamicMethod (name.ToString (), typeof (bool), new Type [0]);
423 var il = method.GetILGenerator ();
424 il.Emit (OpCodes.Ldc_I4_1);
425 il.Emit (OpCodes.Ret);
427 var function = (Func<bool>) method.CreateDelegate (typeof (Func<bool>));
429 Assert.IsTrue (function ());
433 [ExpectedException (typeof (InvalidOperationException))]
434 public void GetMethodBody ()
436 var method = new DynamicMethod ("method", typeof (object), new Type [] { typeof (object) });
438 var il = method.GetILGenerator ();
439 il.Emit (OpCodes.Ldarg_0);
440 il.Emit (OpCodes.Ret);
442 var f = (Func<object, object>) method.CreateDelegate (typeof (Func<object, object>));
443 f.Method.GetMethodBody ();
447 public void GetCustomAttributes ()
449 var method = new DynamicMethod ("method", typeof (void), new Type [] { });
451 var methodImplAttrType = typeof (MethodImplAttribute);
452 Assert.IsTrue (method.IsDefined (methodImplAttrType, true), "MethodImplAttribute is defined");
454 // According to the spec, MethodImplAttribute is the
455 // only custom attr that's present on a DynamicMethod.
456 // And it's always a managed method with no inlining.
457 var a1 = method.GetCustomAttributes (true);
458 Assert.AreEqual (a1.Length, 1, "a1.Length == 1");
459 Assert.AreEqual (a1[0].GetType (), methodImplAttrType, "a1[0] is a MethodImplAttribute");
460 var options = (a1[0] as MethodImplAttribute).Value;
461 Assert.IsTrue ((options & MethodImplOptions.NoInlining) != 0, "NoInlining is set");
462 Assert.IsTrue ((options & MethodImplOptions.Unmanaged) == 0, "Unmanaged isn't set");
465 // any other custom attribute type
466 var extensionAttrType = typeof (ExtensionAttribute);
467 Assert.IsFalse (method.IsDefined (extensionAttrType, true));
468 Assert.AreEqual (Array.Empty<object>(), method.GetCustomAttributes (extensionAttrType, true));
471 public delegate object RetObj();
473 public void GetCurrentMethodWorksWithDynamicMethods ()
475 DynamicMethod dm = new DynamicMethod("Foo", typeof(object), null);
476 ILGenerator ilgen = dm.GetILGenerator();
477 ilgen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod"));
478 ilgen.Emit(OpCodes.Ret);
479 RetObj del = (RetObj)dm.CreateDelegate(typeof(RetObj));
480 MethodInfo res = (MethodInfo)del();
481 Assert.AreEqual (dm.Name, res.Name, "#1");
485 [StructLayout (LayoutKind.Explicit)]
486 struct SizeOfTarget {
487 [FieldOffset (0)] public int X;
488 [FieldOffset (4)] public int Y;
492 public void SizeOf ()
494 var method = new DynamicMethod ("", typeof (int), Type.EmptyTypes);
495 var il = method.GetILGenerator ();
496 il.Emit (OpCodes.Sizeof, typeof (SizeOfTarget));
497 il.Emit (OpCodes.Ret);
499 var func = (Func<int>) method.CreateDelegate (typeof (Func<int>));
500 var point_size = func ();
502 Assert.AreEqual (8, point_size);
505 class TypedRefTarget {
509 class ExceptionHandling_Test_Support
511 public static Exception Caught;
512 public static string CaughtStackTrace;
514 public static void ThrowMe ()
517 CaughtStackTrace = null;
518 throw new Exception("test");
521 public static void Handler (Exception e)
524 CaughtStackTrace = e.StackTrace.ToString ();
529 public void ExceptionHandling ()
531 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
532 var ig = method.GetILGenerator ();
534 ig.BeginExceptionBlock();
535 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("ThrowMe"));
537 ig.BeginCatchBlock(typeof(Exception));
538 ig.Emit(OpCodes.Call, typeof(ExceptionHandling_Test_Support).GetMethod("Handler"));
539 ig.EndExceptionBlock();
541 ig.Emit(OpCodes.Ret);
543 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
546 Assert.IsNotNull (ExceptionHandling_Test_Support.Caught, "#1");
548 var lines = ExceptionHandling_Test_Support.CaughtStackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.None);
549 lines = lines.Where (l => !l.StartsWith ("[")).ToArray ();
550 Assert.AreEqual (2, lines.Length, "#2");
552 var st = new StackTrace (ExceptionHandling_Test_Support.Caught, 0, true);
554 // Caught stack trace when dynamic method is gone
555 Assert.AreEqual (ExceptionHandling_Test_Support.CaughtStackTrace, st.ToString (), "#3");
557 // Catch handler stack trace inside dynamic method match
558 Assert.AreEqual (ExceptionHandling_Test_Support.Caught.StackTrace, st.ToString (), "#4");
561 class ExceptionHandlingWithExceptionDispatchInfo_Test_Support
563 public static Exception Caught;
564 public static string CaughtStackTrace;
566 public static void ThrowMe ()
569 CaughtStackTrace = null;
573 throw new Exception("test");
574 } catch (Exception e2) {
578 var edi = ExceptionDispatchInfo.Capture(e);
583 public static void Handler (Exception e)
585 var lines = e.StackTrace.Split (new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
587 lines = lines.Where (l => !l.StartsWith ("[")).ToArray ();
589 Assert.AreEqual (5, lines.Length, "#1");
590 Assert.IsTrue (lines [1].Contains ("---"), "#2");
595 public void ExceptionHandlingWithExceptionDispatchInfo ()
597 var method = new DynamicMethod ("", typeof(void), new[] { typeof(int) }, typeof (DynamicMethodTest));
598 var ig = method.GetILGenerator ();
600 ig.BeginExceptionBlock();
601 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("ThrowMe"));
603 ig.BeginCatchBlock(typeof(Exception));
604 ig.Emit(OpCodes.Call, typeof(ExceptionHandlingWithExceptionDispatchInfo_Test_Support).GetMethod("Handler"));
605 ig.EndExceptionBlock();
607 ig.Emit(OpCodes.Ret);
609 var invoke = (Action<int>) method.CreateDelegate (typeof(Action<int>));
616 public void TypedRef ()
618 var method = new DynamicMethod ("", typeof (TypedRefTarget), new [] {typeof (TypedRefTarget)}, true);
619 var il = method.GetILGenerator ();
620 var tr = il.DeclareLocal (typeof (TypedReference));
622 il.Emit (OpCodes.Ldarga, 0);
623 il.Emit (OpCodes.Mkrefany, typeof (TypedRefTarget));
624 il.Emit (OpCodes.Stloc, tr);
626 il.Emit (OpCodes.Ldloc, tr);
627 il.Emit (OpCodes.Call, GetType ().GetMethod ("AssertTypedRef", BindingFlags.NonPublic | BindingFlags.Static));
629 il.Emit (OpCodes.Ldloc, tr);
630 il.Emit (OpCodes.Refanyval, typeof (TypedRefTarget));
631 il.Emit (OpCodes.Ldobj, typeof (TypedRefTarget));
632 il.Emit (OpCodes.Ret);
634 var f = (Func<TypedRefTarget, TypedRefTarget>) method.CreateDelegate (typeof (Func<TypedRefTarget, TypedRefTarget>));
636 var target = new TypedRefTarget { Name = "Foo" };
639 Assert.AreEqual (target, rt);
642 private static void AssertTypedRef (TypedReference tr)
644 Assert.AreEqual (typeof (TypedRefTarget), TypedReference.GetTargetType (tr));