Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / gc-test.cs
1 using System;
2 using System.Reflection;
3 using System.Runtime.CompilerServices;
4 using System.Collections;
5 using System.Threading;
6
7 /*
8  * Regression tests for the GC support in the JIT
9  */
10 #if __MOBILE__
11 class GcTests
12 #else
13 class Tests
14 #endif
15 {
16 #if !__MOBILE__
17         public static int Main (string[] args) {
18                 return TestDriver.RunTests (typeof (Tests), args);
19         }
20 #endif
21
22         public static int test_36_simple () {
23                 // Overflow the registers
24                 object o1 = (1);
25                 object o2 = (2);
26                 object o3 = (3);
27                 object o4 = (4);
28                 object o5 = (5);
29                 object o6 = (6);
30                 object o7 = (7);
31                 object o8 = (8);
32
33                 /* Prevent the variables from being local to a bb */
34                 bool b = o1 != null;
35                 GC.Collect (0);
36
37                 if (b)
38                         return (int)o1 + (int)o2 + (int)o3 + (int)o4 + (int)o5 + (int)o6 + (int)o7 + (int)o8;
39                 else
40                         return 0;
41         }
42
43         public static int test_36_liveness () {
44                 object o = 5;
45                 object o1, o2, o3, o4, o5, o6, o7, o8;
46
47                 bool b = o != null;
48
49                 GC.Collect (1);
50
51                 o1 = (1);
52                 o2 = (2);
53                 o3 = (3);
54                 o4 = (4);
55                 o5 = (5);
56                 o6 = (6);
57                 o7 = (7);
58                 o8 = (8);
59
60                 if (b)
61                         return (int)o1 + (int)o2 + (int)o3 + (int)o4 + (int)o5 + (int)o6 + (int)o7 + (int)o8;
62                 else
63                         return 0;
64         }
65
66         struct FooStruct {
67                 public object o1;
68                 public int i;
69                 public object o2;
70
71                 public FooStruct (int i1, int i, int i2) {
72                         this.o1 = i1;
73                         this.i = i;
74                         this.o2 = i2;
75                 }
76         }
77
78         public static int test_4_vtype () {
79                 FooStruct s = new FooStruct (1, 2, 3);
80
81                 GC.Collect (1);
82
83                 return (int)s.o1 + (int)s.o2;
84         }
85
86         class BigClass {
87                 public object o1, o2, o3, o4, o5, o6, o7, o8, o9, o10;
88                 public object o11, o12, o13, o14, o15, o16, o17, o18, o19, o20;
89                 public object o21, o22, o23, o24, o25, o26, o27, o28, o29, o30;
90                 public object o31, o32;
91         }
92
93         static void set_fields (BigClass b) {
94                 b.o31 = 31;
95                 b.o32 = 32;
96
97                 b.o1 = 1;
98                 b.o2 = 2;
99                 b.o3 = 3;
100                 b.o4 = 4;
101                 b.o5 = 5;
102                 b.o6 = 6;
103                 b.o7 = 7;
104                 b.o8 = 8;
105                 b.o9 = 9;
106                 b.o10 = 10;
107                 b.o11 = 11;
108                 b.o12 = 12;
109                 b.o13 = 13;
110                 b.o14 = 14;
111                 b.o15 = 15;
112                 b.o16 = 16;
113                 b.o17 = 17;
114                 b.o18 = 18;
115                 b.o19 = 19;
116                 b.o20 = 20;
117                 b.o21 = 21;
118                 b.o22 = 22;
119                 b.o23 = 23;
120                 b.o24 = 24;
121                 b.o25 = 25;
122                 b.o26 = 26;
123                 b.o27 = 27;
124                 b.o28 = 28;
125                 b.o29 = 29;
126                 b.o30 = 30;
127         }
128
129         // Test marking of objects with > 32 fields
130         public static int test_528_mark_runlength_large () {
131                 BigClass b = new BigClass ();
132
133                 /* 
134                  * Do the initialization in a separate method so no object refs remain in
135                  * spill slots.
136                  */
137                 set_fields (b);
138
139                 GC.Collect (1);
140
141                 return 
142                         (int)b.o1 + (int)b.o2 + (int)b.o3 + (int)b.o4 + (int)b.o5 +
143                         (int)b.o6 + (int)b.o7 + (int)b.o8 + (int)b.o9 + (int)b.o10 +
144                         (int)b.o11 + (int)b.o12 + (int)b.o13 + (int)b.o14 + (int)b.o15 +
145                         (int)b.o16 + (int)b.o17 + (int)b.o18 + (int)b.o19 + (int)b.o20 +
146                         (int)b.o21 + (int)b.o22 + (int)b.o23 + (int)b.o24 + (int)b.o25 +
147                         (int)b.o26 + (int)b.o27 + (int)b.o28 + (int)b.o29 + (int)b.o30 +
148                         (int)b.o31 + (int)b.o32;
149         }
150
151         /*
152          * Test liveness and loops.
153          */
154         public static int test_0_liveness_2 () {
155                 object o = new object ();
156                 for (int n = 0; n < 10; ++n) {
157                         /* Exhaust all registers so 'o' is stack allocated */
158                         int sum = 0, i, j, k, l, m;
159                         for (i = 0; i < 100; ++i)
160                                 sum ++;
161                         for (j = 0; j < 100; ++j)
162                                 sum ++;
163                         for (k = 0; k < 100; ++k)
164                                 sum ++;
165                         for (l = 0; l < 100; ++l)
166                                 sum ++;
167                         for (m = 0; m < 100; ++m)
168                                 sum ++;
169
170                         if (o != null)
171                                 o.ToString ();
172
173                         GC.Collect (1);
174
175                         if (o != null)
176                                 o.ToString ();
177
178                         sum += i + j + k;
179
180                         GC.Collect (1);
181                 }
182
183                 return 0;
184         }
185
186         /*
187          * Test liveness and stack slot sharing
188          * This doesn't work yet, its hard to make the JIT share the stack slots of the
189          * two 'o' variables.
190          */
191         public static int test_0_liveness_3 () {
192                 bool b = false;
193                 bool b2 = true;
194
195                 /* Exhaust all registers so 'o' is stack allocated */
196                 int sum = 0, i, j, k, l, m, n, s;
197                 for (i = 0; i < 100; ++i)
198                         sum ++;
199                 for (j = 0; j < 100; ++j)
200                         sum ++;
201                 for (k = 0; k < 100; ++k)
202                         sum ++;
203                 for (l = 0; l < 100; ++l)
204                         sum ++;
205                 for (m = 0; m < 100; ++m)
206                         sum ++;
207                 for (n = 0; n < 100; ++n)
208                         sum ++;
209                 for (s = 0; s < 100; ++s)
210                         sum ++;
211
212                 if (b) {
213                         object o = new object ();
214
215                         /* Make sure o is global */
216                         if (b2)
217                                 Console.WriteLine ();
218
219                         o.ToString ();
220                 }
221
222                 GC.Collect (1);
223
224                 if (b) {
225                         object o = new object ();
226
227                         /* Make sure o is global */
228                         if (b2)
229                                 Console.WriteLine ();
230
231                         o.ToString ();
232                 }
233
234                 sum += i + j + k + l + m + n + s;
235
236                 return 0;
237         }
238
239         /*
240          * Test liveness of variables used to handle items on the IL stack.
241          */
242         [MethodImplAttribute (MethodImplOptions.NoInlining)]
243         static string call1 () {
244                 return "A";
245         }
246
247         [MethodImplAttribute (MethodImplOptions.NoInlining)]
248         static string call2 () {
249                 GC.Collect (1);
250                 return "A";
251         }
252
253         public static int test_0_liveness_4 () {
254                 bool b = false;
255                 bool b2 = true;
256
257                 /* Exhaust all registers so 'o' is stack allocated */
258                 int sum = 0, i, j, k, l, m, n, s;
259                 for (i = 0; i < 100; ++i)
260                         sum ++;
261                 for (j = 0; j < 100; ++j)
262                         sum ++;
263                 for (k = 0; k < 100; ++k)
264                         sum ++;
265                 for (l = 0; l < 100; ++l)
266                         sum ++;
267                 for (m = 0; m < 100; ++m)
268                         sum ++;
269                 for (n = 0; n < 100; ++n)
270                         sum ++;
271                 for (s = 0; s < 100; ++s)
272                         sum ++;
273
274                 string o = b ? call1 () : call2 ();
275
276                 GC.Collect (1);
277
278                 sum += i + j + k + l + m + n + s;
279
280                 return 0;
281         }
282
283
284         /*
285          * Test liveness of volatile variables
286          */
287         [MethodImplAttribute (MethodImplOptions.NoInlining)]
288         static void liveness_5_1 (out object o) {
289                 o = new object ();
290         }
291
292         public static int test_0_liveness_5 () {
293                 bool b = false;
294                 bool b2 = true;
295
296                 /* Exhaust all registers so 'o' is stack allocated */
297                 int sum = 0, i, j, k, l, m, n, s;
298                 for (i = 0; i < 100; ++i)
299                         sum ++;
300                 for (j = 0; j < 100; ++j)
301                         sum ++;
302                 for (k = 0; k < 100; ++k)
303                         sum ++;
304                 for (l = 0; l < 100; ++l)
305                         sum ++;
306                 for (m = 0; m < 100; ++m)
307                         sum ++;
308                 for (n = 0; n < 100; ++n)
309                         sum ++;
310                 for (s = 0; s < 100; ++s)
311                         sum ++;
312
313                 object o;
314
315                 liveness_5_1 (out o);
316
317                 for (int x = 0; x < 10; ++x) {
318
319                         o.ToString ();
320
321                         GC.Collect (1);
322                 }
323
324                 sum += i + j + k + l + m + n + s;
325
326                 return 0;
327         }
328
329         /*
330          * Test the case when a stack slot becomes dead, then live again due to a backward
331          * branch.
332          */
333
334         [MethodImplAttribute (MethodImplOptions.NoInlining)]
335         static object alloc_obj () {
336                 return new object ();
337         }
338
339         [MethodImplAttribute (MethodImplOptions.NoInlining)]
340         static bool return_true () {
341                 return true;
342         }
343
344         [MethodImplAttribute (MethodImplOptions.NoInlining)]
345         static bool return_false () {
346                 return false;
347         }
348
349         public static int test_0_liveness_6 () {
350                 bool b = false;
351                 bool b2 = true;
352
353                 /* Exhaust all registers so 'o' is stack allocated */
354                 int sum = 0, i, j, k, l, m, n, s;
355                 for (i = 0; i < 100; ++i)
356                         sum ++;
357                 for (j = 0; j < 100; ++j)
358                         sum ++;
359                 for (k = 0; k < 100; ++k)
360                         sum ++;
361                 for (l = 0; l < 100; ++l)
362                         sum ++;
363                 for (m = 0; m < 100; ++m)
364                         sum ++;
365                 for (n = 0; n < 100; ++n)
366                         sum ++;
367                 for (s = 0; s < 100; ++s)
368                         sum ++;
369
370                 for (int x = 0; x < 10; ++x) {
371
372                         GC.Collect (1);
373
374                         object o = alloc_obj ();
375
376                         o.ToString ();
377
378                         GC.Collect (1);
379                 }
380
381                 sum += i + j + k + l + m + n + s;
382
383                 return 0;
384         }
385
386         public static int test_0_multi_dim_ref_array_wbarrier () {
387         string [,] arr = new string [256, 256];
388         for (int i = 0; i < 256; ++i) {
389             for (int j = 0; j < 100; ++j)
390                 arr [i, j] = "" + i + " " + j;
391                 }
392                 GC.Collect ();
393
394                 return 0;
395         }
396
397         /*
398          * Liveness + out of line bblocks
399          */
400         public static int test_0_liveness_7 () {
401                 /* Exhaust all registers so 'o' is stack allocated */
402                 int sum = 0, i, j, k, l, m, n, s;
403                 for (i = 0; i < 100; ++i)
404                         sum ++;
405                 for (j = 0; j < 100; ++j)
406                         sum ++;
407                 for (k = 0; k < 100; ++k)
408                         sum ++;
409                 for (l = 0; l < 100; ++l)
410                         sum ++;
411                 for (m = 0; m < 100; ++m)
412                         sum ++;
413                 for (n = 0; n < 100; ++n)
414                         sum ++;
415                 for (s = 0; s < 100; ++s)
416                         sum ++;
417
418                 // o is dead here
419                 GC.Collect (1);
420
421                 if (return_false ()) {
422                         // This bblock is in-line
423                         object o = alloc_obj ();
424                         // o is live here
425                         if (return_false ()) {
426                                 // This bblock is out-of-line, and o is live here
427                                 throw new Exception (o.ToString ());
428                         }
429                 }
430
431                 // o is dead here too
432                 GC.Collect (1);
433
434                 return 0;
435         }
436
437         // Liveness + finally clauses
438         public static int test_0_liveness_8 () {
439                 /* Exhaust all registers so 'o' is stack allocated */
440                 int sum = 0, i, j, k, l, m, n, s;
441                 for (i = 0; i < 100; ++i)
442                         sum ++;
443                 for (j = 0; j < 100; ++j)
444                         sum ++;
445                 for (k = 0; k < 100; ++k)
446                         sum ++;
447                 for (l = 0; l < 100; ++l)
448                         sum ++;
449                 for (m = 0; m < 100; ++m)
450                         sum ++;
451                 for (n = 0; n < 100; ++n)
452                         sum ++;
453                 for (s = 0; s < 100; ++s)
454                         sum ++;
455
456                 object o = null;
457                 try {
458                         o = alloc_obj ();
459                 } finally {
460                         GC.Collect (1);
461                 }
462
463                 o.GetHashCode ();
464                 return 0;
465         }
466
467         [MethodImplAttribute (MethodImplOptions.NoInlining)]
468         static object alloc_string () {
469                 return "A";
470         }
471
472         [MethodImplAttribute (MethodImplOptions.NoInlining)]
473         static object alloc_obj_and_gc () {
474                 GC.Collect (1);
475                 return new object ();
476         }
477
478         [MethodImplAttribute (MethodImplOptions.NoInlining)]
479         static void clobber_regs_and_gc () {
480                 int sum = 0, i, j, k, l, m, n, s;
481                 for (i = 0; i < 100; ++i)
482                         sum ++;
483                 for (j = 0; j < 100; ++j)
484                         sum ++;
485                 for (k = 0; k < 100; ++k)
486                         sum ++;
487                 for (l = 0; l < 100; ++l)
488                         sum ++;
489                 for (m = 0; m < 100; ++m)
490                         sum ++;
491                 for (n = 0; n < 100; ++n)
492                         sum ++;
493                 for (s = 0; s < 100; ++s)
494                         sum ++;
495                 GC.Collect (1);
496         }
497
498         [MethodImplAttribute (MethodImplOptions.NoInlining)]
499         static void liveness_9_call1 (object o1, object o2, object o3) {
500                 o1.GetHashCode ();
501                 o2.GetHashCode ();
502                 o3.GetHashCode ();
503         }
504
505         // Liveness + JIT temporaries
506         public static int test_0_liveness_9 () {
507                 // the result of alloc_obj () goes into a vreg, which gets converted to a
508                 // JIT temporary because of the branching introduced by the cast
509                 // FIXME: This doesn't crash if MONO_TYPE_I is not treated as a GC ref
510                 liveness_9_call1 (alloc_obj (), (string)alloc_string (), alloc_obj_and_gc ());
511                 return 0;
512         }
513
514         // Liveness for registers
515         public static int test_0_liveness_10 () {
516                 // Make sure this goes into a register
517                 object o = alloc_obj ();
518                 o.GetHashCode ();
519                 o.GetHashCode ();
520                 o.GetHashCode ();
521                 o.GetHashCode ();
522                 o.GetHashCode ();
523                 o.GetHashCode ();
524                 // Break the bblock so o doesn't become a local vreg
525                 if (return_true ())
526                         // Clobber it with a call and run a GC
527                         clobber_regs_and_gc ();
528                 // Access it again
529                 o.GetHashCode ();
530                 return 0;
531         }
532
533         class ObjWithShiftOp {
534                 public static ObjWithShiftOp operator >> (ObjWithShiftOp bi1, int shiftVal) {
535                         clobber_regs_and_gc ();
536                         return bi1;
537                 }
538         }
539
540         // Liveness for spill slots holding managed pointers
541         public static int test_0_liveness_11 () {
542                 ObjWithShiftOp[] arr = new ObjWithShiftOp [10];
543                 // This uses an ldelema internally
544                 // FIXME: This doesn't crash if mp-s are not correctly tracked, just writes to
545                 // an old object.
546                 arr [0] >>= 1;
547
548                 return 0;
549         }
550
551
552         [MethodImplAttribute (MethodImplOptions.NoInlining)]
553         public static void liveness_12_inner (int a, int b, int c, int d, int e, int f, object o, ref string s) {
554                 GC.Collect (1);
555                 o.GetHashCode ();
556                 s.GetHashCode ();
557         }
558
559         class FooClass {
560                 public string s;
561         }
562
563         // Liveness for param area
564         public static int test_0_liveness_12 () {
565                 var f = new FooClass () { s = "A" };
566                 // The ref argument should be passed on the stack
567                 liveness_12_inner (1, 2, 3, 4, 5, 6, new object (), ref f.s);
568                 return 0;
569         }
570         
571         interface IFace {
572                 int foo ();
573         }
574
575         struct BarStruct : IFace {
576                 int i;
577
578                 public int foo () {
579                         GC.Collect ();
580                         return i;
581                 }
582         }
583                 
584         public static int test_0_liveness_unbox_trampoline () {
585                 var s = new BarStruct ();
586                 
587                 IFace iface = s;
588                 iface.foo ();
589                 return 0;
590         }
591
592         public static void liveness_13_inner (ref ArrayList arr) {
593                 // The value of arr will be stored in a spill slot
594                 arr.Add (alloc_obj_and_gc ());
595         }
596
597         // Liveness for byref arguments in spill slots
598         public static int test_0_liveness_13 () {
599                 var arr = new ArrayList ();
600                 liveness_13_inner (ref arr);
601                 return 0;
602         }
603
604         static ThreadLocal<object> tls;
605
606         [MethodImplAttribute (MethodImplOptions.NoInlining)]
607         static void alloc_tls_obj () {
608                 tls = new ThreadLocal<object> ();
609                 tls.Value = new object ();
610         }
611
612         public static int test_0_thread_local () {
613                 alloc_tls_obj ();
614                 GC.Collect ();
615                 Type t = tls.Value.GetType ();
616                 if (t == typeof (object))
617                         return 0;
618                 else
619                         return 1;
620         }
621
622         struct LargeBitmap {
623                 public object o1, o2, o3;
624                 public int i;
625                 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;
626         }
627
628         public static int test_12_large_bitmap () {
629                 LargeBitmap lb = new LargeBitmap ();
630                 lb.o1 = 1;
631                 lb.o2 = 2;
632                 lb.o3 = 3;
633                 lb.o32 = 6;
634
635                 GC.Collect (0);
636
637                 return (int)lb.o1 + (int)lb.o2 + (int)lb.o3 + (int)lb.o32;
638         }
639 }