Fri Nov 10 18:38:15 CET 2006 Paolo Molaro <lupus@ximian.com>
[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 gint8
461 mono_fconv_i1 (double a)
462 {
463         return (gint8)a;
464 }
465
466 gint16
467 mono_fconv_i2 (double a)
468 {
469         return (gint16)a;
470 }
471
472 gint32
473 mono_fconv_i4 (double a)
474 {
475         return (gint32)a;
476 }
477
478 guint8
479 mono_fconv_u1 (double a)
480 {
481         return (guint8)a;
482 }
483
484 guint16
485 mono_fconv_u2 (double a)
486 {
487         return (guint16)a;
488 }
489
490 gboolean
491 mono_fcmp_eq (double a, double b)
492 {
493         return a == b;
494 }
495
496 gboolean
497 mono_fcmp_ge (double a, double b)
498 {
499         return a >= b;
500 }
501
502 gboolean
503 mono_fcmp_gt (double a, double b)
504 {
505         return a > b;
506 }
507
508 gboolean
509 mono_fcmp_le (double a, double b)
510 {
511         return a <= b;
512 }
513
514 gboolean
515 mono_fcmp_lt (double a, double b)
516 {
517         return a < b;
518 }
519
520 gboolean
521 mono_fcmp_ne_un (double a, double b)
522 {
523         return isunordered (a, b) || a != b;
524 }
525
526 gboolean
527 mono_fcmp_ge_un (double a, double b)
528 {
529         return isunordered (a, b) || a >= b;
530 }
531
532 gboolean
533 mono_fcmp_gt_un (double a, double b)
534 {
535         return isunordered (a, b) || a > b;
536 }
537
538 gboolean
539 mono_fcmp_le_un (double a, double b)
540 {
541         return isunordered (a, b) || a <= b;
542 }
543
544 gboolean
545 mono_fcmp_lt_un (double a, double b)
546 {
547         return isunordered (a, b) || a < b;
548 }
549
550 gboolean
551 mono_fceq (double a, double b)
552 {
553         return a == b;
554 }
555
556 gboolean
557 mono_fcgt (double a, double b)
558 {
559         return a > b;
560 }
561
562 gboolean
563 mono_fcgt_un (double a, double b)
564 {
565         return a > b;
566 }
567
568 gboolean
569 mono_fclt (double a, double b)
570 {
571         return a < b;
572 }
573
574 gboolean
575 mono_fclt_un (double a, double b)
576 {
577         return a < b;
578 }
579
580 double
581 mono_fload_r4 (float *ptr)
582 {
583         return *ptr;
584 }
585
586 void
587 mono_fstore_r4 (double val, float *ptr)
588 {
589         *ptr = (float)val;
590 }
591
592 #endif
593
594 /**
595  * ves_array_element_address:
596  * @this: a pointer to the array object
597  *
598  * Returns: the address of an array element.
599  */
600 gpointer 
601 ves_array_element_address (MonoArray *this, ...)
602 {
603         MonoClass *class;
604         va_list ap;
605         int i, ind, esize, realidx;
606         gpointer ea;
607
608         MONO_ARCH_SAVE_REGS;
609
610         g_assert (this != NULL);
611
612         va_start(ap, this);
613
614         class = this->obj.vtable->klass;
615
616         g_assert (this->bounds != NULL);
617
618         esize = mono_array_element_size (class);
619         ind = va_arg(ap, int);
620         ind -= (int)this->bounds [0].lower_bound;
621         if ((guint32)ind >= (guint32)this->bounds [0].length)
622                 mono_raise_exception (mono_get_exception_index_out_of_range ());
623         for (i = 1; i < class->rank; i++) {
624                 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
625                 if ((guint32)realidx >= (guint32)this->bounds [i].length)
626                         mono_raise_exception (mono_get_exception_index_out_of_range ());
627                 ind *= this->bounds [i].length;
628                 ind += realidx;
629         }
630         esize *= ind;
631
632         ea = (gpointer*)(gpointer)((char*)this->vector + esize);
633
634         va_end(ap);
635
636         return ea;
637 }
638
639 MonoArray *
640 mono_array_new_va (MonoMethod *cm, ...)
641 {
642         MonoDomain *domain = mono_domain_get ();
643         va_list ap;
644         guint32 *lengths;
645         guint32 *lower_bounds;
646         int pcount;
647         int rank;
648         int i, d;
649
650         MONO_ARCH_SAVE_REGS;
651
652         pcount = mono_method_signature (cm)->param_count;
653         rank = cm->klass->rank;
654
655         va_start (ap, cm);
656         
657         lengths = alloca (sizeof (guint32) * pcount);
658         for (i = 0; i < pcount; ++i)
659                 lengths [i] = d = va_arg(ap, int);
660
661         if (rank == pcount) {
662                 /* Only lengths provided. */
663                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
664                         lower_bounds = alloca (sizeof (guint32) * rank);
665                         memset (lower_bounds, 0, sizeof (guint32) * rank);
666                 } else {
667                         lower_bounds = NULL;
668                 }
669         } else {
670                 g_assert (pcount == (rank * 2));
671                 /* lower bounds are first. */
672                 lower_bounds = lengths;
673                 lengths += rank;
674         }
675         va_end(ap);
676
677         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
678 }
679
680 gpointer
681 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
682 {
683         MonoVTable *vtable;
684         gpointer addr;
685         
686         MONO_ARCH_SAVE_REGS;
687
688         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
689
690         mono_class_init (field->parent);
691
692         vtable = mono_class_vtable (domain, field->parent);
693         if (!vtable->initialized)
694                 mono_runtime_class_init (vtable);
695
696         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
697
698         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
699                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
700         else
701                 addr = (char*)vtable->data + field->offset;
702         
703         return addr;
704 }
705
706 gpointer
707 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
708 {
709         MonoClass *handle_class;
710         gpointer res;
711
712         MONO_ARCH_SAVE_REGS;
713         res = mono_ldtoken (image, token, &handle_class, context);      
714         mono_class_init (handle_class);
715
716         return res;
717 }
718
719 guint64
720 mono_fconv_u8 (double v)
721 {
722         return (guint64)v;
723 }
724
725 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
726 gint64
727 mono_fconv_i8 (double v)
728 {
729         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
730         return (gint64)v;
731 }
732 #endif
733
734 guint32
735 mono_fconv_u4 (double v)
736 {
737         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
738         return (guint32)v;
739 }
740
741 #ifndef HAVE_TRUNC
742 /* Solaris doesn't have trunc */
743 #ifdef HAVE_AINTL
744 extern long double aintl (long double);
745 #define trunc aintl
746 #else
747 /* FIXME: This means we will never throw overflow exceptions */
748 #define trunc(v) res
749 #endif
750 #endif /* HAVE_TRUNC */
751
752 gint64
753 mono_fconv_ovf_i8 (double v)
754 {
755         gint64 res;
756
757         MONO_ARCH_SAVE_REGS;
758
759         res = (gint64)v;
760
761         if (isnan(v) || trunc (v) != res) {
762                 mono_raise_exception (mono_get_exception_overflow ());
763         }
764         return res;
765 }
766
767 guint64
768 mono_fconv_ovf_u8 (double v)
769 {
770         guint64 res;
771
772         MONO_ARCH_SAVE_REGS;
773     
774         res = (guint64)v;
775
776         if (isnan(v) || trunc (v) != res) {
777                 mono_raise_exception (mono_get_exception_overflow ());
778         }
779         return res;
780 }
781
782 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
783 double
784 mono_lconv_to_r8 (gint64 a)
785 {
786         return (double)a;
787 }
788 #endif
789
790 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
791 float
792 mono_lconv_to_r4 (gint64 a)
793 {
794         return (float)a;
795 }
796 #endif
797
798 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
799 double
800 mono_conv_to_r8_un (guint32 a)
801 {
802         return (double)a;
803 }
804 #endif
805
806 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
807 double
808 mono_lconv_to_r8_un (guint64 a)
809 {
810         return (double)a;
811 }
812 #endif
813
814 gpointer
815 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
816 {
817         MonoMethod *vmethod, *inflated;
818         gpointer addr;
819
820         if (obj == NULL)
821                 mono_raise_exception (mono_get_exception_null_reference ());
822         vmethod = mono_object_get_virtual_method (obj, method);
823
824         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
825            declaring class have been inflated.  We still need to fully inflate the method parameters.
826
827            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
828            the same context.
829         */
830         g_assert (!vmethod->klass->generic_container);
831         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->inst->is_open);
832         g_assert (!context->gmethod || !context->gmethod->inst->is_open);
833         inflated = mono_class_inflate_generic_method (vmethod, context);
834         inflated = mono_get_inflated_method (inflated);
835         addr = mono_compile_method (inflated);
836
837         /* Since this is a virtual call, have to unbox vtypes */
838         if (obj->vtable->klass->valuetype)
839                 *this_arg = mono_object_unbox (obj);
840         else
841                 *this_arg = obj;
842
843         return addr;
844 }
845
846 MonoString*
847 mono_helper_ldstr (MonoImage *image, guint32 idx)
848 {
849         return mono_ldstr (mono_domain_get (), image, idx);
850 }
851
852 MonoString*
853 mono_helper_ldstr_mscorlib (guint32 idx)
854 {
855         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
856 }
857
858 MonoObject*
859 mono_helper_newobj_mscorlib (guint32 idx)
860 {
861         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
862         
863         g_assert (klass);
864
865         return mono_object_new (mono_domain_get (), klass);
866 }