New test.
[mono.git] / mono / mini / jit-icalls.c
1 /*
2  * jit-icalls.c: internal calls used by the JIT
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <math.h>
12
13 #include "jit-icalls.h"
14
15 void*
16 mono_ldftn (MonoMethod *method)
17 {
18         gpointer addr;
19
20         MONO_ARCH_SAVE_REGS;
21
22         addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
23
24         return mono_create_ftnptr (mono_domain_get (), addr);
25 }
26
27 /*
28  * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
29  * synchronized wrappers to avoid infinite recursion.
30  */
31 void*
32 mono_ldftn_nosync (MonoMethod *method)
33 {
34         gpointer addr;
35
36         MONO_ARCH_SAVE_REGS;
37
38         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
39
40         return mono_create_ftnptr (mono_domain_get (), addr);
41 }
42
43 void*
44 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
45 {
46         MONO_ARCH_SAVE_REGS;
47
48         if (obj == NULL)
49                 mono_raise_exception (mono_get_exception_null_reference ());
50
51         method = mono_object_get_virtual_method (obj, method);
52
53         return mono_ldftn (method);
54 }
55
56 void
57 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
58 {
59         MONO_ARCH_SAVE_REGS;
60
61         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
62                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
63 }
64
65 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
66
67 gint64 
68 mono_llmult (gint64 a, gint64 b)
69 {
70         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
71         return a * b;
72 }
73
74 guint64  
75 mono_llmult_ovf_un (guint64 a, guint64 b)
76 {
77         guint32 al = a;
78         guint32 ah = a >> 32;
79         guint32 bl = b;
80         guint32 bh = b >> 32; 
81         guint64 res, t1;
82
83         MONO_ARCH_SAVE_REGS;
84
85         // fixme: this is incredible slow
86
87         if (ah && bh)
88                 goto raise_exception;
89
90         res = (guint64)al * (guint64)bl;
91
92         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
93
94         if (t1 > 0xffffffff)
95                 goto raise_exception;
96
97         res += ((guint64)t1) << 32; 
98
99         return res;
100
101  raise_exception:
102         mono_raise_exception (mono_get_exception_overflow ());
103         return 0;
104 }
105
106 guint64  
107 mono_llmult_ovf (gint64 a, gint64 b) 
108 {
109         guint32 al = a;
110         gint32 ah = a >> 32;
111         guint32 bl = b;
112         gint32 bh = b >> 32; 
113         /*
114         Use Karatsuba algorithm where:
115                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
116                 where Ah is the "high half" (most significant 32 bits) of a and
117                 where Al is the "low half" (least significant 32 bits) of a and
118                 where  Bh is the "high half" of b and Bl is the "low half" and
119                 where R is the Radix or "size of the half" (in our case 32 bits)
120
121         Note, for the product of two 64 bit numbers to fit into a 64
122         result, ah and/or bh must be 0.  This will save us from doing
123         the AhBh term at all.
124
125         Also note that we refactor so that we don't overflow 64 bits with 
126         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
127         */
128
129         gint64 res, t1;
130         gint32 sign;
131
132         MONO_ARCH_SAVE_REGS;
133
134         /* need to work with absoulte values, so find out what the
135            resulting sign will be and convert any negative numbers
136            from two's complement
137         */
138         sign = ah ^ bh;
139         if (ah < 0) {
140                 if (((guint32)ah == 0x80000000) && (al == 0)) {
141                         /* This has no two's complement */
142                         if (b == 0)
143                                 return 0;
144                         else if (b == 1)
145                                 return a;
146                         else
147                                 goto raise_exception;
148                 }
149
150                 /* flip the bits and add 1 */
151                 ah ^= ~0;
152                 if (al ==  0)
153                         ah += 1;
154                 else {
155                         al ^= ~0;
156                         al +=1;
157                 }
158         }
159
160         if (bh < 0) {
161                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
162                         /* This has no two's complement */
163                         if (a == 0)
164                                 return 0;
165                         else if (a == 1)
166                                 return b;
167                         else
168                                 goto raise_exception;
169                 }
170
171                 /* flip the bits and add 1 */
172                 bh ^= ~0;
173                 if (bl ==  0)
174                         bh += 1;
175                 else {
176                         bl ^= ~0;
177                         bl +=1;
178                 }
179         }
180                 
181         /* we overflow for sure if both upper halves are greater 
182            than zero because we would need to shift their 
183            product 64 bits to the left and that will not fit
184            in a 64 bit result */
185         if (ah && bh)
186                 goto raise_exception;
187         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
188                 goto raise_exception;
189
190         /* do the AlBl term first */
191         t1 = (gint64)al * (gint64)bl;
192
193         res = t1;
194
195         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
196         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
197         /* check for overflow */
198         t1 <<= 32;
199         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
200                 goto raise_exception;
201
202         res += t1;
203
204         if (res < 0)
205                 goto raise_exception;
206
207         if (sign < 0)
208                 return -res;
209         else
210                 return res;
211
212  raise_exception:
213         mono_raise_exception (mono_get_exception_overflow ());
214         return 0;
215 }
216
217 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
218
219 gint32
220 mono_idiv (gint32 a, gint32 b)
221 {
222         MONO_ARCH_SAVE_REGS;
223
224 #ifdef MONO_ARCH_NEED_DIV_CHECK
225         if (!b)
226                 mono_raise_exception (mono_get_exception_divide_by_zero ());
227         else if (b == -1 && a == (0x80000000))
228                 mono_raise_exception (mono_get_exception_arithmetic ());
229 #endif
230         return a / b;
231 }
232
233 guint32
234 mono_idiv_un (guint32 a, guint32 b)
235 {
236         MONO_ARCH_SAVE_REGS;
237
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
239         if (!b)
240                 mono_raise_exception (mono_get_exception_divide_by_zero ());
241 #endif
242         return a / b;
243 }
244
245 gint32
246 mono_irem (gint32 a, gint32 b)
247 {
248         MONO_ARCH_SAVE_REGS;
249
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
251         if (!b)
252                 mono_raise_exception (mono_get_exception_divide_by_zero ());
253         else if (b == -1 && a == (0x80000000))
254                 mono_raise_exception (mono_get_exception_arithmetic ());
255 #endif
256
257         return a % b;
258 }
259
260 guint32
261 mono_irem_un (guint32 a, guint32 b)
262 {
263         MONO_ARCH_SAVE_REGS;
264
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
266         if (!b)
267                 mono_raise_exception (mono_get_exception_divide_by_zero ());
268 #endif
269         return a % b;
270 }
271
272 #endif
273
274 #ifdef MONO_ARCH_EMULATE_MUL_DIV
275
276 gint32
277 mono_imul (gint32 a, gint32 b)
278 {
279         MONO_ARCH_SAVE_REGS;
280
281         return a * b;
282 }
283
284 gint32
285 mono_imul_ovf (gint32 a, gint32 b)
286 {
287         gint64 res;
288
289         MONO_ARCH_SAVE_REGS;
290
291         res = (gint64)a * (gint64)b;
292
293         if ((res > 0x7fffffffL) || (res < -2147483648))
294                 mono_raise_exception (mono_get_exception_overflow ());
295
296         return res;
297 }
298
299 gint32
300 mono_imul_ovf_un (guint32 a, guint32 b)
301 {
302         guint64 res;
303
304         MONO_ARCH_SAVE_REGS;
305
306         res = (guint64)a * (guint64)b;
307
308         if ((res >> 32))
309                 mono_raise_exception (mono_get_exception_overflow ());
310
311         return res;
312 }
313 #endif
314
315 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
316 double
317 mono_fdiv (double a, double b)
318 {
319         MONO_ARCH_SAVE_REGS;
320
321         return a / b;
322 }
323 #endif
324
325 gint64 
326 mono_lldiv (gint64 a, gint64 b)
327 {
328         MONO_ARCH_SAVE_REGS;
329
330 #ifdef MONO_ARCH_NEED_DIV_CHECK
331         if (!b)
332                 mono_raise_exception (mono_get_exception_divide_by_zero ());
333         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
334                 mono_raise_exception (mono_get_exception_arithmetic ());
335 #endif
336         return a / b;
337 }
338
339 gint64 
340 mono_llrem (gint64 a, gint64 b)
341 {
342         MONO_ARCH_SAVE_REGS;
343
344 #ifdef MONO_ARCH_NEED_DIV_CHECK
345         if (!b)
346                 mono_raise_exception (mono_get_exception_divide_by_zero ());
347         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
348                 mono_raise_exception (mono_get_exception_arithmetic ());
349 #endif
350         return a % b;
351 }
352
353 guint64 
354 mono_lldiv_un (guint64 a, guint64 b)
355 {
356         MONO_ARCH_SAVE_REGS;
357
358 #ifdef MONO_ARCH_NEED_DIV_CHECK
359         if (!b)
360                 mono_raise_exception (mono_get_exception_divide_by_zero ());
361 #endif
362         return a / b;
363 }
364
365 guint64 
366 mono_llrem_un (guint64 a, guint64 b)
367 {
368         MONO_ARCH_SAVE_REGS;
369
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
371         if (!b)
372                 mono_raise_exception (mono_get_exception_divide_by_zero ());
373 #endif
374         return a % b;
375 }
376
377 #endif
378
379 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
380
381 guint64 
382 mono_lshl (guint64 a, gint32 shamt)
383 {
384         guint64 res;
385
386         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
387         res = a << shamt;
388
389         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
390
391         return res;
392 }
393
394 guint64 
395 mono_lshr_un (guint64 a, gint32 shamt)
396 {
397         guint64 res;
398
399         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
400         res = a >> shamt;
401
402         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
403
404         return res;
405 }
406
407 gint64 
408 mono_lshr (gint64 a, gint32 shamt)
409 {
410         gint64 res;
411
412         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
413         res = a >> shamt;
414
415         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
416
417         return res;
418 }
419
420 #endif
421
422 #ifdef MONO_ARCH_SOFT_FLOAT
423
424 double
425 mono_fsub (double a, double b)
426 {
427         return a - b;
428 }
429
430 double
431 mono_fadd (double a, double b)
432 {
433         return a + b;
434 }
435
436 double
437 mono_fmul (double a, double b)
438 {
439         return a * b;
440 }
441
442 double
443 mono_fneg (double a)
444 {
445         return -a;
446 }
447
448 double
449 mono_fconv_r4 (double a)
450 {
451         return (float)a;
452 }
453
454 double
455 mono_conv_to_r8 (int a)
456 {
457         return (double)a;
458 }
459
460 double
461 mono_conv_to_r4 (int a)
462 {
463         return (double)(float)a;
464 }
465
466 gint8
467 mono_fconv_i1 (double a)
468 {
469         return (gint8)a;
470 }
471
472 gint16
473 mono_fconv_i2 (double a)
474 {
475         return (gint16)a;
476 }
477
478 gint32
479 mono_fconv_i4 (double a)
480 {
481         return (gint32)a;
482 }
483
484 guint8
485 mono_fconv_u1 (double a)
486 {
487         return (guint8)a;
488 }
489
490 guint16
491 mono_fconv_u2 (double a)
492 {
493         return (guint16)a;
494 }
495
496 gboolean
497 mono_fcmp_eq (double a, double b)
498 {
499         return a == b;
500 }
501
502 gboolean
503 mono_fcmp_ge (double a, double b)
504 {
505         return a >= b;
506 }
507
508 gboolean
509 mono_fcmp_gt (double a, double b)
510 {
511         return a > b;
512 }
513
514 gboolean
515 mono_fcmp_le (double a, double b)
516 {
517         return a <= b;
518 }
519
520 gboolean
521 mono_fcmp_lt (double a, double b)
522 {
523         return a < b;
524 }
525
526 gboolean
527 mono_fcmp_ne_un (double a, double b)
528 {
529         return isunordered (a, b) || a != b;
530 }
531
532 gboolean
533 mono_fcmp_ge_un (double a, double b)
534 {
535         return isunordered (a, b) || a >= b;
536 }
537
538 gboolean
539 mono_fcmp_gt_un (double a, double b)
540 {
541         return isunordered (a, b) || a > b;
542 }
543
544 gboolean
545 mono_fcmp_le_un (double a, double b)
546 {
547         return isunordered (a, b) || a <= b;
548 }
549
550 gboolean
551 mono_fcmp_lt_un (double a, double b)
552 {
553         return isunordered (a, b) || a < b;
554 }
555
556 gboolean
557 mono_fceq (double a, double b)
558 {
559         return a == b;
560 }
561
562 gboolean
563 mono_fcgt (double a, double b)
564 {
565         return a > b;
566 }
567
568 gboolean
569 mono_fcgt_un (double a, double b)
570 {
571         return a > b;
572 }
573
574 gboolean
575 mono_fclt (double a, double b)
576 {
577         return a < b;
578 }
579
580 gboolean
581 mono_fclt_un (double a, double b)
582 {
583         return a < b;
584 }
585
586 double
587 mono_fload_r4 (float *ptr)
588 {
589         return *ptr;
590 }
591
592 void
593 mono_fstore_r4 (double val, float *ptr)
594 {
595         *ptr = (float)val;
596 }
597
598 /* returns the integer bitpattern that is passed in the regs or stack */
599 guint32
600 mono_fload_r4_arg (double val)
601 {
602         float v = (float)val;
603         return *(guint32*)&v;
604 }
605
606 #endif
607
608 /**
609  * ves_array_element_address:
610  * @this: a pointer to the array object
611  *
612  * Returns: the address of an array element.
613  */
614 gpointer 
615 ves_array_element_address (MonoArray *this, ...)
616 {
617         MonoClass *class;
618         va_list ap;
619         int i, ind, esize, realidx;
620         gpointer ea;
621
622         MONO_ARCH_SAVE_REGS;
623
624         g_assert (this != NULL);
625
626         va_start(ap, this);
627
628         class = this->obj.vtable->klass;
629
630         g_assert (this->bounds != NULL);
631
632         esize = mono_array_element_size (class);
633         ind = va_arg(ap, int);
634         ind -= (int)this->bounds [0].lower_bound;
635         if ((guint32)ind >= (guint32)this->bounds [0].length)
636                 mono_raise_exception (mono_get_exception_index_out_of_range ());
637         for (i = 1; i < class->rank; i++) {
638                 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
639                 if ((guint32)realidx >= (guint32)this->bounds [i].length)
640                         mono_raise_exception (mono_get_exception_index_out_of_range ());
641                 ind *= this->bounds [i].length;
642                 ind += realidx;
643         }
644         esize *= ind;
645
646         ea = (gpointer*)(gpointer)((char*)this->vector + esize);
647
648         va_end(ap);
649
650         return ea;
651 }
652
653 MonoArray *
654 mono_array_new_va (MonoMethod *cm, ...)
655 {
656         MonoDomain *domain = mono_domain_get ();
657         va_list ap;
658         guint32 *lengths;
659         guint32 *lower_bounds;
660         int pcount;
661         int rank;
662         int i, d;
663
664         MONO_ARCH_SAVE_REGS;
665
666         pcount = mono_method_signature (cm)->param_count;
667         rank = cm->klass->rank;
668
669         va_start (ap, cm);
670         
671         lengths = alloca (sizeof (guint32) * pcount);
672         for (i = 0; i < pcount; ++i)
673                 lengths [i] = d = va_arg(ap, int);
674
675         if (rank == pcount) {
676                 /* Only lengths provided. */
677                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
678                         lower_bounds = alloca (sizeof (guint32) * rank);
679                         memset (lower_bounds, 0, sizeof (guint32) * rank);
680                 } else {
681                         lower_bounds = NULL;
682                 }
683         } else {
684                 g_assert (pcount == (rank * 2));
685                 /* lower bounds are first. */
686                 lower_bounds = lengths;
687                 lengths += rank;
688         }
689         va_end(ap);
690
691         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
692 }
693
694 gpointer
695 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
696 {
697         MonoVTable *vtable;
698         gpointer addr;
699         
700         MONO_ARCH_SAVE_REGS;
701
702         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
703
704         mono_class_init (field->parent);
705
706         vtable = mono_class_vtable (domain, field->parent);
707         if (!vtable->initialized)
708                 mono_runtime_class_init (vtable);
709
710         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
711
712         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
713                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
714         else
715                 addr = (char*)vtable->data + field->offset;
716         
717         return addr;
718 }
719
720 gpointer
721 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
722 {
723         MonoClass *handle_class;
724         gpointer res;
725
726         MONO_ARCH_SAVE_REGS;
727         res = mono_ldtoken (image, token, &handle_class, context);      
728         mono_class_init (handle_class);
729
730         return res;
731 }
732
733 guint64
734 mono_fconv_u8 (double v)
735 {
736         return (guint64)v;
737 }
738
739 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
740 gint64
741 mono_fconv_i8 (double v)
742 {
743         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
744         return (gint64)v;
745 }
746 #endif
747
748 guint32
749 mono_fconv_u4 (double v)
750 {
751         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
752         return (guint32)v;
753 }
754
755 #ifndef HAVE_TRUNC
756 /* Solaris doesn't have trunc */
757 #ifdef HAVE_AINTL
758 extern long double aintl (long double);
759 #define trunc aintl
760 #else
761 /* FIXME: This means we will never throw overflow exceptions */
762 #define trunc(v) res
763 #endif
764 #endif /* HAVE_TRUNC */
765
766 gint64
767 mono_fconv_ovf_i8 (double v)
768 {
769         gint64 res;
770
771         MONO_ARCH_SAVE_REGS;
772
773         res = (gint64)v;
774
775         if (isnan(v) || trunc (v) != res) {
776                 mono_raise_exception (mono_get_exception_overflow ());
777         }
778         return res;
779 }
780
781 guint64
782 mono_fconv_ovf_u8 (double v)
783 {
784         guint64 res;
785
786         MONO_ARCH_SAVE_REGS;
787     
788         res = (guint64)v;
789
790         if (isnan(v) || trunc (v) != res) {
791                 mono_raise_exception (mono_get_exception_overflow ());
792         }
793         return res;
794 }
795
796 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
797 double
798 mono_lconv_to_r8 (gint64 a)
799 {
800         return (double)a;
801 }
802 #endif
803
804 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
805 float
806 mono_lconv_to_r4 (gint64 a)
807 {
808         return (float)a;
809 }
810 #endif
811
812 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
813 double
814 mono_conv_to_r8_un (guint32 a)
815 {
816         return (double)a;
817 }
818 #endif
819
820 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
821 double
822 mono_lconv_to_r8_un (guint64 a)
823 {
824         return (double)a;
825 }
826 #endif
827
828 gpointer
829 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
830 {
831         MonoMethod *vmethod, *inflated;
832         gpointer addr;
833
834         if (obj == NULL)
835                 mono_raise_exception (mono_get_exception_null_reference ());
836         vmethod = mono_object_get_virtual_method (obj, method);
837
838         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
839            declaring class have been inflated.  We still need to fully inflate the method parameters.
840
841            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
842            the same context.
843         */
844         g_assert (!vmethod->klass->generic_container);
845         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->inst->is_open);
846         g_assert (!context->gmethod || !context->gmethod->inst->is_open);
847         inflated = mono_class_inflate_generic_method (vmethod, context);
848         inflated = mono_get_inflated_method (inflated);
849         addr = mono_compile_method (inflated);
850
851         /* Since this is a virtual call, have to unbox vtypes */
852         if (obj->vtable->klass->valuetype)
853                 *this_arg = mono_object_unbox (obj);
854         else
855                 *this_arg = obj;
856
857         return addr;
858 }
859
860 MonoString*
861 mono_helper_ldstr (MonoImage *image, guint32 idx)
862 {
863         return mono_ldstr (mono_domain_get (), image, idx);
864 }
865
866 MonoString*
867 mono_helper_ldstr_mscorlib (guint32 idx)
868 {
869         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
870 }
871
872 MonoObject*
873 mono_helper_newobj_mscorlib (guint32 idx)
874 {
875         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
876         
877         g_assert (klass);
878
879         return mono_object_new (mono_domain_get (), klass);
880 }