update rx (mobile builds).
[mono-project.git] / mono / mini / gc-test.cs
blob50a91fdf2ea4ef97daa5257c588f42ab40ae82de
1 using System;
2 using System.Reflection;
3 using System.Runtime.CompilerServices;
4 using System.Collections;
5 using System.Threading;
7 /*
8 * Regression tests for the GC support in the JIT
9 */
11 class Tests {
13 static int Main () {
14 return TestDriver.RunTests (typeof (Tests));
17 public static int test_36_simple () {
18 // Overflow the registers
19 object o1 = (1);
20 object o2 = (2);
21 object o3 = (3);
22 object o4 = (4);
23 object o5 = (5);
24 object o6 = (6);
25 object o7 = (7);
26 object o8 = (8);
28 /* Prevent the variables from being local to a bb */
29 bool b = o1 != null;
30 GC.Collect (0);
32 if (b)
33 return (int)o1 + (int)o2 + (int)o3 + (int)o4 + (int)o5 + (int)o6 + (int)o7 + (int)o8;
34 else
35 return 0;
38 public static int test_36_liveness () {
39 object o = 5;
40 object o1, o2, o3, o4, o5, o6, o7, o8;
42 bool b = o != null;
44 GC.Collect (1);
46 o1 = (1);
47 o2 = (2);
48 o3 = (3);
49 o4 = (4);
50 o5 = (5);
51 o6 = (6);
52 o7 = (7);
53 o8 = (8);
55 if (b)
56 return (int)o1 + (int)o2 + (int)o3 + (int)o4 + (int)o5 + (int)o6 + (int)o7 + (int)o8;
57 else
58 return 0;
61 struct FooStruct {
62 public object o1;
63 public int i;
64 public object o2;
66 public FooStruct (int i1, int i, int i2) {
67 this.o1 = i1;
68 this.i = i;
69 this.o2 = i2;
73 public static int test_4_vtype () {
74 FooStruct s = new FooStruct (1, 2, 3);
76 GC.Collect (1);
78 return (int)s.o1 + (int)s.o2;
81 class BigClass {
82 public object o1, o2, o3, o4, o5, o6, o7, o8, o9, o10;
83 public object o11, o12, o13, o14, o15, o16, o17, o18, o19, o20;
84 public object o21, o22, o23, o24, o25, o26, o27, o28, o29, o30;
85 public object o31, o32;
88 static void set_fields (BigClass b) {
89 b.o31 = 31;
90 b.o32 = 32;
92 b.o1 = 1;
93 b.o2 = 2;
94 b.o3 = 3;
95 b.o4 = 4;
96 b.o5 = 5;
97 b.o6 = 6;
98 b.o7 = 7;
99 b.o8 = 8;
100 b.o9 = 9;
101 b.o10 = 10;
102 b.o11 = 11;
103 b.o12 = 12;
104 b.o13 = 13;
105 b.o14 = 14;
106 b.o15 = 15;
107 b.o16 = 16;
108 b.o17 = 17;
109 b.o18 = 18;
110 b.o19 = 19;
111 b.o20 = 20;
112 b.o21 = 21;
113 b.o22 = 22;
114 b.o23 = 23;
115 b.o24 = 24;
116 b.o25 = 25;
117 b.o26 = 26;
118 b.o27 = 27;
119 b.o28 = 28;
120 b.o29 = 29;
121 b.o30 = 30;
124 // Test marking of objects with > 32 fields
125 public static int test_528_mark_runlength_large () {
126 BigClass b = new BigClass ();
129 * Do the initialization in a separate method so no object refs remain in
130 * spill slots.
132 set_fields (b);
134 GC.Collect (1);
136 return
137 (int)b.o1 + (int)b.o2 + (int)b.o3 + (int)b.o4 + (int)b.o5 +
138 (int)b.o6 + (int)b.o7 + (int)b.o8 + (int)b.o9 + (int)b.o10 +
139 (int)b.o11 + (int)b.o12 + (int)b.o13 + (int)b.o14 + (int)b.o15 +
140 (int)b.o16 + (int)b.o17 + (int)b.o18 + (int)b.o19 + (int)b.o20 +
141 (int)b.o21 + (int)b.o22 + (int)b.o23 + (int)b.o24 + (int)b.o25 +
142 (int)b.o26 + (int)b.o27 + (int)b.o28 + (int)b.o29 + (int)b.o30 +
143 (int)b.o31 + (int)b.o32;
147 * Test liveness and loops.
149 public static int test_0_liveness_2 () {
150 object o = new object ();
151 for (int n = 0; n < 10; ++n) {
152 /* Exhaust all registers so 'o' is stack allocated */
153 int sum = 0, i, j, k, l, m;
154 for (i = 0; i < 100; ++i)
155 sum ++;
156 for (j = 0; j < 100; ++j)
157 sum ++;
158 for (k = 0; k < 100; ++k)
159 sum ++;
160 for (l = 0; l < 100; ++l)
161 sum ++;
162 for (m = 0; m < 100; ++m)
163 sum ++;
165 if (o != null)
166 o.ToString ();
168 GC.Collect (1);
170 if (o != null)
171 o.ToString ();
173 sum += i + j + k;
175 GC.Collect (1);
178 return 0;
182 * Test liveness and stack slot sharing
183 * This doesn't work yet, its hard to make the JIT share the stack slots of the
184 * two 'o' variables.
186 public static int test_0_liveness_3 () {
187 bool b = false;
188 bool b2 = true;
190 /* Exhaust all registers so 'o' is stack allocated */
191 int sum = 0, i, j, k, l, m, n, s;
192 for (i = 0; i < 100; ++i)
193 sum ++;
194 for (j = 0; j < 100; ++j)
195 sum ++;
196 for (k = 0; k < 100; ++k)
197 sum ++;
198 for (l = 0; l < 100; ++l)
199 sum ++;
200 for (m = 0; m < 100; ++m)
201 sum ++;
202 for (n = 0; n < 100; ++n)
203 sum ++;
204 for (s = 0; s < 100; ++s)
205 sum ++;
207 if (b) {
208 object o = new object ();
210 /* Make sure o is global */
211 if (b2)
212 Console.WriteLine ();
214 o.ToString ();
217 GC.Collect (1);
219 if (b) {
220 object o = new object ();
222 /* Make sure o is global */
223 if (b2)
224 Console.WriteLine ();
226 o.ToString ();
229 sum += i + j + k + l + m + n + s;
231 return 0;
235 * Test liveness of variables used to handle items on the IL stack.
237 [MethodImplAttribute (MethodImplOptions.NoInlining)]
238 static string call1 () {
239 return "A";
242 [MethodImplAttribute (MethodImplOptions.NoInlining)]
243 static string call2 () {
244 GC.Collect (1);
245 return "A";
248 public static int test_0_liveness_4 () {
249 bool b = false;
250 bool b2 = true;
252 /* Exhaust all registers so 'o' is stack allocated */
253 int sum = 0, i, j, k, l, m, n, s;
254 for (i = 0; i < 100; ++i)
255 sum ++;
256 for (j = 0; j < 100; ++j)
257 sum ++;
258 for (k = 0; k < 100; ++k)
259 sum ++;
260 for (l = 0; l < 100; ++l)
261 sum ++;
262 for (m = 0; m < 100; ++m)
263 sum ++;
264 for (n = 0; n < 100; ++n)
265 sum ++;
266 for (s = 0; s < 100; ++s)
267 sum ++;
269 string o = b ? call1 () : call2 ();
271 GC.Collect (1);
273 sum += i + j + k + l + m + n + s;
275 return 0;
280 * Test liveness of volatile variables
282 [MethodImplAttribute (MethodImplOptions.NoInlining)]
283 static void liveness_5_1 (out object o) {
284 o = new object ();
287 public static int test_0_liveness_5 () {
288 bool b = false;
289 bool b2 = true;
291 /* Exhaust all registers so 'o' is stack allocated */
292 int sum = 0, i, j, k, l, m, n, s;
293 for (i = 0; i < 100; ++i)
294 sum ++;
295 for (j = 0; j < 100; ++j)
296 sum ++;
297 for (k = 0; k < 100; ++k)
298 sum ++;
299 for (l = 0; l < 100; ++l)
300 sum ++;
301 for (m = 0; m < 100; ++m)
302 sum ++;
303 for (n = 0; n < 100; ++n)
304 sum ++;
305 for (s = 0; s < 100; ++s)
306 sum ++;
308 object o;
310 liveness_5_1 (out o);
312 for (int x = 0; x < 10; ++x) {
314 o.ToString ();
316 GC.Collect (1);
319 sum += i + j + k + l + m + n + s;
321 return 0;
325 * Test the case when a stack slot becomes dead, then live again due to a backward
326 * branch.
329 [MethodImplAttribute (MethodImplOptions.NoInlining)]
330 static object alloc_obj () {
331 return new object ();
334 [MethodImplAttribute (MethodImplOptions.NoInlining)]
335 static bool return_true () {
336 return true;
339 [MethodImplAttribute (MethodImplOptions.NoInlining)]
340 static bool return_false () {
341 return false;
344 public static int test_0_liveness_6 () {
345 bool b = false;
346 bool b2 = true;
348 /* Exhaust all registers so 'o' is stack allocated */
349 int sum = 0, i, j, k, l, m, n, s;
350 for (i = 0; i < 100; ++i)
351 sum ++;
352 for (j = 0; j < 100; ++j)
353 sum ++;
354 for (k = 0; k < 100; ++k)
355 sum ++;
356 for (l = 0; l < 100; ++l)
357 sum ++;
358 for (m = 0; m < 100; ++m)
359 sum ++;
360 for (n = 0; n < 100; ++n)
361 sum ++;
362 for (s = 0; s < 100; ++s)
363 sum ++;
365 for (int x = 0; x < 10; ++x) {
367 GC.Collect (1);
369 object o = alloc_obj ();
371 o.ToString ();
373 GC.Collect (1);
376 sum += i + j + k + l + m + n + s;
378 return 0;
381 public static int test_0_multi_dim_ref_array_wbarrier () {
382 string [,] arr = new string [256, 256];
383 for (int i = 0; i < 256; ++i) {
384 for (int j = 0; j < 100; ++j)
385 arr [i, j] = "" + i + " " + j;
387 GC.Collect ();
389 return 0;
393 * Liveness + out of line bblocks
395 public static int test_0_liveness_7 () {
396 /* Exhaust all registers so 'o' is stack allocated */
397 int sum = 0, i, j, k, l, m, n, s;
398 for (i = 0; i < 100; ++i)
399 sum ++;
400 for (j = 0; j < 100; ++j)
401 sum ++;
402 for (k = 0; k < 100; ++k)
403 sum ++;
404 for (l = 0; l < 100; ++l)
405 sum ++;
406 for (m = 0; m < 100; ++m)
407 sum ++;
408 for (n = 0; n < 100; ++n)
409 sum ++;
410 for (s = 0; s < 100; ++s)
411 sum ++;
413 // o is dead here
414 GC.Collect (1);
416 if (return_false ()) {
417 // This bblock is in-line
418 object o = alloc_obj ();
419 // o is live here
420 if (return_false ()) {
421 // This bblock is out-of-line, and o is live here
422 throw new Exception (o.ToString ());
426 // o is dead here too
427 GC.Collect (1);
429 return 0;
432 // Liveness + finally clauses
433 public static int test_0_liveness_8 () {
434 /* Exhaust all registers so 'o' is stack allocated */
435 int sum = 0, i, j, k, l, m, n, s;
436 for (i = 0; i < 100; ++i)
437 sum ++;
438 for (j = 0; j < 100; ++j)
439 sum ++;
440 for (k = 0; k < 100; ++k)
441 sum ++;
442 for (l = 0; l < 100; ++l)
443 sum ++;
444 for (m = 0; m < 100; ++m)
445 sum ++;
446 for (n = 0; n < 100; ++n)
447 sum ++;
448 for (s = 0; s < 100; ++s)
449 sum ++;
451 object o = null;
452 try {
453 o = alloc_obj ();
454 } finally {
455 GC.Collect (1);
458 o.GetHashCode ();
459 return 0;
462 [MethodImplAttribute (MethodImplOptions.NoInlining)]
463 static object alloc_string () {
464 return "A";
467 [MethodImplAttribute (MethodImplOptions.NoInlining)]
468 static object alloc_obj_and_gc () {
469 GC.Collect (1);
470 return new object ();
473 [MethodImplAttribute (MethodImplOptions.NoInlining)]
474 static void clobber_regs_and_gc () {
475 int sum = 0, i, j, k, l, m, n, s;
476 for (i = 0; i < 100; ++i)
477 sum ++;
478 for (j = 0; j < 100; ++j)
479 sum ++;
480 for (k = 0; k < 100; ++k)
481 sum ++;
482 for (l = 0; l < 100; ++l)
483 sum ++;
484 for (m = 0; m < 100; ++m)
485 sum ++;
486 for (n = 0; n < 100; ++n)
487 sum ++;
488 for (s = 0; s < 100; ++s)
489 sum ++;
490 GC.Collect (1);
493 [MethodImplAttribute (MethodImplOptions.NoInlining)]
494 static void liveness_9_call1 (object o1, object o2, object o3) {
495 o1.GetHashCode ();
496 o2.GetHashCode ();
497 o3.GetHashCode ();
500 // Liveness + JIT temporaries
501 public static int test_0_liveness_9 () {
502 // the result of alloc_obj () goes into a vreg, which gets converted to a
503 // JIT temporary because of the branching introduced by the cast
504 // FIXME: This doesn't crash if MONO_TYPE_I is not treated as a GC ref
505 liveness_9_call1 (alloc_obj (), (string)alloc_string (), alloc_obj_and_gc ());
506 return 0;
509 // Liveness for registers
510 public static int test_0_liveness_10 () {
511 // Make sure this goes into a register
512 object o = alloc_obj ();
513 o.GetHashCode ();
514 o.GetHashCode ();
515 o.GetHashCode ();
516 o.GetHashCode ();
517 o.GetHashCode ();
518 o.GetHashCode ();
519 // Break the bblock so o doesn't become a local vreg
520 if (return_true ())
521 // Clobber it with a call and run a GC
522 clobber_regs_and_gc ();
523 // Access it again
524 o.GetHashCode ();
525 return 0;
528 // Liveness for spill slots holding managed pointers
529 public static int test_0_liveness_11 () {
530 Tests[] arr = new Tests [10];
531 // This uses an ldelema internally
532 // FIXME: This doesn't crash if mp-s are not correctly tracked, just writes to
533 // an old object.
534 arr [0] >>= 1;
536 return 0;
539 public static Tests operator >> (Tests bi1, int shiftVal) {
540 clobber_regs_and_gc ();
541 return bi1;
544 [MethodImplAttribute (MethodImplOptions.NoInlining)]
545 public static void liveness_12_inner (int a, int b, int c, int d, int e, int f, object o, ref string s) {
546 GC.Collect (1);
547 o.GetHashCode ();
548 s.GetHashCode ();
551 class FooClass {
552 public string s;
555 // Liveness for param area
556 public static int test_0_liveness_12 () {
557 var f = new FooClass () { s = "A" };
558 // The ref argument should be passed on the stack
559 liveness_12_inner (1, 2, 3, 4, 5, 6, new object (), ref f.s);
560 return 0;
563 interface IFace {
564 int foo ();
567 struct BarStruct : IFace {
568 int i;
570 public int foo () {
571 GC.Collect ();
572 return i;
576 public static int test_0_liveness_unbox_trampoline () {
577 var s = new BarStruct ();
579 IFace iface = s;
580 iface.foo ();
581 return 0;
584 public static void liveness_13_inner (ref ArrayList arr) {
585 // The value of arr will be stored in a spill slot
586 arr.Add (alloc_obj_and_gc ());
589 // Liveness for byref arguments in spill slots
590 public static int test_0_liveness_13 () {
591 var arr = new ArrayList ();
592 liveness_13_inner (ref arr);
593 return 0;
596 static ThreadLocal<object> tls;
598 [MethodImplAttribute (MethodImplOptions.NoInlining)]
599 static void alloc_tls_obj () {
600 tls = new ThreadLocal<object> ();
601 tls.Value = new object ();
604 public static int test_0_thread_local () {
605 alloc_tls_obj ();
606 GC.Collect ();
607 Type t = tls.Value.GetType ();
608 if (t == typeof (object))
609 return 0;
610 else
611 return 1;
614 struct LargeBitmap {
615 public object o1, o2, o3;
616 public int i;
617 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;
620 public static int test_12_large_bitmap () {
621 LargeBitmap lb = new LargeBitmap ();
622 lb.o1 = 1;
623 lb.o2 = 2;
624 lb.o3 = 3;
625 lb.o32 = 6;
627 GC.Collect (0);
629 return (int)lb.o1 + (int)lb.o2 + (int)lb.o3 + (int)lb.o32;