d300b6033f3d17fc59d2d6977aeccff0a3169937
[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 gpointer
689 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
690 {
691         MonoMethodSignature *sig = mono_method_signature (method);
692         MonoGenericContext *generic_context;
693
694         if (sig->is_inflated) {
695                 generic_context = mono_method_get_context (method);
696         } else {
697                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
698                 g_assert (generic_container);
699                 generic_context = &generic_container->context;
700         }
701
702         return mono_ldtoken_wrapper (image, token, generic_context);
703 }
704
705 guint64
706 mono_fconv_u8 (double v)
707 {
708         return (guint64)v;
709 }
710
711 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
712 gint64
713 mono_fconv_i8 (double v)
714 {
715         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
716         return (gint64)v;
717 }
718 #endif
719
720 guint32
721 mono_fconv_u4 (double v)
722 {
723         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
724         return (guint32)v;
725 }
726
727 #ifndef HAVE_TRUNC
728 /* Solaris doesn't have trunc */
729 #ifdef HAVE_AINTL
730 extern long double aintl (long double);
731 #define trunc aintl
732 #else
733 /* FIXME: This means we will never throw overflow exceptions */
734 #define trunc(v) res
735 #endif
736 #endif /* HAVE_TRUNC */
737
738 gint64
739 mono_fconv_ovf_i8 (double v)
740 {
741         gint64 res;
742
743         MONO_ARCH_SAVE_REGS;
744
745         res = (gint64)v;
746
747         if (isnan(v) || trunc (v) != res) {
748                 mono_raise_exception (mono_get_exception_overflow ());
749         }
750         return res;
751 }
752
753 guint64
754 mono_fconv_ovf_u8 (double v)
755 {
756         guint64 res;
757
758         MONO_ARCH_SAVE_REGS;
759     
760         res = (guint64)v;
761
762         if (isnan(v) || trunc (v) != res) {
763                 mono_raise_exception (mono_get_exception_overflow ());
764         }
765         return res;
766 }
767
768 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
769 double
770 mono_lconv_to_r8 (gint64 a)
771 {
772         return (double)a;
773 }
774 #endif
775
776 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
777 float
778 mono_lconv_to_r4 (gint64 a)
779 {
780         return (float)a;
781 }
782 #endif
783
784 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
785 double
786 mono_conv_to_r8_un (guint32 a)
787 {
788         return (double)a;
789 }
790 #endif
791
792 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
793 double
794 mono_lconv_to_r8_un (guint64 a)
795 {
796         return (double)a;
797 }
798 #endif
799
800 gpointer
801 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
802 {
803         MonoMethod *vmethod, *inflated;
804         gpointer addr;
805
806         mono_jit_stats.generic_virtual_invocations++;
807
808         if (obj == NULL)
809                 mono_raise_exception (mono_get_exception_null_reference ());
810         vmethod = mono_object_get_virtual_method (obj, method);
811
812         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
813            declaring class have been inflated.  We still need to fully inflate the method parameters.
814
815            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
816            the same context.
817         */
818         g_assert (!vmethod->klass->generic_container);
819         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
820         g_assert (!context->method_inst || !context->method_inst->is_open);
821         inflated = mono_class_inflate_generic_method (vmethod, context);
822         addr = mono_compile_method (inflated);
823
824         /* Since this is a virtual call, have to unbox vtypes */
825         if (obj->vtable->klass->valuetype)
826                 *this_arg = mono_object_unbox (obj);
827         else
828                 *this_arg = obj;
829
830         return addr;
831 }
832
833 MonoString*
834 mono_helper_ldstr (MonoImage *image, guint32 idx)
835 {
836         return mono_ldstr (mono_domain_get (), image, idx);
837 }
838
839 MonoString*
840 mono_helper_ldstr_mscorlib (guint32 idx)
841 {
842         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
843 }
844
845 MonoObject*
846 mono_helper_newobj_mscorlib (guint32 idx)
847 {
848         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
849         
850         g_assert (klass);
851
852         return mono_object_new (mono_domain_get (), klass);
853 }
854
855 /*
856  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
857  * in generated code. So instead we emit a call to this function and place a gdb
858  * breakpoint here.
859  */
860 void
861 mono_break (void)
862 {
863 }
864
865 MonoException *
866 mono_create_corlib_exception_0 (guint32 token)
867 {
868         return mono_exception_from_token (mono_defaults.corlib, token);
869 }
870
871 MonoException *
872 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
873 {
874         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
875 }
876
877 MonoException *
878 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
879 {
880         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
881 }