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_fconv_i1 (double a)
467 mono_fconv_i2 (double a)
473 mono_fconv_i4 (double a)
479 mono_fconv_u1 (double a)
485 mono_fconv_u2 (double a)
491 mono_fcmp_eq (double a, double b)
497 mono_fcmp_ge (double a, double b)
503 mono_fcmp_gt (double a, double b)
509 mono_fcmp_le (double a, double b)
515 mono_fcmp_lt (double a, double b)
521 mono_fcmp_ne_un (double a, double b)
523 return isunordered (a, b) || a != b;
527 mono_fcmp_ge_un (double a, double b)
529 return isunordered (a, b) || a >= b;
533 mono_fcmp_gt_un (double a, double b)
535 return isunordered (a, b) || a > b;
539 mono_fcmp_le_un (double a, double b)
541 return isunordered (a, b) || a <= b;
545 mono_fcmp_lt_un (double a, double b)
547 return isunordered (a, b) || a < b;
551 mono_fceq (double a, double b)
557 mono_fcgt (double a, double b)
563 mono_fcgt_un (double a, double b)
569 mono_fclt (double a, double b)
575 mono_fclt_un (double a, double b)
581 mono_fload_r4 (float *ptr)
587 mono_fstore_r4 (double val, float *ptr)
595 * ves_array_element_address:
596 * @this: a pointer to the array object
598 * Returns: the address of an array element.
601 ves_array_element_address (MonoArray *this, ...)
605 int i, ind, esize, realidx;
610 g_assert (this != NULL);
614 class = this->obj.vtable->klass;
616 g_assert (this->bounds != NULL);
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;
632 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
640 mono_array_new_va (MonoMethod *cm, ...)
642 MonoDomain *domain = mono_domain_get ();
645 guint32 *lower_bounds;
652 pcount = mono_method_signature (cm)->param_count;
653 rank = cm->klass->rank;
657 lengths = alloca (sizeof (guint32) * pcount);
658 for (i = 0; i < pcount; ++i)
659 lengths [i] = d = va_arg(ap, int);
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);
670 g_assert (pcount == (rank * 2));
671 /* lower bounds are first. */
672 lower_bounds = lengths;
677 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
681 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
688 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
690 mono_class_init (field->parent);
692 vtable = mono_class_vtable (domain, field->parent);
693 if (!vtable->initialized)
694 mono_runtime_class_init (vtable);
696 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
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));
701 addr = (char*)vtable->data + field->offset;
707 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
709 MonoClass *handle_class;
713 res = mono_ldtoken (image, token, &handle_class, context);
714 mono_class_init (handle_class);
720 mono_fconv_u8 (double v)
725 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
727 mono_fconv_i8 (double v)
729 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
735 mono_fconv_u4 (double v)
737 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
742 /* Solaris doesn't have trunc */
744 extern long double aintl (long double);
747 /* FIXME: This means we will never throw overflow exceptions */
750 #endif /* HAVE_TRUNC */
753 mono_fconv_ovf_i8 (double v)
761 if (isnan(v) || trunc (v) != res) {
762 mono_raise_exception (mono_get_exception_overflow ());
768 mono_fconv_ovf_u8 (double v)
776 if (isnan(v) || trunc (v) != res) {
777 mono_raise_exception (mono_get_exception_overflow ());
782 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
784 mono_lconv_to_r8 (gint64 a)
790 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
792 mono_lconv_to_r4 (gint64 a)
798 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
800 mono_conv_to_r8_un (guint32 a)
806 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
808 mono_lconv_to_r8_un (guint64 a)
815 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
817 MonoMethod *vmethod, *inflated;
821 mono_raise_exception (mono_get_exception_null_reference ());
822 vmethod = mono_object_get_virtual_method (obj, method);
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.
827 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
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);
837 /* Since this is a virtual call, have to unbox vtypes */
838 if (obj->vtable->klass->valuetype)
839 *this_arg = mono_object_unbox (obj);
847 mono_helper_ldstr (MonoImage *image, guint32 idx)
849 return mono_ldstr (mono_domain_get (), image, idx);
853 mono_helper_ldstr_mscorlib (guint32 idx)
855 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
859 mono_helper_newobj_mscorlib (guint32 idx)
861 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
865 return mono_object_new (mono_domain_get (), klass);