X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fgc-test.cs;h=50a91fdf2ea4ef97daa5257c588f42ab40ae82de;hb=4c78059bc5c4792dfa04f4c26a0e66796642b2e4;hp=50a4a76f13cc941296a294b444c9a0921d36b24e;hpb=e33dfa7dc414b90ba7e2878520c3f095d02f5ee0;p=mono.git diff --git a/mono/mini/gc-test.cs b/mono/mini/gc-test.cs index 50a4a76f13c..50a91fdf2ea 100644 --- a/mono/mini/gc-test.cs +++ b/mono/mini/gc-test.cs @@ -1,26 +1,11 @@ using System; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Threading; /* - * Regression tests for the mono JIT. - * - * Each test needs to be of the form: - * - * static int test__ (); - * - * where is an integer (the value that needs to be returned by - * the method to make it pass. - * is a user-displayed name used to identify the test. - * - * The tests can be driven in two ways: - * *) running the program directly: Main() uses reflection to find and invoke - * the test methods (this is useful mostly to check that the tests are correct) - * *) with the --regression switch of the jit (this is the preferred way since - * all the tests will be run with optimizations on and off) - * - * The reflection logic could be moved to a .dll since we need at least another - * regression test file written in IL code to have better control on how - * the IL code looks. + * Regression tests for the GC support in the JIT */ class Tests { @@ -158,41 +143,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. - */ - /* FIXME: This doesn't work yet - public static int test_0_liveness_out_of_line_bblocks () { - cond (false); - return 0; - } - */ - /* * Test liveness and loops. */ @@ -280,4 +230,402 @@ class Tests { return 0; } + + /* + * Test liveness of variables used to handle items on the IL stack. + */ + [MethodImplAttribute (MethodImplOptions.NoInlining)] + static string call1 () { + return "A"; + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + static string call2 () { + GC.Collect (1); + return "A"; + } + + public static int test_0_liveness_4 () { + bool b = false; + bool b2 = true; + + /* 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 ++; + + string o = b ? call1 () : call2 (); + + GC.Collect (1); + + sum += i + j + k + l + m + n + s; + + return 0; + } + + + /* + * Test liveness of volatile variables + */ + [MethodImplAttribute (MethodImplOptions.NoInlining)] + static void liveness_5_1 (out object o) { + o = new object (); + } + + public static int test_0_liveness_5 () { + bool b = false; + bool b2 = true; + + /* 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; + + liveness_5_1 (out o); + + for (int x = 0; x < 10; ++x) { + + o.ToString (); + + GC.Collect (1); + } + + sum += i + j + k + l + m + n + s; + + return 0; + } + + /* + * Test the case when a stack slot becomes dead, then live again due to a backward + * branch. + */ + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + 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; + + /* 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 ++; + + for (int x = 0; x < 10; ++x) { + + GC.Collect (1); + + object o = alloc_obj (); + + o.ToString (); + + GC.Collect (1); + } + + sum += i + j + k + l + m + n + s; + + return 0; + } + + 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; + } + + // Liveness for spill slots holding managed pointers + public static int test_0_liveness_11 () { + Tests[] arr = new Tests [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; + } + + public static Tests operator >> (Tests bi1, int shiftVal) { + clobber_regs_and_gc (); + return bi1; + } + + [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 tls; + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + static void alloc_tls_obj () { + tls = new ThreadLocal (); + 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; + } } \ No newline at end of file