2 * jit-icalls.c: internal calls used by the JIT
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2002 Ximian, Inc.
13 #include "jit-icalls.h"
16 mono_ldftn (MonoMethod *method)
22 addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
24 return mono_create_ftnptr (mono_domain_get (), addr);
28 * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
29 * synchronized wrappers to avoid infinite recursion.
32 mono_ldftn_nosync (MonoMethod *method)
38 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
40 return mono_create_ftnptr (mono_domain_get (), addr);
44 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
49 mono_raise_exception (mono_get_exception_null_reference ());
51 method = mono_object_get_virtual_method (obj, method);
53 return mono_ldftn (method);
57 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
61 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
62 mono_raise_exception (mono_get_exception_array_type_mismatch ());
65 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
68 mono_llmult (gint64 a, gint64 b)
70 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
75 mono_llmult_ovf_un (guint64 a, guint64 b)
85 // fixme: this is incredible slow
90 res = (guint64)al * (guint64)bl;
92 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
97 res += ((guint64)t1) << 32;
102 mono_raise_exception (mono_get_exception_overflow ());
107 mono_llmult_ovf (gint64 a, gint64 b)
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)
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.
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
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
140 if (((guint32)ah == 0x80000000) && (al == 0)) {
141 /* This has no two's complement */
147 goto raise_exception;
150 /* flip the bits and add 1 */
161 if (((guint32)bh == 0x80000000) && (bl == 0)) {
162 /* This has no two's complement */
168 goto raise_exception;
171 /* flip the bits and add 1 */
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 */
186 goto raise_exception;
187 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
188 goto raise_exception;
190 /* do the AlBl term first */
191 t1 = (gint64)al * (gint64)bl;
195 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
196 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
197 /* check for overflow */
199 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
200 goto raise_exception;
205 goto raise_exception;
213 mono_raise_exception (mono_get_exception_overflow ());
217 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
220 mono_idiv (gint32 a, gint32 b)
224 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
234 mono_idiv_un (guint32 a, guint32 b)
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
240 mono_raise_exception (mono_get_exception_divide_by_zero ());
246 mono_irem (gint32 a, gint32 b)
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
261 mono_irem_un (guint32 a, guint32 b)
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
267 mono_raise_exception (mono_get_exception_divide_by_zero ());
274 #ifdef MONO_ARCH_EMULATE_MUL_DIV
277 mono_imul (gint32 a, gint32 b)
285 mono_imul_ovf (gint32 a, gint32 b)
291 res = (gint64)a * (gint64)b;
293 if ((res > 0x7fffffffL) || (res < -2147483648))
294 mono_raise_exception (mono_get_exception_overflow ());
300 mono_imul_ovf_un (guint32 a, guint32 b)
306 res = (guint64)a * (guint64)b;
309 mono_raise_exception (mono_get_exception_overflow ());
315 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
317 mono_fdiv (double a, double b)
326 mono_lldiv (gint64 a, gint64 b)
330 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
340 mono_llrem (gint64 a, gint64 b)
344 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
354 mono_lldiv_un (guint64 a, guint64 b)
358 #ifdef MONO_ARCH_NEED_DIV_CHECK
360 mono_raise_exception (mono_get_exception_divide_by_zero ());
366 mono_llrem_un (guint64 a, guint64 b)
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
372 mono_raise_exception (mono_get_exception_divide_by_zero ());
379 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
382 mono_lshl (guint64 a, gint32 shamt)
386 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
389 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
395 mono_lshr_un (guint64 a, gint32 shamt)
399 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
402 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
408 mono_lshr (gint64 a, gint32 shamt)
412 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
415 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
422 #ifdef MONO_ARCH_SOFT_FLOAT
425 mono_fsub (double a, double b)
431 mono_fadd (double a, double b)
437 mono_fmul (double a, double b)
449 mono_fconv_r4 (double a)
455 mono_conv_to_r8 (int a)
461 mono_conv_to_r4 (int a)
463 return (double)(float)a;
467 mono_fconv_i1 (double a)
473 mono_fconv_i2 (double a)
479 mono_fconv_i4 (double a)
485 mono_fconv_u1 (double a)
491 mono_fconv_u2 (double a)
497 mono_fcmp_eq (double a, double b)
503 mono_fcmp_ge (double a, double b)
509 mono_fcmp_gt (double a, double b)
515 mono_fcmp_le (double a, double b)
521 mono_fcmp_lt (double a, double b)
527 mono_fcmp_ne_un (double a, double b)
529 return isunordered (a, b) || a != b;
533 mono_fcmp_ge_un (double a, double b)
535 return isunordered (a, b) || a >= b;
539 mono_fcmp_gt_un (double a, double b)
541 return isunordered (a, b) || a > b;
545 mono_fcmp_le_un (double a, double b)
547 return isunordered (a, b) || a <= b;
551 mono_fcmp_lt_un (double a, double b)
553 return isunordered (a, b) || a < b;
557 mono_fceq (double a, double b)
563 mono_fcgt (double a, double b)
569 mono_fcgt_un (double a, double b)
575 mono_fclt (double a, double b)
581 mono_fclt_un (double a, double b)
587 mono_fload_r4 (float *ptr)
593 mono_fstore_r4 (double val, float *ptr)
598 /* returns the integer bitpattern that is passed in the regs or stack */
600 mono_fload_r4_arg (double val)
602 float v = (float)val;
603 return *(guint32*)&v;
609 * ves_array_element_address:
610 * @this: a pointer to the array object
612 * Returns: the address of an array element.
615 ves_array_element_address (MonoArray *this, ...)
619 int i, ind, esize, realidx;
624 g_assert (this != NULL);
628 class = this->obj.vtable->klass;
630 g_assert (this->bounds != NULL);
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;
646 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
654 mono_array_new_va (MonoMethod *cm, ...)
656 MonoDomain *domain = mono_domain_get ();
659 guint32 *lower_bounds;
666 pcount = mono_method_signature (cm)->param_count;
667 rank = cm->klass->rank;
671 lengths = alloca (sizeof (guint32) * pcount);
672 for (i = 0; i < pcount; ++i)
673 lengths [i] = d = va_arg(ap, int);
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);
684 g_assert (pcount == (rank * 2));
685 /* lower bounds are first. */
686 lower_bounds = lengths;
691 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
695 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
702 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
704 mono_class_init (field->parent);
706 vtable = mono_class_vtable (domain, field->parent);
707 if (!vtable->initialized)
708 mono_runtime_class_init (vtable);
710 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
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));
715 addr = (char*)vtable->data + field->offset;
721 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
723 MonoClass *handle_class;
727 res = mono_ldtoken (image, token, &handle_class, context);
728 mono_class_init (handle_class);
734 mono_fconv_u8 (double v)
739 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
741 mono_fconv_i8 (double v)
743 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
749 mono_fconv_u4 (double v)
751 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
756 /* Solaris doesn't have trunc */
758 extern long double aintl (long double);
761 /* FIXME: This means we will never throw overflow exceptions */
764 #endif /* HAVE_TRUNC */
767 mono_fconv_ovf_i8 (double v)
775 if (isnan(v) || trunc (v) != res) {
776 mono_raise_exception (mono_get_exception_overflow ());
782 mono_fconv_ovf_u8 (double v)
790 if (isnan(v) || trunc (v) != res) {
791 mono_raise_exception (mono_get_exception_overflow ());
796 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
798 mono_lconv_to_r8 (gint64 a)
804 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
806 mono_lconv_to_r4 (gint64 a)
812 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
814 mono_conv_to_r8_un (guint32 a)
820 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
822 mono_lconv_to_r8_un (guint64 a)
829 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
831 MonoMethod *vmethod, *inflated;
835 mono_raise_exception (mono_get_exception_null_reference ());
836 vmethod = mono_object_get_virtual_method (obj, method);
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.
841 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
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);
851 /* Since this is a virtual call, have to unbox vtypes */
852 if (obj->vtable->klass->valuetype)
853 *this_arg = mono_object_unbox (obj);
861 mono_helper_ldstr (MonoImage *image, guint32 idx)
863 return mono_ldstr (mono_domain_get (), image, idx);
867 mono_helper_ldstr_mscorlib (guint32 idx)
869 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
873 mono_helper_newobj_mscorlib (guint32 idx)
875 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
879 return mono_object_new (mono_domain_get (), klass);