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_fconv_i1 (double a)
461 mono_fconv_i2 (double a)
467 mono_fconv_i4 (double a)
473 mono_fconv_u1 (double a)
479 mono_fconv_u2 (double a)
485 mono_fcmp_eq (double a, double b)
491 mono_fcmp_ge (double a, double b)
497 mono_fcmp_gt (double a, double b)
503 mono_fcmp_le (double a, double b)
509 mono_fcmp_lt (double a, double b)
515 mono_fcmp_ne_un (double a, double b)
517 return isunordered (a, b) || a != b;
521 mono_fcmp_ge_un (double a, double b)
523 return isunordered (a, b) || a >= b;
527 mono_fcmp_gt_un (double a, double b)
529 return isunordered (a, b) || a > b;
533 mono_fcmp_le_un (double a, double b)
535 return isunordered (a, b) || a <= b;
539 mono_fcmp_lt_un (double a, double b)
541 return isunordered (a, b) || a < b;
547 * ves_array_element_address:
548 * @this: a pointer to the array object
550 * Returns: the address of an array element.
553 ves_array_element_address (MonoArray *this, ...)
557 int i, ind, esize, realidx;
562 g_assert (this != NULL);
566 class = this->obj.vtable->klass;
568 g_assert (this->bounds != NULL);
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;
584 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
592 mono_array_new_va (MonoMethod *cm, ...)
594 MonoDomain *domain = mono_domain_get ();
597 guint32 *lower_bounds;
604 pcount = mono_method_signature (cm)->param_count;
605 rank = cm->klass->rank;
609 lengths = alloca (sizeof (guint32) * pcount);
610 for (i = 0; i < pcount; ++i)
611 lengths [i] = d = va_arg(ap, int);
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);
622 g_assert (pcount == (rank * 2));
623 /* lower bounds are first. */
624 lower_bounds = lengths;
629 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
633 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
640 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
642 mono_class_init (field->parent);
644 vtable = mono_class_vtable (domain, field->parent);
645 if (!vtable->initialized)
646 mono_runtime_class_init (vtable);
648 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
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));
653 addr = (char*)vtable->data + field->offset;
659 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
661 MonoClass *handle_class;
665 res = mono_ldtoken (image, token, &handle_class, context);
666 mono_class_init (handle_class);
672 mono_fconv_u8 (double v)
677 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
679 mono_fconv_i8 (double v)
681 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
687 mono_fconv_u4 (double v)
689 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
694 /* Solaris doesn't have trunc */
696 extern long double aintl (long double);
699 /* FIXME: This means we will never throw overflow exceptions */
702 #endif /* HAVE_TRUNC */
705 mono_fconv_ovf_i8 (double v)
713 if (isnan(v) || trunc (v) != res) {
714 mono_raise_exception (mono_get_exception_overflow ());
720 mono_fconv_ovf_u8 (double v)
728 if (isnan(v) || trunc (v) != res) {
729 mono_raise_exception (mono_get_exception_overflow ());
734 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
736 mono_lconv_to_r8 (gint64 a)
742 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
744 mono_lconv_to_r4 (gint64 a)
750 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
752 mono_conv_to_r8_un (guint32 a)
758 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
760 mono_lconv_to_r8_un (guint64 a)
767 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
769 MonoMethod *vmethod, *inflated;
773 mono_raise_exception (mono_get_exception_null_reference ());
774 vmethod = mono_object_get_virtual_method (obj, method);
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.
779 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
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);
789 /* Since this is a virtual call, have to unbox vtypes */
790 if (obj->vtable->klass->valuetype)
791 *this_arg = mono_object_unbox (obj);
799 mono_helper_ldstr (MonoImage *image, guint32 idx)
801 return mono_ldstr (mono_domain_get (), image, idx);
805 mono_helper_ldstr_mscorlib (guint32 idx)
807 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
811 mono_helper_newobj_mscorlib (guint32 idx)
813 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
817 return mono_object_new (mono_domain_get (), klass);