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