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