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.
14 #include "jit-icalls.h"
17 mono_ldftn (MonoMethod *method)
23 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
25 return mono_create_ftnptr (mono_domain_get (), addr);
29 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
36 mono_raise_exception (mono_get_exception_null_reference ());
38 res = mono_object_get_virtual_method (obj, method);
40 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
41 MonoGenericContext context = { NULL, NULL };
43 if (res->klass->generic_class)
44 context.class_inst = res->klass->generic_class->context.class_inst;
45 else if (res->klass->generic_container)
46 context.class_inst = res->klass->generic_container->context.class_inst;
47 context.method_inst = mono_method_get_context (method)->method_inst;
49 res = mono_class_inflate_generic_method (res, &context);
52 if (mono_method_needs_static_rgctx_invoke (res, FALSE))
53 res = mono_marshal_get_static_rgctx_invoke (res);
55 return mono_ldftn (res);
59 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
61 return ldvirtfn_internal (obj, method, FALSE);
65 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
67 return ldvirtfn_internal (obj, method, TRUE);
71 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
75 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
76 mono_raise_exception (mono_get_exception_array_type_mismatch ());
79 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
82 mono_llmult (gint64 a, gint64 b)
84 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
89 mono_llmult_ovf_un (guint64 a, guint64 b)
99 // fixme: this is incredible slow
102 goto raise_exception;
104 res = (guint64)al * (guint64)bl;
106 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
109 goto raise_exception;
111 res += ((guint64)t1) << 32;
116 mono_raise_exception (mono_get_exception_overflow ());
121 mono_llmult_ovf (gint64 a, gint64 b)
128 Use Karatsuba algorithm where:
129 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
130 where Ah is the "high half" (most significant 32 bits) of a and
131 where Al is the "low half" (least significant 32 bits) of a and
132 where Bh is the "high half" of b and Bl is the "low half" and
133 where R is the Radix or "size of the half" (in our case 32 bits)
135 Note, for the product of two 64 bit numbers to fit into a 64
136 result, ah and/or bh must be 0. This will save us from doing
137 the AhBh term at all.
139 Also note that we refactor so that we don't overflow 64 bits with
140 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
148 /* need to work with absoulte values, so find out what the
149 resulting sign will be and convert any negative numbers
150 from two's complement
154 if (((guint32)ah == 0x80000000) && (al == 0)) {
155 /* This has no two's complement */
161 goto raise_exception;
164 /* flip the bits and add 1 */
175 if (((guint32)bh == 0x80000000) && (bl == 0)) {
176 /* This has no two's complement */
182 goto raise_exception;
185 /* flip the bits and add 1 */
195 /* we overflow for sure if both upper halves are greater
196 than zero because we would need to shift their
197 product 64 bits to the left and that will not fit
198 in a 64 bit result */
200 goto raise_exception;
201 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
202 goto raise_exception;
204 /* do the AlBl term first */
205 t1 = (gint64)al * (gint64)bl;
209 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
210 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
211 /* check for overflow */
213 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
214 goto raise_exception;
219 goto raise_exception;
227 mono_raise_exception (mono_get_exception_overflow ());
231 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
234 mono_idiv (gint32 a, gint32 b)
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
240 mono_raise_exception (mono_get_exception_divide_by_zero ());
241 else if (b == -1 && a == (0x80000000))
242 mono_raise_exception (mono_get_exception_arithmetic ());
248 mono_idiv_un (guint32 a, guint32 b)
252 #ifdef MONO_ARCH_NEED_DIV_CHECK
254 mono_raise_exception (mono_get_exception_divide_by_zero ());
260 mono_irem (gint32 a, gint32 b)
264 #ifdef MONO_ARCH_NEED_DIV_CHECK
266 mono_raise_exception (mono_get_exception_divide_by_zero ());
267 else if (b == -1 && a == (0x80000000))
268 mono_raise_exception (mono_get_exception_arithmetic ());
275 mono_irem_un (guint32 a, guint32 b)
279 #ifdef MONO_ARCH_NEED_DIV_CHECK
281 mono_raise_exception (mono_get_exception_divide_by_zero ());
288 #ifdef MONO_ARCH_EMULATE_MUL_DIV
291 mono_imul (gint32 a, gint32 b)
299 mono_imul_ovf (gint32 a, gint32 b)
305 res = (gint64)a * (gint64)b;
307 if ((res > 0x7fffffffL) || (res < -2147483648))
308 mono_raise_exception (mono_get_exception_overflow ());
314 mono_imul_ovf_un (guint32 a, guint32 b)
320 res = (guint64)a * (guint64)b;
323 mono_raise_exception (mono_get_exception_overflow ());
329 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
331 mono_fdiv (double a, double b)
340 mono_lldiv (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_llrem (gint64 a, gint64 b)
358 #ifdef MONO_ARCH_NEED_DIV_CHECK
360 mono_raise_exception (mono_get_exception_divide_by_zero ());
361 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
362 mono_raise_exception (mono_get_exception_arithmetic ());
368 mono_lldiv_un (guint64 a, guint64 b)
372 #ifdef MONO_ARCH_NEED_DIV_CHECK
374 mono_raise_exception (mono_get_exception_divide_by_zero ());
380 mono_llrem_un (guint64 a, guint64 b)
384 #ifdef MONO_ARCH_NEED_DIV_CHECK
386 mono_raise_exception (mono_get_exception_divide_by_zero ());
393 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
396 mono_lshl (guint64 a, gint32 shamt)
400 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
403 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
409 mono_lshr_un (guint64 a, gint32 shamt)
413 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
416 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
422 mono_lshr (gint64 a, gint32 shamt)
426 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
429 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
436 #ifdef MONO_ARCH_SOFT_FLOAT
439 mono_fsub (double a, double b)
445 mono_fadd (double a, double b)
451 mono_fmul (double a, double b)
463 mono_fconv_r4 (double a)
469 mono_conv_to_r8 (int a)
475 mono_conv_to_r4 (int a)
477 return (double)(float)a;
481 mono_fconv_i1 (double a)
487 mono_fconv_i2 (double a)
493 mono_fconv_i4 (double a)
499 mono_fconv_u1 (double a)
505 mono_fconv_u2 (double a)
511 mono_fcmp_eq (double a, double b)
517 mono_fcmp_ge (double a, double b)
523 mono_fcmp_gt (double a, double b)
529 mono_fcmp_le (double a, double b)
535 mono_fcmp_lt (double a, double b)
541 mono_fcmp_ne_un (double a, double b)
543 return isunordered (a, b) || a != b;
547 mono_fcmp_ge_un (double a, double b)
549 return isunordered (a, b) || a >= b;
553 mono_fcmp_gt_un (double a, double b)
555 return isunordered (a, b) || a > b;
559 mono_fcmp_le_un (double a, double b)
561 return isunordered (a, b) || a <= b;
565 mono_fcmp_lt_un (double a, double b)
567 return isunordered (a, b) || a < b;
571 mono_fceq (double a, double b)
577 mono_fcgt (double a, double b)
583 mono_fcgt_un (double a, double b)
585 return isunordered (a, b) || a > b;
589 mono_fclt (double a, double b)
595 mono_fclt_un (double a, double b)
597 return isunordered (a, b) || a < b;
601 mono_fload_r4 (float *ptr)
607 mono_fstore_r4 (double val, float *ptr)
612 /* returns the integer bitpattern that is passed in the regs or stack */
614 mono_fload_r4_arg (double val)
616 float v = (float)val;
617 return *(guint32*)&v;
623 mono_array_new_va (MonoMethod *cm, ...)
625 MonoDomain *domain = mono_domain_get ();
628 guint32 *lower_bounds;
635 pcount = mono_method_signature (cm)->param_count;
636 rank = cm->klass->rank;
640 lengths = alloca (sizeof (guint32) * pcount);
641 for (i = 0; i < pcount; ++i)
642 lengths [i] = d = va_arg(ap, int);
644 if (rank == pcount) {
645 /* Only lengths provided. */
646 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
647 lower_bounds = alloca (sizeof (guint32) * rank);
648 memset (lower_bounds, 0, sizeof (guint32) * rank);
653 g_assert (pcount == (rank * 2));
654 /* lower bounds are first. */
655 lower_bounds = lengths;
660 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
663 /* Specialized version of mono_array_new_va () which avoids varargs */
665 mono_array_new_1 (MonoMethod *cm, guint32 length)
667 MonoDomain *domain = mono_domain_get ();
669 guint32 *lower_bounds;
675 pcount = mono_method_signature (cm)->param_count;
676 rank = cm->klass->rank;
678 lengths [0] = length;
680 g_assert (rank == pcount);
682 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
683 lower_bounds = alloca (sizeof (guint32) * rank);
684 memset (lower_bounds, 0, sizeof (guint32) * rank);
689 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
693 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
695 MonoDomain *domain = mono_domain_get ();
697 guint32 *lower_bounds;
703 pcount = mono_method_signature (cm)->param_count;
704 rank = cm->klass->rank;
706 lengths [0] = length1;
707 lengths [1] = length2;
709 g_assert (rank == pcount);
711 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
712 lower_bounds = alloca (sizeof (guint32) * rank);
713 memset (lower_bounds, 0, sizeof (guint32) * rank);
718 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
722 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
729 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
731 mono_class_init (field->parent);
733 vtable = mono_class_vtable (domain, field->parent);
734 if (!vtable->initialized)
735 mono_runtime_class_init (vtable);
737 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
739 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
740 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
742 addr = (char*)vtable->data + field->offset;
748 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
750 MonoClass *handle_class;
754 res = mono_ldtoken (image, token, &handle_class, context);
755 mono_class_init (handle_class);
761 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
763 MonoMethodSignature *sig = mono_method_signature (method);
764 MonoGenericContext *generic_context;
766 if (sig->is_inflated) {
767 generic_context = mono_method_get_context (method);
769 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
770 g_assert (generic_container);
771 generic_context = &generic_container->context;
774 return mono_ldtoken_wrapper (image, token, generic_context);
778 mono_fconv_u8 (double v)
783 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
785 mono_fconv_i8 (double v)
787 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
793 mono_fconv_u4 (double v)
795 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
800 /* Solaris doesn't have trunc */
802 extern long double aintl (long double);
805 /* FIXME: This means we will never throw overflow exceptions */
808 #endif /* HAVE_TRUNC */
811 mono_fconv_ovf_i8 (double v)
819 if (isnan(v) || trunc (v) != res) {
820 mono_raise_exception (mono_get_exception_overflow ());
826 mono_fconv_ovf_u8 (double v)
832 * The soft-float implementation of some ARM devices have a buggy guin64 to double
833 * conversion that it looses precision even when the integer if fully representable
836 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
838 * To work around this issue we test for value boundaries instead.
840 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
841 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
842 mono_raise_exception (mono_get_exception_overflow ());
847 if (isnan(v) || trunc (v) != res) {
848 mono_raise_exception (mono_get_exception_overflow ());
854 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
856 mono_lconv_to_r8 (gint64 a)
862 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
864 mono_lconv_to_r4 (gint64 a)
870 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
872 mono_conv_to_r8_un (guint32 a)
878 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
880 mono_lconv_to_r8_un (guint64 a)
887 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
889 MonoMethod *vmethod, *inflated;
891 MonoGenericContext *context = mono_method_get_context (method);
893 mono_jit_stats.generic_virtual_invocations++;
896 mono_raise_exception (mono_get_exception_null_reference ());
897 vmethod = mono_object_get_virtual_method (obj, method);
899 /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the
900 declaring class have been inflated. We still need to fully inflate the method parameters.
902 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
905 g_assert (!vmethod->klass->generic_container);
906 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
907 g_assert (!context->method_inst || !context->method_inst->is_open);
908 inflated = mono_class_inflate_generic_method (vmethod, context);
909 if (mono_method_needs_static_rgctx_invoke (inflated, FALSE))
910 inflated = mono_marshal_get_static_rgctx_invoke (inflated);
911 addr = mono_compile_method (inflated);
913 /* Since this is a virtual call, have to unbox vtypes */
914 if (obj->vtable->klass->valuetype)
915 *this_arg = mono_object_unbox (obj);
923 mono_helper_ldstr (MonoImage *image, guint32 idx)
925 return mono_ldstr (mono_domain_get (), image, idx);
929 mono_helper_ldstr_mscorlib (guint32 idx)
931 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
935 mono_helper_newobj_mscorlib (guint32 idx)
937 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
941 return mono_object_new (mono_domain_get (), klass);
945 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
946 * in generated code. So instead we emit a call to this function and place a gdb
955 mono_create_corlib_exception_0 (guint32 token)
957 return mono_exception_from_token (mono_defaults.corlib, token);
961 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
963 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
967 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
969 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
973 mono_object_castclass (MonoObject *obj, MonoClass *klass)
978 if (mono_object_isinst (obj, klass))
981 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
982 "System", "InvalidCastException"));