Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / gc-test.cs
index 498abf5271785dbdae789ce8bef17025f1e3314a..91234b6eec8da38a58334dc3a7f04e00c5ea9864 100644 (file)
@@ -1,16 +1,23 @@
 using System;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Collections;
+using System.Threading;
 
 /*
  * Regression tests for the GC support in the JIT
  */
-
-class Tests {
-
-       static int Main () {
-               return TestDriver.RunTests (typeof (Tests));
+#if __MOBILE__
+class GcTests
+#else
+class Tests
+#endif
+{
+#if !__MOBILE__
+       public static int Main (string[] args) {
+               return TestDriver.RunTests (typeof (Tests), args);
        }
+#endif
 
        public static int test_36_simple () {
                // Overflow the registers
@@ -141,39 +148,6 @@ class Tests {
                        (int)b.o31 + (int)b.o32;
        }
 
-       static void cond (bool b) {
-               if (b) {
-                       /* Exhaust all registers so 'o' is stack allocated */
-                       int sum = 0, i, j, k, l, m;
-                       for (i = 0; i < 100; ++i)
-                               sum ++;
-                       for (j = 0; j < 100; ++j)
-                               sum ++;
-                       for (k = 0; k < 100; ++k)
-                               sum ++;
-                       for (l = 0; l < 100; ++l)
-                               sum ++;
-                       for (m = 0; m < 100; ++m)
-                               sum ++;
-
-                       object o = new object ();
-                       sum += i + j + k;
-                       if (b) {
-                               throw new Exception (o.ToString ());
-                       }
-               }
-               GC.Collect (1);
-       }
-
-       /* 
-        * Tests liveness of object references which are initialized conditionally,
-        * used in an out-of-line bblock, and the initlocals assignment is optimized away.
-        */
-       public static int test_0_liveness_out_of_line_bblocks () {
-               cond (false);
-               return 0;
-       }
-
        /*
         * Test liveness and loops.
         */
@@ -358,10 +332,20 @@ class Tests {
         */
 
        [MethodImplAttribute (MethodImplOptions.NoInlining)]
-       static object liveness_6_1 () {
+       static object alloc_obj () {
                return new object ();
        }
 
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static bool return_true () {
+               return true;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static bool return_false () {
+               return false;
+       }
+
        public static int test_0_liveness_6 () {
                bool b = false;
                bool b2 = true;
@@ -387,7 +371,7 @@ class Tests {
 
                        GC.Collect (1);
 
-                       object o = liveness_6_1 ();
+                       object o = alloc_obj ();
 
                        o.ToString ();
 
@@ -398,4 +382,258 @@ class Tests {
 
                return 0;
        }
-}
\ No newline at end of file
+
+       public static int test_0_multi_dim_ref_array_wbarrier () {
+        string [,] arr = new string [256, 256];
+        for (int i = 0; i < 256; ++i) {
+            for (int j = 0; j < 100; ++j)
+                arr [i, j] = "" + i + " " + j;
+               }
+               GC.Collect ();
+
+               return 0;
+       }
+
+       /*
+        * Liveness + out of line bblocks
+        */
+       public static int test_0_liveness_7 () {
+               /* Exhaust all registers so 'o' is stack allocated */
+               int sum = 0, i, j, k, l, m, n, s;
+               for (i = 0; i < 100; ++i)
+                       sum ++;
+               for (j = 0; j < 100; ++j)
+                       sum ++;
+               for (k = 0; k < 100; ++k)
+                       sum ++;
+               for (l = 0; l < 100; ++l)
+                       sum ++;
+               for (m = 0; m < 100; ++m)
+                       sum ++;
+               for (n = 0; n < 100; ++n)
+                       sum ++;
+               for (s = 0; s < 100; ++s)
+                       sum ++;
+
+               // o is dead here
+               GC.Collect (1);
+
+               if (return_false ()) {
+                       // This bblock is in-line
+                       object o = alloc_obj ();
+                       // o is live here
+                       if (return_false ()) {
+                               // This bblock is out-of-line, and o is live here
+                               throw new Exception (o.ToString ());
+                       }
+               }
+
+               // o is dead here too
+               GC.Collect (1);
+
+               return 0;
+       }
+
+       // Liveness + finally clauses
+       public static int test_0_liveness_8 () {
+               /* Exhaust all registers so 'o' is stack allocated */
+               int sum = 0, i, j, k, l, m, n, s;
+               for (i = 0; i < 100; ++i)
+                       sum ++;
+               for (j = 0; j < 100; ++j)
+                       sum ++;
+               for (k = 0; k < 100; ++k)
+                       sum ++;
+               for (l = 0; l < 100; ++l)
+                       sum ++;
+               for (m = 0; m < 100; ++m)
+                       sum ++;
+               for (n = 0; n < 100; ++n)
+                       sum ++;
+               for (s = 0; s < 100; ++s)
+                       sum ++;
+
+               object o = null;
+               try {
+                       o = alloc_obj ();
+               } finally {
+                       GC.Collect (1);
+               }
+
+               o.GetHashCode ();
+               return 0;
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static object alloc_string () {
+               return "A";
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static object alloc_obj_and_gc () {
+               GC.Collect (1);
+               return new object ();
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static void clobber_regs_and_gc () {
+               int sum = 0, i, j, k, l, m, n, s;
+               for (i = 0; i < 100; ++i)
+                       sum ++;
+               for (j = 0; j < 100; ++j)
+                       sum ++;
+               for (k = 0; k < 100; ++k)
+                       sum ++;
+               for (l = 0; l < 100; ++l)
+                       sum ++;
+               for (m = 0; m < 100; ++m)
+                       sum ++;
+               for (n = 0; n < 100; ++n)
+                       sum ++;
+               for (s = 0; s < 100; ++s)
+                       sum ++;
+               GC.Collect (1);
+       }
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static void liveness_9_call1 (object o1, object o2, object o3) {
+               o1.GetHashCode ();
+               o2.GetHashCode ();
+               o3.GetHashCode ();
+       }
+
+       // Liveness + JIT temporaries
+       public static int test_0_liveness_9 () {
+               // the result of alloc_obj () goes into a vreg, which gets converted to a
+               // JIT temporary because of the branching introduced by the cast
+               // FIXME: This doesn't crash if MONO_TYPE_I is not treated as a GC ref
+               liveness_9_call1 (alloc_obj (), (string)alloc_string (), alloc_obj_and_gc ());
+               return 0;
+       }
+
+       // Liveness for registers
+       public static int test_0_liveness_10 () {
+               // Make sure this goes into a register
+               object o = alloc_obj ();
+               o.GetHashCode ();
+               o.GetHashCode ();
+               o.GetHashCode ();
+               o.GetHashCode ();
+               o.GetHashCode ();
+               o.GetHashCode ();
+               // Break the bblock so o doesn't become a local vreg
+               if (return_true ())
+                       // Clobber it with a call and run a GC
+                       clobber_regs_and_gc ();
+               // Access it again
+               o.GetHashCode ();
+               return 0;
+       }
+
+       class ObjWithShiftOp {
+               public static ObjWithShiftOp operator >> (ObjWithShiftOp bi1, int shiftVal) {
+                       clobber_regs_and_gc ();
+                       return bi1;
+               }
+       }
+
+       // Liveness for spill slots holding managed pointers
+       public static int test_0_liveness_11 () {
+               ObjWithShiftOp[] arr = new ObjWithShiftOp [10];
+               // This uses an ldelema internally
+               // FIXME: This doesn't crash if mp-s are not correctly tracked, just writes to
+               // an old object.
+               arr [0] >>= 1;
+
+               return 0;
+       }
+
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       public static void liveness_12_inner (int a, int b, int c, int d, int e, int f, object o, ref string s) {
+               GC.Collect (1);
+               o.GetHashCode ();
+               s.GetHashCode ();
+       }
+
+       class FooClass {
+               public string s;
+       }
+
+       // Liveness for param area
+       public static int test_0_liveness_12 () {
+               var f = new FooClass () { s = "A" };
+               // The ref argument should be passed on the stack
+               liveness_12_inner (1, 2, 3, 4, 5, 6, new object (), ref f.s);
+               return 0;
+       }
+       
+       interface IFace {
+               int foo ();
+       }
+
+       struct BarStruct : IFace {
+               int i;
+
+               public int foo () {
+                       GC.Collect ();
+                       return i;
+               }
+       }
+               
+       public static int test_0_liveness_unbox_trampoline () {
+               var s = new BarStruct ();
+               
+               IFace iface = s;
+               iface.foo ();
+               return 0;
+       }
+
+       public static void liveness_13_inner (ref ArrayList arr) {
+               // The value of arr will be stored in a spill slot
+               arr.Add (alloc_obj_and_gc ());
+       }
+
+       // Liveness for byref arguments in spill slots
+       public static int test_0_liveness_13 () {
+               var arr = new ArrayList ();
+               liveness_13_inner (ref arr);
+               return 0;
+       }
+
+       static ThreadLocal<object> tls;
+
+       [MethodImplAttribute (MethodImplOptions.NoInlining)]
+       static void alloc_tls_obj () {
+               tls = new ThreadLocal<object> ();
+               tls.Value = new object ();
+       }
+
+       public static int test_0_thread_local () {
+               alloc_tls_obj ();
+               GC.Collect ();
+               Type t = tls.Value.GetType ();
+               if (t == typeof (object))
+                       return 0;
+               else
+                       return 1;
+       }
+
+       struct LargeBitmap {
+               public object o1, o2, o3;
+               public int i;
+               public object o4, o5, o6, o7, o9, o10, o11, o12, o13, o14, o15, o16, o17, o18, o19, o20, o21, o22, o23, o24, o25, o26, o27, o28, o29, o30, o31, o32;
+       }
+
+       public static int test_12_large_bitmap () {
+               LargeBitmap lb = new LargeBitmap ();
+               lb.o1 = 1;
+               lb.o2 = 2;
+               lb.o3 = 3;
+               lb.o32 = 6;
+
+               GC.Collect (0);
+
+               return (int)lb.o1 + (int)lb.o2 + (int)lb.o3 + (int)lb.o32;
+       }
+}