[jit] In native-to-managed wrappers, emit the initlocals code for vtypes after the...
[mono.git] / mono / tests / pinvoke3.cs
index a55e9a571583731bf0cf1676378cc526e691c688..c1354ce9b544dc34baea80b26e75b16fa20e156b 100644 (file)
@@ -5,7 +5,9 @@
 //
 
 using System;
+using System.Text;
 using System.Runtime.InteropServices;
+using System.Threading;
 
 public class Tests {
 
@@ -64,6 +66,19 @@ public class Tests {
                return 0;
        }
 
+       public static int delegate_test_struct_in (int a, [In] ref SimpleStruct ss, int b)
+       {
+               if (a == 1 && b == 2 && ss.a && !ss.b && ss.c && ss.d == "TEST2") {
+                       ss.a = true;
+                       ss.b = true;
+                       ss.c = true;
+                       ss.d = "TEST3";
+                       return 0;
+               }
+
+               return 1;
+       }
+
        public static SimpleClass delegate_test_class (SimpleClass ss)
        {
                if (ss == null)
@@ -119,13 +134,26 @@ public class Tests {
                return s == "ABC" ? 0 : 1;
        }
 
+       public static int delegate_test_string_builder_marshalling (StringBuilder s)
+       {
+               if (s == null)
+                       return 2;
+               else
+                       return s.ToString () == "ABC" ? 0 : 1;
+       }
+
        [DllImport ("libtest", EntryPoint="mono_test_ref_vtype")]
        public static extern int mono_test_ref_vtype (int a, ref SimpleStruct ss, int b, TestDelegate d);
 
        public delegate int OutStructDelegate (int a, out SimpleStruct ss, int b);
 
+       public delegate int InStructDelegate (int a, [In] ref SimpleStruct ss, int b);
+
        [DllImport ("libtest", EntryPoint="mono_test_marshal_out_struct")]
        public static extern int mono_test_marshal_out_struct (int a, out SimpleStruct ss, int b, OutStructDelegate d);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_in_struct")]
+       public static extern int mono_test_marshal_in_struct (int a, ref SimpleStruct ss, int b, InStructDelegate d);
        
        [DllImport ("libtest", EntryPoint="mono_test_marshal_delegate2")]
        public static extern int mono_test_marshal_delegate2 (SimpleDelegate2 d);
@@ -151,12 +179,26 @@ public class Tests {
        [DllImport ("libtest", EntryPoint="mono_test_marshal_delegate10")]
        public static extern int mono_test_marshal_delegate10 (SimpleDelegate9 d);
 
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_delegate8")]
+       public static extern int mono_test_marshal_delegate11 (SimpleDelegate11 d, string s);
+
        [DllImport ("libtest", EntryPoint="mono_test_marshal_primitive_byref_delegate")]
        public static extern int mono_test_marshal_primitive_byref_delegate (PrimitiveByrefDelegate d);
 
        [DllImport ("libtest", EntryPoint="mono_test_marshal_return_delegate_delegate")]
        public static extern int mono_test_marshal_return_delegate_delegate (ReturnDelegateDelegate d);
 
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_delegate_ref_delegate")]
+       public static extern int mono_test_marshal_delegate_ref_delegate (DelegateByrefDelegate del);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_virtual_delegate")]
+       public static extern int mono_test_marshal_virtual_delegate (VirtualDelegate del);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_icall_delegate")]
+       public static extern int mono_test_marshal_icall_delegate (IcallDelegate del);
+
+       public delegate string IcallDelegate (IntPtr p);
+
        public delegate int TestDelegate (int a, ref SimpleStruct ss, int b);
 
        public delegate SimpleStruct SimpleDelegate2 (SimpleStruct ss);
@@ -173,10 +215,16 @@ public class Tests {
 
        public delegate int SimpleDelegate9 (return_int_delegate del);
 
+       public delegate int SimpleDelegate11 (StringBuilder s1);
+
        public delegate int PrimitiveByrefDelegate (ref int i);
 
        public delegate return_int_delegate ReturnDelegateDelegate ();
 
+       public delegate int DelegateByrefDelegate (ref return_int_delegate del);
+
+       public delegate int VirtualDelegate (int i);
+
        public static int Main () {
                return TestDriver.RunTests (typeof (Tests));
        }
@@ -213,6 +261,14 @@ public class Tests {
                return mono_test_marshal_out_struct (1, out ss, 2, d);
        }
 
+       /* Test structures as in arguments of delegates */
+       public static int test_0_marshal_in_struct_delegate () {
+               SimpleStruct ss = new SimpleStruct () { a = true, b = false, c = true, d = "TEST2" };
+               InStructDelegate d = new InStructDelegate (delegate_test_struct_in);
+
+               return mono_test_marshal_in_struct (1, ref ss, 2, d);
+       }
+
        /* Test classes as arguments and return values of delegates */
        public static int test_0_marshal_class_delegate () {
                SimpleDelegate4 d = new SimpleDelegate4 (delegate_test_class);
@@ -241,6 +297,16 @@ public class Tests {
                return mono_test_marshal_delegate8 (d, "ABC");
        }
 
+       /* Test string builder marshalling with delegates */
+       public static int test_0_marshal_string_builder_delegate () {
+               SimpleDelegate11 d = new SimpleDelegate11 (delegate_test_string_builder_marshalling);
+
+               if (mono_test_marshal_delegate11 (d, null) != 2)
+                       return 2;
+
+               return mono_test_marshal_delegate11 (d, "ABC");
+       }
+
        /* Test that the delegate wrapper correctly catches null byref arguments */
        public static int test_0_marshal_byref_class_delegate_null () {
                SimpleDelegate5 d = new SimpleDelegate5 (delegate_test_class_byref);
@@ -282,6 +348,20 @@ public class Tests {
                return mono_test_marshal_return_delegate_delegate (new ReturnDelegateDelegate (return_delegate));
        }
 
+       public static int return_plus_1 (int i) {
+               return i + 1;
+       }
+
+       public static int ref_delegate_delegate (ref return_int_delegate del) {
+               del = return_plus_1;
+               return 0;
+       }
+
+       public static int test_55_marshal_delegate_ref_delegate () {
+               var del = new DelegateByrefDelegate (ref_delegate_delegate);
+               return mono_test_marshal_delegate_ref_delegate (del);
+       }
+
        /* Passing and returning strings */
 
        public delegate String ReturnStringDelegate (String s);
@@ -666,6 +746,21 @@ public class Tests {
                return mono_test_marshal_array_delegate1 (null, 0, new ArrayDelegate1 (array_delegate2));
        }
 
+       public delegate int ArrayDelegateBlittable (int i, string j,
+                                                                               [In, MarshalAs(UnmanagedType.LPArray,
+                                                                                                          ArraySubType=UnmanagedType.LPStr, SizeParamIndex=0)] int[] arr);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_array_delegate")]
+       public static extern int mono_test_marshal_array_delegate1 (string[] arr, int len, ArrayDelegateBlittable d);
+
+       public static int array_delegate_null_blittable (int i, string j, int[] arr) {
+               return (arr == null) ? 0 : 1;
+       }
+
+       public static int test_0_marshal_array_delegate_null_blittable () {
+               return mono_test_marshal_array_delegate1 (null, 0, new ArrayDelegateBlittable (array_delegate_null_blittable));
+       }
+
        public delegate int ArrayDelegate3 (int i, 
                                                                                string j, 
                                                                                [In, MarshalAs(UnmanagedType.LPArray, 
@@ -710,6 +805,49 @@ public class Tests {
                }
        }
 
+       public delegate int ArrayDelegate4_2 (int i, 
+                                                                               string j, 
+                                                                                 string[] arr);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_array_delegate")]
+       public static extern int mono_test_marshal_array_delegate4_2 (string[] arr, int len, ArrayDelegate4_2 d);
+
+       public static int array_delegate4_2 (int i, string j, string[] arr) {
+               return (arr == null) ? 0 : 1;
+       }
+
+       public static int test_0_marshal_array_delegate_no_marshal_directive () {
+               try {
+                       mono_test_marshal_array_delegate4_2 (null, 0, new ArrayDelegate4_2 (array_delegate4_2));
+                       return 1;
+               }
+               catch (MarshalDirectiveException) {
+                       return 0;
+               }
+       }
+
+       public delegate int ArrayDelegate4_3 (int i, 
+                                                                               string j, 
+                                                                                 string[] arr);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_array_delegate")]
+       public static extern int mono_test_marshal_array_delegate4_3 (string[] arr, int len, ArrayDelegate4_3 d);
+
+       public int array_delegate4_3 (int i, string j, string[] arr) {
+               return (arr == null) ? 0 : 1;
+       }
+
+       public static int test_0_marshal_array_delegate_no_marshal_directive_instance () {
+               try {
+                       Tests t = new Tests ();
+                       mono_test_marshal_array_delegate4_3 (null, 0, new ArrayDelegate4_3 (t.array_delegate4_3));
+                       return 1;
+               }
+               catch (MarshalDirectiveException) {
+                       return 0;
+               }
+       }
+
        public delegate int ArrayDelegate5 (int i, 
                                                                                string j, 
                                                                                [In, MarshalAs(UnmanagedType.LPArray, 
@@ -794,6 +932,30 @@ public class Tests {
                return mono_test_marshal_array_delegate8 (arr, 2, new ArrayDelegate8 (array_delegate8));
        }
 
+       /* Array with size param of type long */
+
+       public delegate int ArrayDelegate8_2 (long i, 
+                                                                               string j, 
+                                                                               [In, MarshalAs(UnmanagedType.LPArray, 
+                                                                                                          ArraySubType=UnmanagedType.LPStr, SizeParamIndex=0)] string[] arr);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_array_delegate_long")]
+       public static extern int mono_test_marshal_array_delegate8_2 (string[] arr, long len, ArrayDelegate8_2 d);
+
+       public static int array_delegate8_2 (long i, string j, string[] arr) {
+               if (arr.Length != 2)
+                       return 1;
+               if ((arr [0] != "ABC") || (arr [1] != "DEF"))
+                       return 2;
+               return 0;
+       }
+
+       public static int test_0_marshal_array_delegate_long_param () { 
+               string[] arr = new string [] { "ABC", "DEF" };
+               return mono_test_marshal_array_delegate8_2 (arr, arr.Length, new ArrayDelegate8_2 (array_delegate8_2));
+       }
+
+
        /*
         * [Out] blittable arrays
         */
@@ -848,4 +1010,262 @@ public class Tests {
                return mono_test_marshal_out_string_array_delegate (arr, 2, new ArrayDelegate10 (array_delegate10));
        }
 
+       /*
+        * [In, Out] classes
+        */
+
+       public delegate int InOutByvalClassDelegate ([In, Out] SimpleClass ss);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_inout_byval_class_delegate")]
+       public static extern int mono_test_marshal_inout_byval_class_delegate (InOutByvalClassDelegate d);
+
+       public static int delegate_test_byval_class_inout (SimpleClass ss) {
+               if ((ss.a != false) || (ss.b != true) || (ss.c != false) || (ss.d != "FOO"))
+                       return 1;
+
+               ss.a = true;
+               ss.b = false;
+               ss.c = true;
+               ss.d = "RES";
+
+               return 0;
+       }
+
+       public static int test_0_marshal_inout_byval_class_delegate () {
+               return mono_test_marshal_inout_byval_class_delegate (new InOutByvalClassDelegate (delegate_test_byval_class_inout));
+       }
+
+       /*
+        * Returning unicode strings
+        */
+       [return: MarshalAs(UnmanagedType.LPWStr)]
+       public delegate string ReturnUnicodeStringDelegate([MarshalAs(UnmanagedType.LPWStr)] string message);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_return_unicode_string_delegate")]
+       public static extern int mono_test_marshal_return_unicode_string_delegate (ReturnUnicodeStringDelegate d);
+
+       public static String return_unicode_string_delegate (string message) {
+               return message;
+       }
+
+       public static int test_0_marshal_return_unicode_string_delegate () {    
+               return mono_test_marshal_return_unicode_string_delegate (new ReturnUnicodeStringDelegate (return_unicode_string_delegate));
+       }
+
+       /*
+        * Returning string arrays
+        */
+       public delegate string[] ReturnArrayDelegate (int i);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_return_string_array_delegate")]
+       public static extern int mono_test_marshal_return_string_array_delegate (ReturnArrayDelegate d);
+
+       public static String[] return_array_delegate (int i) {
+               String[] arr = new String [2];
+
+               arr [0] = "ABC";
+               arr [1] = "DEF";
+
+               return arr;
+       }
+
+       public static String[] return_array_delegate_null (int i) {
+               return null;
+       }
+
+       public static int test_0_marshal_return_string_array_delegate () {      
+               return mono_test_marshal_return_string_array_delegate (new ReturnArrayDelegate (return_array_delegate));
+       }
+
+       public static int test_3_marshal_return_string_array_delegate_null () { 
+               return mono_test_marshal_return_string_array_delegate (new ReturnArrayDelegate (return_array_delegate_null));
+       }
+
+       /*
+        * Byref string marshalling
+        */
+       public delegate int ByrefStringDelegate (ref string s);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_byref_string_delegate")]
+       public static extern int mono_test_marshal_byref_string_delegate (ByrefStringDelegate d);
+
+       public static int byref_string_delegate (ref string s) {
+               if (s != "ABC")
+                       return 1;
+
+               s = "DEF";
+
+               return 0;
+       }
+
+       public static int test_0_marshal_byref_string_delegate () {     
+               return mono_test_marshal_byref_string_delegate (new ByrefStringDelegate (byref_string_delegate));
+       }
+
+       /*
+        * Thread attach
+        */
+
+       public delegate int SimpleDelegate (int i);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_thread_attach")]
+       public static extern int mono_test_marshal_thread_attach (SimpleDelegate d);
+
+       public static int test_43_thread_attach () {
+               int res = mono_test_marshal_thread_attach (delegate (int i) {
+                               if (!Thread.CurrentThread.IsBackground)
+                                       return 0;
+                               return i + 1;
+                       });
+               return res;
+       }
+
+       public struct LargeStruct {
+            public Int16 s;
+            public Int16 v;
+            public UInt32 p;
+            public UInt32 e;
+            public Int32 l;
+            public Int32 ll;
+            public UInt16 h;
+            public Int16 r;
+            public Int16 pp;
+            public Int32 hh;
+            public Int32 bn;
+            public Int32 dn;
+            public Int32 dr;
+            public Int32 sh;
+            public Int32 ra;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+            public Int32[] angle;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+            public Int32[] width;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+            public Int32[] edge;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3 * 1024)]
+            public byte[] echo;
+       }
+
+       public delegate int LargeStructDelegate (ref LargeStruct s);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_thread_attach_large_vt")]
+       public static extern int mono_test_marshal_thread_attach_large_vt (LargeStructDelegate d);
+
+       public static int test_43_thread_attach_large_vt () {
+               int res = mono_test_marshal_thread_attach_large_vt (delegate (ref LargeStruct s) {
+                               return 43;
+                       });
+               return res;
+       }
+
+       class Worker {
+               volatile bool stop = false;
+               public void Stop () {
+                       stop = true;
+               }
+
+               public void Work () {
+                       while (!stop) {
+                               for (int i = 0; i < 100; i++) {
+                                       var a = new double[80000];
+                                       Thread.Sleep (0);
+                               }
+                               GC.Collect ();
+                       }
+               }
+       }
+
+       public static int test_43_thread_attach_detach_contested () {
+               // Test plan: we want to create a race between the GC
+               // and native threads detaching.  When a native thread
+               // calls a managed delegate, it's attached to the
+               // runtime by the wrapper.  It is detached when the
+               // thread is destroyed and the TLS key destructor for
+               // MonoThreadInfo runs.  That destructor wants to take
+               // the GC lock.  So we create a lot of native threads
+               // while at the same time running a worker that
+               // allocates garbage and invokes the collector.
+               var w = new Worker ();
+               Thread t = new Thread(new ThreadStart (w.Work));
+               t.Start ();
+
+               for (int count = 0; count < 500; count++) {
+                       int res = mono_test_marshal_thread_attach (delegate (int i) {
+                                       Thread.Sleep (0);
+                                       return i + 1;
+                               });
+               }
+               Thread.Sleep (1000);
+               w.Stop ();
+               t.Join ();
+               return 43; 
+
+       }
+       /*
+        * Appdomain save/restore
+        */
+    static Func<int> callback;
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_set_callback")]
+       public static extern int mono_test_marshal_set_callback (Func<int> a);
+
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_call_callback")]
+       public static extern int mono_test_marshal_call_callback ();
+
+       public static int test_0_appdomain_switch () {
+               // FIXME: The appdomain unload hangs
+               //return 0;
+        AppDomain ad = AppDomain.CreateDomain ("foo");
+               var c = (CallbackClass)ad.CreateInstanceAndUnwrap (
+                               typeof (CallbackClass).Assembly.FullName, "Tests/CallbackClass");
+               c.SetCallback ();
+               int domain_id = AppDomain.CurrentDomain.Id;
+               int new_id = mono_test_marshal_call_callback ();
+               int res = 0;
+               if (new_id == domain_id)
+                       res = 1;
+               if (AppDomain.CurrentDomain.Id != domain_id)
+                       res = 2;
+               AppDomain.Unload (ad);
+               return res;
+    }
+
+       static int domain_callback () {
+               return AppDomain.CurrentDomain.Id;
+       }
+
+       class CallbackClass : MarshalByRefObject {
+               public int SetCallback () {
+                       mono_test_marshal_set_callback (domain_callback);
+                       return 0;
+               }
+    }
+
+       class Base {
+               public VirtualDelegate get_del () {
+                       return delegate_test;
+               }
+
+               public virtual int delegate_test (int i) {
+                       return i;
+               }
+       }
+
+       class Derived : Base {
+               public override int delegate_test (int i) {
+                       return i + 1;
+               }
+       }
+
+       public static int test_43_virtual () {
+               Base b = new Derived ();
+
+               return mono_test_marshal_virtual_delegate (b.get_del ());
+       }
+
+       public static int test_0_icall_delegate () {
+               var m = typeof (Marshal).GetMethod ("PtrToStringAnsi", new Type[] { typeof (IntPtr) });
+
+               return mono_test_marshal_icall_delegate ((IcallDelegate)Delegate.CreateDelegate (typeof (IcallDelegate), m));
+       }
 }