2008-02-06 Mark Probst <mark.probst@gmail.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 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 MonoArray *
609 mono_array_new_va (MonoMethod *cm, ...)
610 {
611         MonoDomain *domain = mono_domain_get ();
612         va_list ap;
613         guint32 *lengths;
614         guint32 *lower_bounds;
615         int pcount;
616         int rank;
617         int i, d;
618
619         MONO_ARCH_SAVE_REGS;
620
621         pcount = mono_method_signature (cm)->param_count;
622         rank = cm->klass->rank;
623
624         va_start (ap, cm);
625         
626         lengths = alloca (sizeof (guint32) * pcount);
627         for (i = 0; i < pcount; ++i)
628                 lengths [i] = d = va_arg(ap, int);
629
630         if (rank == pcount) {
631                 /* Only lengths provided. */
632                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
633                         lower_bounds = alloca (sizeof (guint32) * rank);
634                         memset (lower_bounds, 0, sizeof (guint32) * rank);
635                 } else {
636                         lower_bounds = NULL;
637                 }
638         } else {
639                 g_assert (pcount == (rank * 2));
640                 /* lower bounds are first. */
641                 lower_bounds = lengths;
642                 lengths += rank;
643         }
644         va_end(ap);
645
646         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
647 }
648
649 gpointer
650 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
651 {
652         MonoVTable *vtable;
653         gpointer addr;
654         
655         MONO_ARCH_SAVE_REGS;
656
657         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
658
659         mono_class_init (field->parent);
660
661         vtable = mono_class_vtable (domain, field->parent);
662         if (!vtable->initialized)
663                 mono_runtime_class_init (vtable);
664
665         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
666
667         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
668                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
669         else
670                 addr = (char*)vtable->data + field->offset;
671         
672         return addr;
673 }
674
675 gpointer
676 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
677 {
678         MonoClass *handle_class;
679         gpointer res;
680
681         MONO_ARCH_SAVE_REGS;
682         res = mono_ldtoken (image, token, &handle_class, context);      
683         mono_class_init (handle_class);
684
685         return res;
686 }
687
688 guint64
689 mono_fconv_u8 (double v)
690 {
691         return (guint64)v;
692 }
693
694 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
695 gint64
696 mono_fconv_i8 (double v)
697 {
698         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
699         return (gint64)v;
700 }
701 #endif
702
703 guint32
704 mono_fconv_u4 (double v)
705 {
706         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
707         return (guint32)v;
708 }
709
710 #ifndef HAVE_TRUNC
711 /* Solaris doesn't have trunc */
712 #ifdef HAVE_AINTL
713 extern long double aintl (long double);
714 #define trunc aintl
715 #else
716 /* FIXME: This means we will never throw overflow exceptions */
717 #define trunc(v) res
718 #endif
719 #endif /* HAVE_TRUNC */
720
721 gint64
722 mono_fconv_ovf_i8 (double v)
723 {
724         gint64 res;
725
726         MONO_ARCH_SAVE_REGS;
727
728         res = (gint64)v;
729
730         if (isnan(v) || trunc (v) != res) {
731                 mono_raise_exception (mono_get_exception_overflow ());
732         }
733         return res;
734 }
735
736 guint64
737 mono_fconv_ovf_u8 (double v)
738 {
739         guint64 res;
740
741         MONO_ARCH_SAVE_REGS;
742     
743         res = (guint64)v;
744
745         if (isnan(v) || trunc (v) != res) {
746                 mono_raise_exception (mono_get_exception_overflow ());
747         }
748         return res;
749 }
750
751 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
752 double
753 mono_lconv_to_r8 (gint64 a)
754 {
755         return (double)a;
756 }
757 #endif
758
759 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
760 float
761 mono_lconv_to_r4 (gint64 a)
762 {
763         return (float)a;
764 }
765 #endif
766
767 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
768 double
769 mono_conv_to_r8_un (guint32 a)
770 {
771         return (double)a;
772 }
773 #endif
774
775 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
776 double
777 mono_lconv_to_r8_un (guint64 a)
778 {
779         return (double)a;
780 }
781 #endif
782
783 gpointer
784 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
785 {
786         MonoMethod *vmethod, *inflated;
787         gpointer addr;
788
789         mono_jit_stats.generic_virtual_invocations++;
790
791         if (obj == NULL)
792                 mono_raise_exception (mono_get_exception_null_reference ());
793         vmethod = mono_object_get_virtual_method (obj, method);
794
795         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
796            declaring class have been inflated.  We still need to fully inflate the method parameters.
797
798            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
799            the same context.
800         */
801         g_assert (!vmethod->klass->generic_container);
802         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
803         g_assert (!context->method_inst || !context->method_inst->is_open);
804         inflated = mono_class_inflate_generic_method (vmethod, context);
805         addr = mono_compile_method (inflated);
806
807         /* Since this is a virtual call, have to unbox vtypes */
808         if (obj->vtable->klass->valuetype)
809                 *this_arg = mono_object_unbox (obj);
810         else
811                 *this_arg = obj;
812
813         return addr;
814 }
815
816 MonoString*
817 mono_helper_ldstr (MonoImage *image, guint32 idx)
818 {
819         return mono_ldstr (mono_domain_get (), image, idx);
820 }
821
822 MonoString*
823 mono_helper_ldstr_mscorlib (guint32 idx)
824 {
825         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
826 }
827
828 MonoObject*
829 mono_helper_newobj_mscorlib (guint32 idx)
830 {
831         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
832         
833         g_assert (klass);
834
835         return mono_object_new (mono_domain_get (), klass);
836 }
837
838 /*
839  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
840  * in generated code. So instead we emit a call to this function and place a gdb
841  * breakpoint here.
842  */
843 void
844 mono_break (void)
845 {
846 }