Merge pull request #439 from mono-soc-2012/garyb/iconfix
[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
11 class Tests {
12
13         static int Main () {
14                 return TestDriver.RunTests (typeof (Tests));
15         }
16
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);
27
28                 /* Prevent the variables from being local to a bb */
29                 bool b = o1 != null;
30                 GC.Collect (0);
31
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;
36         }
37
38         public static int test_36_liveness () {
39                 object o = 5;
40                 object o1, o2, o3, o4, o5, o6, o7, o8;
41
42                 bool b = o != null;
43
44                 GC.Collect (1);
45
46                 o1 = (1);
47                 o2 = (2);
48                 o3 = (3);
49                 o4 = (4);
50                 o5 = (5);
51                 o6 = (6);
52                 o7 = (7);
53                 o8 = (8);
54
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;
59         }
60
61         struct FooStruct {
62                 public object o1;
63                 public int i;
64                 public object o2;
65
66                 public FooStruct (int i1, int i, int i2) {
67                         this.o1 = i1;
68                         this.i = i;
69                         this.o2 = i2;
70                 }
71         }
72
73         public static int test_4_vtype () {
74                 FooStruct s = new FooStruct (1, 2, 3);
75
76                 GC.Collect (1);
77
78                 return (int)s.o1 + (int)s.o2;
79         }
80
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;
86         }
87
88         static void set_fields (BigClass b) {
89                 b.o31 = 31;
90                 b.o32 = 32;
91
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;
122         }
123
124         // Test marking of objects with > 32 fields
125         public static int test_528_mark_runlength_large () {
126                 BigClass b = new BigClass ();
127
128                 /* 
129                  * Do the initialization in a separate method so no object refs remain in
130                  * spill slots.
131                  */
132                 set_fields (b);
133
134                 GC.Collect (1);
135
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;
144         }
145
146         /*
147          * Test liveness and loops.
148          */
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 ++;
164
165                         if (o != null)
166                                 o.ToString ();
167
168                         GC.Collect (1);
169
170                         if (o != null)
171                                 o.ToString ();
172
173                         sum += i + j + k;
174
175                         GC.Collect (1);
176                 }
177
178                 return 0;
179         }
180
181         /*
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.
185          */
186         public static int test_0_liveness_3 () {
187                 bool b = false;
188                 bool b2 = true;
189
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 ++;
206
207                 if (b) {
208                         object o = new object ();
209
210                         /* Make sure o is global */
211                         if (b2)
212                                 Console.WriteLine ();
213
214                         o.ToString ();
215                 }
216
217                 GC.Collect (1);
218
219                 if (b) {
220                         object o = new object ();
221
222                         /* Make sure o is global */
223                         if (b2)
224                                 Console.WriteLine ();
225
226                         o.ToString ();
227                 }
228
229                 sum += i + j + k + l + m + n + s;
230
231                 return 0;
232         }
233
234         /*
235          * Test liveness of variables used to handle items on the IL stack.
236          */
237         [MethodImplAttribute (MethodImplOptions.NoInlining)]
238         static string call1 () {
239                 return "A";
240         }
241
242         [MethodImplAttribute (MethodImplOptions.NoInlining)]
243         static string call2 () {
244                 GC.Collect (1);
245                 return "A";
246         }
247
248         public static int test_0_liveness_4 () {
249                 bool b = false;
250                 bool b2 = true;
251
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 ++;
268
269                 string o = b ? call1 () : call2 ();
270
271                 GC.Collect (1);
272
273                 sum += i + j + k + l + m + n + s;
274
275                 return 0;
276         }
277
278
279         /*
280          * Test liveness of volatile variables
281          */
282         [MethodImplAttribute (MethodImplOptions.NoInlining)]
283         static void liveness_5_1 (out object o) {
284                 o = new object ();
285         }
286
287         public static int test_0_liveness_5 () {
288                 bool b = false;
289                 bool b2 = true;
290
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 ++;
307
308                 object o;
309
310                 liveness_5_1 (out o);
311
312                 for (int x = 0; x < 10; ++x) {
313
314                         o.ToString ();
315
316                         GC.Collect (1);
317                 }
318
319                 sum += i + j + k + l + m + n + s;
320
321                 return 0;
322         }
323
324         /*
325          * Test the case when a stack slot becomes dead, then live again due to a backward
326          * branch.
327          */
328
329         [MethodImplAttribute (MethodImplOptions.NoInlining)]
330         static object alloc_obj () {
331                 return new object ();
332         }
333
334         [MethodImplAttribute (MethodImplOptions.NoInlining)]
335         static bool return_true () {
336                 return true;
337         }
338
339         [MethodImplAttribute (MethodImplOptions.NoInlining)]
340         static bool return_false () {
341                 return false;
342         }
343
344         public static int test_0_liveness_6 () {
345                 bool b = false;
346                 bool b2 = true;
347
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 ++;
364
365                 for (int x = 0; x < 10; ++x) {
366
367                         GC.Collect (1);
368
369                         object o = alloc_obj ();
370
371                         o.ToString ();
372
373                         GC.Collect (1);
374                 }
375
376                 sum += i + j + k + l + m + n + s;
377
378                 return 0;
379         }
380
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;
386                 }
387                 GC.Collect ();
388
389                 return 0;
390         }
391
392         /*
393          * Liveness + out of line bblocks
394          */
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 ++;
412
413                 // o is dead here
414                 GC.Collect (1);
415
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 ());
423                         }
424                 }
425
426                 // o is dead here too
427                 GC.Collect (1);
428
429                 return 0;
430         }
431
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 ++;
450
451                 object o = null;
452                 try {
453                         o = alloc_obj ();
454                 } finally {
455                         GC.Collect (1);
456                 }
457
458                 o.GetHashCode ();
459                 return 0;
460         }
461
462         [MethodImplAttribute (MethodImplOptions.NoInlining)]
463         static object alloc_string () {
464                 return "A";
465         }
466
467         [MethodImplAttribute (MethodImplOptions.NoInlining)]
468         static object alloc_obj_and_gc () {
469                 GC.Collect (1);
470                 return new object ();
471         }
472
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);
491         }
492
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 ();
498         }
499
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;
507         }
508
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;
526         }
527
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;
535
536                 return 0;
537         }
538
539         public static Tests operator >> (Tests bi1, int shiftVal) {
540                 clobber_regs_and_gc ();
541                 return bi1;
542         }
543
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) {
546                 GC.Collect (1);
547                 o.GetHashCode ();
548         }
549
550         // Liveness for param area
551         public static int test_0_liveness_12 () {
552                 // The ref argument should be passed on the stack
553                 liveness_12_inner (1, 2, 3, 4, 5, 6, new object ());
554                 return 0;
555         }
556
557         public static void liveness_13_inner (ref ArrayList arr) {
558                 // The value of arr will be stored in a spill slot
559                 arr.Add (alloc_obj_and_gc ());
560         }
561
562         // Liveness for byref arguments in spill slots
563         public static int test_0_liveness_13 () {
564                 var arr = new ArrayList ();
565                 liveness_13_inner (ref arr);
566                 return 0;
567         }
568
569         static ThreadLocal<object> tls;
570
571         [MethodImplAttribute (MethodImplOptions.NoInlining)]
572         static void alloc_tls_obj () {
573                 tls = new ThreadLocal<object> ();
574                 tls.Value = new object ();
575         }
576
577         public static int test_0_thread_local () {
578                 alloc_tls_obj ();
579                 GC.Collect ();
580                 Type t = tls.Value.GetType ();
581                 if (t == typeof (object))
582                         return 0;
583                 else
584                         return 1;
585         }
586 }