New test.
[mono.git] / mono / mini / objects.cs
1 using System;
2 using System.Reflection;
3 using System.Runtime.InteropServices;
4 using System.Runtime.CompilerServices;
5
6 /*
7  * Regression tests for the mono JIT.
8  *
9  * Each test needs to be of the form:
10  *
11  * static int test_<result>_<name> ();
12  *
13  * where <result> is an integer (the value that needs to be returned by
14  * the method to make it pass.
15  * <name> is a user-displayed name used to identify the test.
16  *
17  * The tests can be driven in two ways:
18  * *) running the program directly: Main() uses reflection to find and invoke
19  *      the test methods (this is useful mostly to check that the tests are correct)
20  * *) with the --regression switch of the jit (this is the preferred way since
21  *      all the tests will be run with optimizations on and off)
22  *
23  * The reflection logic could be moved to a .dll since we need at least another
24  * regression test file written in IL code to have better control on how
25  * the IL code looks.
26  */
27
28 struct Simple {
29         public int a;
30         public byte b;
31         public short c;
32         public long d;
33 }
34
35 struct Small {
36         public byte b1;
37         public byte b2;
38 }
39
40 // Size=2, Align=1
41 struct Foo {
42         bool b1;
43         bool b2;
44 }
45
46 struct Large {
47         int one;
48         int two;
49         long three;
50         long four;
51         int five;
52         long six;
53         int seven;
54         long eight;
55         long nine;
56         long ten;
57
58         public void populate ()
59         {
60                 one = 1; two = 2;
61                 three = 3; four = 4;
62                 five = 5; six = 6;
63                 seven = 7; eight = 8;
64                 nine = 9; ten = 10;
65         }
66         public bool check ()
67         {
68                 return one == 1  && two == 2  &&
69                         three == 3  && four == 4  &&
70                         five == 5  && six == 6  &&
71                         seven == 7  && eight == 8  &&
72                         nine == 9  && ten == 10;
73         }
74 }
75
76 class Sample {
77         public int a;
78         public Sample (int v) {
79                 a = v;
80         }
81 }
82
83 [StructLayout ( LayoutKind.Explicit )]
84 struct StructWithBigOffsets {
85                 [ FieldOffset(10000) ] public byte b;
86                 [ FieldOffset(10001) ] public sbyte sb;
87                 [ FieldOffset(11000) ] public short s;
88                 [ FieldOffset(11002) ] public ushort us;
89                 [ FieldOffset(12000) ] public uint i;
90                 [ FieldOffset(12004) ] public int si;
91                 [ FieldOffset(13000) ] public long l;
92                 [ FieldOffset(14000) ] public float f;
93                 [ FieldOffset(15000) ] public double d;
94 }
95
96 enum SampleEnum {
97         A,
98         B,
99         C
100 }
101
102 class Tests {
103
104         static int Main () {
105                 return TestDriver.RunTests (typeof (Tests));
106         }
107         
108         static int test_0_return () {
109                 Simple s;
110                 s.a = 1;
111                 s.b = 2;
112                 s.c = (short)(s.a + s.b);
113                 s.d = 4;
114                 return s.a - 1;
115         }
116
117         static int test_0_string_access () {
118                 string s = "Hello";
119                 if (s [1] != 'e')
120                         return 1;
121                 return 0;
122         }
123
124         static int test_0_string_virtual_call () {
125                 string s = "Hello";
126                 string s2 = s.ToString ();
127                 if (s2 [1] != 'e')
128                         return 1;
129                 return 0;
130         }
131
132         static int test_0_iface_call () {
133                 string s = "Hello";
134                 object o = ((ICloneable)s).Clone ();
135                 return 0;
136         }
137
138         static int test_5_newobj () {
139                 Sample s = new Sample (5);
140                 return s.a;
141         }
142
143         static int test_4_box () {
144                 object obj = 4;
145                 return (int)obj;
146         }
147
148         static int test_0_enum_unbox () {
149                 SampleEnum x = SampleEnum.A;
150                 object o = x;
151                 
152                 int res = 1;
153
154                 res = (int)o;
155                 
156                 return res;
157         }
158         
159         static Simple get_simple (int v) {
160                 Simple r = new Simple ();
161                 r.a = v;
162                 r.b = (byte)(v + 1);
163                 r.c = (short)(v + 2);
164                 r.d = v + 3;
165
166                 return r;
167         }
168
169         static int test_3_return_struct () {
170                 Simple v = get_simple (1);
171
172                 if (v.a != 1)
173                         return 0;
174                 if (v.b != 2)
175                         return 0;
176                 if (v.c != 3)
177                         return 0;
178                 if (v.d != 4)
179                         return 0;
180                 return 3;
181         }
182
183         public virtual Simple v_get_simple (int v)
184         {
185                 return get_simple (v);
186         }
187         
188         static int test_2_return_struct_virtual () {
189                 Tests t = new Tests ();
190                 Simple v = t.v_get_simple (2);
191
192                 if (v.a != 2)
193                         return 0;
194                 if (v.b != 3)
195                         return 0;
196                 if (v.c != 4)
197                         return 0;
198                 if (v.d != 5)
199                         return 0;
200                 return 2;
201         }
202
203         static int receive_simple (int a, Simple v, int b) {
204                 if (v.a != 1)
205                         return 1;
206                 if (v.b != 2)
207                         return 2;
208                 if (v.c != 3)
209                         return 3;
210                 if (v.d != 4)
211                         return 4;
212                 if (a != 7)
213                         return 5;
214                 if (b != 9)
215                         return 6;
216                 return 0;
217         }
218         
219         static int test_5_pass_struct () {
220                 Simple v = get_simple (1);
221                 if (receive_simple (7, v, 9) != 0)
222                         return 0;
223                 if (receive_simple (7, get_simple (1), 9) != 0)
224                         return 1;
225                 return 5;
226         }
227
228         // Test alignment of small structs
229
230         static Small get_small (byte v) {
231                 Small r = new Small ();
232         
233                 r.b1 = v;
234                 r.b2 = (byte)(v + 1);
235
236                 return r;
237         }
238
239         static Small return_small (Small s) {
240                 return s;
241         }
242
243         static int receive_small (int a, Small v, int b) {
244                 if (v.b1 != 1)
245                         return 1;
246                 if (v.b2 != 2)
247                         return 2;
248                 return 0;
249         }
250
251         static int test_5_pass_small_struct () {
252                 Small v = get_small (1);
253                 if (receive_small (7, v, 9) != 0)
254                         return 0;
255                 if (receive_small (7, get_small (1), 9) != 0)
256                         return 1;
257                 v = return_small (v);
258                 if (v.b1 != 1)
259                         return 2;
260                 if (v.b2 != 2)
261                         return 3;
262                 return 5;
263         }
264
265         struct AStruct {
266                 public int i;
267
268                 public AStruct (int i) {
269                         this.i = i;
270                 }
271
272                 public override int GetHashCode () {
273                         return i;
274                 }
275         }
276
277         // Test that vtypes are unboxed during a virtual call
278         static int test_44_unbox_trampoline () {
279                 AStruct s = new AStruct (44);
280                 object o = s;
281                 return o.GetHashCode ();
282         }
283
284         static int test_0_unbox_trampoline2 () {
285                 int i = 12;
286                 object o = i;
287                         
288                 if (i.ToString () != "12")
289                         return 1;
290                 if (((Int32)o).ToString () != "12")
291                         return 2;
292                 if (o.ToString () != "12")
293                         return 3;
294                 return 0;
295         }
296
297         // Test fields with big offsets
298         static int test_0_fields_with_big_offsets () {
299                 StructWithBigOffsets s = new StructWithBigOffsets ();
300                 StructWithBigOffsets s2 = new StructWithBigOffsets ();
301
302                 s.b = 0xde;
303                 s.sb = 0xe;
304                 s.s = 0x12de;
305                 s.us = 0x12da;
306                 s.i = 0xdeadbeef;
307                 s.si = 0xcafe;
308                 s.l = 0xcafebabe;
309                 s.f = 3.14F;
310                 s.d = 3.14;
311
312                 s2.b = s.b;
313                 s2.sb = s.sb;
314                 s2.s = s.s;
315                 s2.us = s.us;
316                 s2.i = s.i;
317                 s2.si = s.si;
318                 s2.l = s.l;
319                 s2.f = s.f;
320                 s2.d = s.d;
321
322                 if (s2.b != 0xde)
323                         return 1;
324                 if (s2.s != 0x12de)
325                         return 2;
326                 if (s2.i != 0xdeadbeef)
327                         return 3;
328                 if (s2.l != 0xcafebabe)
329                         return 4;
330                 if (s2.f != 3.14F)
331                         return 5;
332                 if (s2.d != 3.14)
333                         return 6;
334                 if (s2.sb != 0xe)
335                         return 7;
336                 if (s2.us != 0x12da)
337                         return 9;
338                 if (s2.si != 0xcafe)
339                         return 10;
340
341                 return 0;
342         }
343
344         class TestRegA {
345
346                 long buf_start;
347                 int buf_length, buf_offset;
348
349                 public TestRegA () {
350                         buf_start = 0;
351                         buf_length = 0;
352                         buf_offset = 0;
353                 }
354         
355                 public long Seek (long position) {
356                         long pos = position;
357                         /* interaction between the register allocator and
358                          * allocating arguments to registers */
359                         if (pos >= buf_start && pos <= buf_start + buf_length) {
360                                 buf_offset = (int) (pos - buf_start);
361                                 return pos;
362                         }
363                         return buf_start;
364                 }
365
366         }
367
368         static int test_0_seektest () {
369                 TestRegA t = new TestRegA ();
370                 return (int)t.Seek (0);
371         }
372
373         class Super : ICloneable {
374                 public virtual object Clone () {
375                         return null;
376                 }
377         }
378         class Duper: Super {
379         }
380
381         static int test_0_null_cast () {
382                 object o = null;
383
384                 Super s = (Super)o;
385
386                 return 0;
387         }
388         
389         static int test_0_super_cast () {
390                 Duper d = new Duper ();
391                 Super sup = d;
392                 Object o = d;
393
394                 if (!(o is Super))
395                         return 1;
396                 try {
397                         d = (Duper)sup;
398                 } catch {
399                         return 2;
400                 }
401                 if (!(d is Object))
402                         return 3;
403                 try {
404                         d = (Duper)(object)sup;
405                 } catch {
406                         return 4;
407                 }
408                 return 0;
409         }
410
411         static int test_0_super_cast_array () {
412                 Duper[] d = new Duper [0];
413                 Super[] sup = d;
414                 Object[] o = d;
415
416                 if (!(o is Super[]))
417                         return 1;
418                 try {
419                         d = (Duper[])sup;
420                 } catch {
421                         return 2;
422                 }
423                 if (!(d is Object[]))
424                         return 3;
425                 try {
426                         d = (Duper[])(object[])sup;
427                 } catch {
428                         return 4;
429                 }
430                 return 0;
431         }
432
433         static int test_0_multi_array_cast () {
434                 Duper[,] d = new Duper [1, 1];
435                 object[,] o = d;
436
437                 try {
438                         o [0, 0] = new Super ();
439                         return 1;
440                 }
441                 catch (ArrayTypeMismatchException) {
442                 }
443
444                 return 0;
445         }
446
447         static int test_0_vector_array_cast () {
448                 Array arr1 = Array.CreateInstance (typeof (int), new int[] {1}, new int[] {0});
449                 Array arr2 = Array.CreateInstance (typeof (int), new int[] {1}, new int[] {10});
450
451                 if (arr1.GetType () != typeof (int[]))
452                         return 1;
453
454                 if (arr2.GetType () == typeof (int[]))
455                         return 2;
456
457                 int[] b;
458
459                 b = (int[])arr1;
460
461                 try {
462                         b = (int[])arr2;
463                         return 3;
464                 }
465                 catch (InvalidCastException) {
466                 }
467
468                 if (arr2 is int[])
469                         return 4;
470
471                 return 0;
472         }
473
474         static int test_0_enum_array_cast () {
475                 TypeCode[] tc = new TypeCode [0];
476                 object[] oa;
477                 ValueType[] vta;
478                 int[] inta;
479                 Array a = tc;
480                 bool ok;
481
482                 if (a is object[])
483                         return 1;
484                 if (a is ValueType[])
485                         return 2;
486                 if (a is Enum[])
487                         return 3;
488                 try {
489                         ok = false;
490                         oa = (object[])a;
491                 } catch {
492                         ok = true;
493                 }
494                 if (!ok)
495                         return 4;
496                 try {
497                         ok = false;
498                         vta = (ValueType[])a;
499                 } catch {
500                         ok = true;
501                 }
502                 if (!ok)
503                         return 5;
504                 try {
505                         ok = true;
506                         inta = (int[])a;
507                 } catch {
508                         ok = false;
509                 }
510                 if (!ok)
511                         return 6;
512                 return 0;
513         }
514
515         static int test_0_more_cast_corner_cases () {
516                 ValueType[] vta = new ValueType [0];
517                 Enum[] ea = new Enum [0];
518                 Array a = vta;
519                 object[] oa;
520                 bool ok;
521
522                 if (!(a is object[]))
523                         return 1;
524                 if (!(a is ValueType[]))
525                         return 2;
526                 if (a is Enum[])
527                         return 3;
528                 a = ea;
529                 if (!(a is object[]))
530                         return 4;
531                 if (!(a is ValueType[]))
532                         return 5;
533                 if (!(a is Enum[]))
534                         return 6;
535
536                 try {
537                         ok = true;
538                         oa = (object[])a;
539                 } catch {
540                         ok = false;
541                 }
542                 if (!ok)
543                         return 7;
544         
545                 try {
546                         ok = true;
547                         oa = (Enum[])a;
548                 } catch {
549                         ok = false;
550                 }
551                 if (!ok)
552                         return 8;
553         
554                 try {
555                         ok = true;
556                         oa = (ValueType[])a;
557                 } catch {
558                         ok = false;
559                 }
560                 if (!ok)
561                         return 9;
562
563                 a = vta;
564                 try {
565                         ok = true;
566                         oa = (object[])a;
567                 } catch {
568                         ok = false;
569                 }
570                 if (!ok)
571                         return 10;
572         
573                 try {
574                         ok = true;
575                         oa = (ValueType[])a;
576                 } catch {
577                         ok = false;
578                 }
579                 if (!ok)
580                         return 11;
581         
582                 try {
583                         ok = false;
584                         vta = (Enum[])a;
585                 } catch {
586                         ok = true;
587                 }
588                 if (!ok)
589                         return 12;
590                 return 0;
591         }
592
593         static int test_0_cast_iface_array () {
594                 object o = new ICloneable [0];
595                 object o2 = new Duper [0];
596                 object t;
597                 bool ok;
598
599                 if (!(o is object[]))
600                         return 1;
601                 if (!(o2 is ICloneable[]))
602                         return 2;
603
604                 try {
605                         ok = true;
606                         t = (object[])o;
607                 } catch {
608                         ok = false;
609                 }
610                 if (!ok)
611                         return 3;
612         
613                 try {
614                         ok = true;
615                         t = (ICloneable[])o2;
616                 } catch {
617                         ok = false;
618                 }
619                 if (!ok)
620                         return 4;
621
622                 try {
623                         ok = true;
624                         t = (ICloneable[])o;
625                 } catch {
626                         ok = false;
627                 }
628                 if (!ok)
629                         return 5;
630
631                 if (!(o is ICloneable[]))
632                         return 6;
633
634                 /* add tests for interfaces that 'inherit' interfaces */
635                 return 0;
636         }
637
638         private static int[] daysmonthleap = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
639
640         private static int AbsoluteDays (int year, int month, int day)
641         {
642                 int temp = 0, m = 1;
643                 int[] days = daysmonthleap;
644                 while (m < month)
645                         temp += days[m++];
646                 return ((day-1) + temp + (365* (year-1)) + ((year-1)/4) - ((year-1)/100) + ((year-1)/400));
647         }
648
649         static int test_719162_complex_div () {
650                 int adays = AbsoluteDays (1970, 1, 1);
651                 return adays;
652         }
653
654         delegate int GetIntDel ();
655
656         static int return4 () {
657                 return 4;
658         }
659
660         int return5 () {
661                 return 5;
662         }
663
664         static int test_2_static_delegate () {
665                 GetIntDel del = new GetIntDel (return4);
666                 int v = del ();
667                 if (v != 4)
668                         return 0;
669                 return 2;
670         }
671
672         static int test_2_instance_delegate () {
673                 Tests t = new Tests ();
674                 GetIntDel del = new GetIntDel (t.return5);
675                 int v = del ();
676                 if (v != 5)
677                         return 0;
678                 return 2;
679         }
680
681         static int test_1_store_decimal () {
682                 decimal[,] a = {{1}};
683
684                 if (a[0,0] != 1m)
685                         return 0;
686                 return 1;
687         }
688
689         static int test_2_intptr_stobj () {
690                 System.IntPtr [] arr = { new System.IntPtr () };
691
692                 if (arr [0] != (System.IntPtr)0)
693                         return 1;
694                 return 2;
695         }
696
697         static int llmult (int a, int b, int c, int d) {
698                 return a + b + c + d;
699         }
700
701         /* 
702          * Test that evaluation of complex arguments does not overwrite the
703          * arguments already in outgoing registers.
704          */
705         static int test_155_regalloc () {
706                 int a = 10;
707                 int b = 10;
708
709                 int c = 0;
710                 int d = 0;
711                 int[] arr = new int [5];
712
713                 return llmult (arr [c + d], 150, 5, 0);
714         }
715
716         static bool large_struct_test (Large a, Large b, Large c, Large d)
717         {
718                 if (!a.check ()) return false;
719                 if (!b.check ()) return false;
720                 if (!c.check ()) return false;
721                 if (!d.check ()) return false;
722                 return true;
723         }
724
725         static int test_2_large_struct_pass ()
726         {
727                 Large a, b, c, d;
728                 a = new Large ();
729                 b = new Large ();
730                 c = new Large ();
731                 d = new Large ();
732                 a.populate ();
733                 b.populate ();
734                 c.populate ();
735                 d.populate ();
736                 if (large_struct_test (a, b, c, d))
737                         return 2;
738                 return 0;
739         }
740
741         public static unsafe int test_0_pin_string () {
742                 string x = "xxx";
743                 fixed (char *c = x) {
744                         if (*c != 'x')
745                                 return 1;
746                 }
747                 return 0;
748         }
749         
750         public static int my_flags;
751         public static int test_0_and_cmp_static ()
752         {
753                 
754                 /* various forms of test [mem], imm */
755                 
756                 my_flags = 0x01020304;
757                 
758                 if ((my_flags & 0x01020304) == 0)
759                         return 1;
760                 
761                 if ((my_flags & 0x00000304) == 0)
762                         return 2;
763                 
764                 if ((my_flags & 0x00000004) == 0)
765                         return 3;
766                 
767                 if ((my_flags & 0x00000300) == 0)
768                         return 4;
769                 
770                 if ((my_flags & 0x00020000) == 0)
771                         return 5;
772                 
773                 if ((my_flags & 0x01000000) == 0)
774                         return 6;
775                 
776                 return 0;
777         }
778         
779         static byte b;
780         public static int test_0_byte_compares ()
781         {
782                 b = 0xff;
783                 if (b == -1)
784                         return 1;
785                 b = 0;
786                 if (!(b < System.Byte.MaxValue))
787                         return 2;
788                 
789                 if (!(b <= System.Byte.MaxValue))
790                         return 3;
791                 
792                 return 0;
793         }
794
795         public static int test_71_long_shift_right () {
796                 ulong value = 38654838087;
797                 int x = 0;
798                 byte [] buffer = new byte [1];
799                 buffer [x] = ((byte)(value >> x));
800                 return buffer [x];
801         }
802         
803         static long x;
804         public static int test_0_addsub_mem ()
805         {
806                 x = 0;
807                 x += 5;
808                 
809                 if (x != 5)
810                         return 1;
811                 
812                 x -= 10;
813                 
814                 if (x != -5)
815                         return 2;
816                 
817                 return 0;
818         }
819         
820         static ulong y;
821         public static int test_0_sh32_mem ()
822         {
823                 y = 0x0102130405060708;
824                 y >>= 32;
825                 
826                 if (y != 0x01021304)
827                         return 1;
828                 
829                 y = 0x0102130405060708;
830                 y <<= 32;
831                 
832                 if (y != 0x0506070800000000)
833                         return 2;
834                 
835                 x = 0x0102130405060708;
836                 x <<= 32;
837                 
838                 if (x != 0x0506070800000000)
839                         return 2;
840                 
841                 return 0;
842         }
843
844
845         static uint dum_de_dum = 1;
846         static int test_0_long_arg_opt ()
847         {
848                 return Foo (0x1234567887654321, dum_de_dum);
849         }
850         
851         static int Foo (ulong x, ulong y)
852         {
853                 if (x != 0x1234567887654321)
854                         return 1;
855                 
856                 if (y != 1)
857                         return 2;
858                 
859                 return 0;
860         }
861         
862         static int test_0_long_ret_opt ()
863         {
864                 ulong x = X ();
865                 if (x != 0x1234567887654321)
866                         return 1;
867                 ulong y = Y ();
868                 if (y != 1)
869                         return 2;
870                 
871                 return 0;
872         }
873         
874         static ulong X ()
875         {
876                 return 0x1234567887654321;
877         }
878         
879         static ulong Y ()
880         {
881                 return dum_de_dum;
882         }
883
884         /* from bug# 71515 */
885         static int counter = 0;
886         static bool WriteStuff () {
887                 counter = 10;
888                 return true;
889         }
890         static int test_0_cond_branch_side_effects () {
891                 counter = 5;
892                 if (WriteStuff());
893                 if (counter == 10)
894                         return 0;
895                 return 1;
896         }
897
898         // bug #74992
899         public static int arg_only_written (string file_name, int[]
900 ncells ) {
901                 if (file_name == null)
902                         return 1;
903
904                 ncells = foo ();
905                 bar (ncells [0]);
906
907                 return 0;
908         }
909
910         public static int[] foo () {
911                 return new int [3];
912         }
913
914         public static void bar (int i) {
915         }
916         
917
918         public static int test_0_arg_only_written ()
919         {
920                 return arg_only_written ("md.in", null);
921         }               
922
923         static long position = 0;
924
925         public static int test_4_static_inc_long () {
926
927                 int count = 4;
928
929                 position = 0;
930
931                 position += count;
932
933                 return (int)position;
934         }
935
936         struct FooStruct {
937
938                 public FooStruct (long l) {
939                 }
940         }
941
942         static int test_0_calls_opcode_emulation () {
943                 // Test that emulated opcodes do not clobber arguments already in
944                 // out registers
945                 checked {
946                         long val = 10000;
947                         new FooStruct (val * 10000);
948                 }
949                 return 0;
950         }
951
952         static int test_0_intrins_string_length () {
953                 string s = "ABC";
954
955                 return (s.Length == 3) ? 0 : 1;
956         }
957
958         static int test_0_intrins_string_chars () {
959                 string s = "ABC";
960
961                 return (s [0] == 'A' && s [1] == 'B' && s [2] == 'C') ? 0 : 1;
962         }
963
964         static int test_0_intrins_object_gettype () {
965                 object o = 1;
966
967                 return (o.GetType () == typeof (int)) ? 0 : 1;
968         }
969
970         static int test_0_intrins_object_gethashcode () {
971                 object o = new Object ();
972
973                 return (o.GetHashCode () == o.GetHashCode ()) ? 0 : 1;
974         }
975
976         class FooClass {
977         }
978
979         static int test_0_intrins_object_ctor () {
980                 object o = new FooClass ();
981
982                 return (o != null) ? 0 : 1;
983         }
984
985         static int test_0_intrins_array_rank () {
986                 int[,] a = new int [10, 10];
987
988                 return (a.Rank == 2) ? 0 : 1;
989         }
990
991         static int test_0_intrins_array_length () {
992                 int[,] a = new int [10, 10];
993                 Array a2 = a;
994
995                 return (a2.Length == 100) ? 0 : 1;
996         }
997
998         static int test_0_intrins_runtimehelpers_offset_to_string_data () {
999                 int i = RuntimeHelpers.OffsetToStringData;
1000                 
1001                 return i - i;
1002         }
1003
1004         public class Bar {
1005                 bool allowLocation = true;
1006         Foo f = new Foo ();     
1007         }
1008
1009         static int test_0_regress_78990_unaligned_structs () {
1010                 new Bar ();
1011
1012                 return 0;
1013         }
1014 }
1015