[runtime] Synthesize IList and IReadOnlyList for the element type of enum errays...
[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, ref string s) {
546                 GC.Collect (1);
547                 o.GetHashCode ();
548                 s.GetHashCode ();
549         }
550
551         class FooClass {
552                 public string s;
553         }
554
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;
561         }
562         
563         interface IFace {
564                 int foo ();
565         }
566
567         struct BarStruct : IFace {
568                 int i;
569
570                 public int foo () {
571                         GC.Collect ();
572                         return i;
573                 }
574         }
575                 
576         public static int test_0_liveness_unbox_trampoline () {
577                 var s = new BarStruct ();
578                 
579                 IFace iface = s;
580                 iface.foo ();
581                 return 0;
582         }
583
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 ());
587         }
588
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;
594         }
595
596         static ThreadLocal<object> tls;
597
598         [MethodImplAttribute (MethodImplOptions.NoInlining)]
599         static void alloc_tls_obj () {
600                 tls = new ThreadLocal<object> ();
601                 tls.Value = new object ();
602         }
603
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;
612         }
613
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;
618         }
619
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;
626
627                 GC.Collect (0);
628
629                 return (int)lb.o1 + (int)lb.o2 + (int)lb.o3 + (int)lb.o32;
630         }
631 }