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