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, TRUE);
25 return mono_create_ftnptr (mono_domain_get (), addr);
29 * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
30 * synchronized wrappers to avoid infinite recursion.
33 mono_ldftn_nosync (MonoMethod *method)
39 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
41 return mono_create_ftnptr (mono_domain_get (), addr);
45 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
52 mono_raise_exception (mono_get_exception_null_reference ());
54 res = mono_object_get_virtual_method (obj, method);
56 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
57 MonoGenericContext context = { NULL, NULL };
59 if (res->klass->generic_class)
60 context.class_inst = res->klass->generic_class->context.class_inst;
61 else if (res->klass->generic_container)
62 context.class_inst = res->klass->generic_container->context.class_inst;
63 context.method_inst = mono_method_get_context (method)->method_inst;
65 res = mono_class_inflate_generic_method (res, &context);
68 /* FIXME: only do this for methods which can be shared! */
69 if (res->is_inflated && mono_method_get_context (res)->method_inst &&
70 mono_class_generic_sharing_enabled (res->klass)) {
71 res = mono_marshal_get_static_rgctx_invoke (res);
74 return mono_ldftn (res);
78 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
80 return ldvirtfn_internal (obj, method, FALSE);
84 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
86 return ldvirtfn_internal (obj, method, TRUE);
90 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
94 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
95 mono_raise_exception (mono_get_exception_array_type_mismatch ());
98 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
101 mono_llmult (gint64 a, gint64 b)
103 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
108 mono_llmult_ovf_un (guint64 a, guint64 b)
111 guint32 ah = a >> 32;
113 guint32 bh = b >> 32;
118 // fixme: this is incredible slow
121 goto raise_exception;
123 res = (guint64)al * (guint64)bl;
125 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
128 goto raise_exception;
130 res += ((guint64)t1) << 32;
135 mono_raise_exception (mono_get_exception_overflow ());
140 mono_llmult_ovf (gint64 a, gint64 b)
147 Use Karatsuba algorithm where:
148 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
149 where Ah is the "high half" (most significant 32 bits) of a and
150 where Al is the "low half" (least significant 32 bits) of a and
151 where Bh is the "high half" of b and Bl is the "low half" and
152 where R is the Radix or "size of the half" (in our case 32 bits)
154 Note, for the product of two 64 bit numbers to fit into a 64
155 result, ah and/or bh must be 0. This will save us from doing
156 the AhBh term at all.
158 Also note that we refactor so that we don't overflow 64 bits with
159 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
167 /* need to work with absoulte values, so find out what the
168 resulting sign will be and convert any negative numbers
169 from two's complement
173 if (((guint32)ah == 0x80000000) && (al == 0)) {
174 /* This has no two's complement */
180 goto raise_exception;
183 /* flip the bits and add 1 */
194 if (((guint32)bh == 0x80000000) && (bl == 0)) {
195 /* This has no two's complement */
201 goto raise_exception;
204 /* flip the bits and add 1 */
214 /* we overflow for sure if both upper halves are greater
215 than zero because we would need to shift their
216 product 64 bits to the left and that will not fit
217 in a 64 bit result */
219 goto raise_exception;
220 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
221 goto raise_exception;
223 /* do the AlBl term first */
224 t1 = (gint64)al * (gint64)bl;
228 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
229 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
230 /* check for overflow */
232 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
233 goto raise_exception;
238 goto raise_exception;
246 mono_raise_exception (mono_get_exception_overflow ());
250 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
253 mono_idiv (gint32 a, gint32 b)
257 #ifdef MONO_ARCH_NEED_DIV_CHECK
259 mono_raise_exception (mono_get_exception_divide_by_zero ());
260 else if (b == -1 && a == (0x80000000))
261 mono_raise_exception (mono_get_exception_arithmetic ());
267 mono_idiv_un (guint32 a, guint32 b)
271 #ifdef MONO_ARCH_NEED_DIV_CHECK
273 mono_raise_exception (mono_get_exception_divide_by_zero ());
279 mono_irem (gint32 a, gint32 b)
283 #ifdef MONO_ARCH_NEED_DIV_CHECK
285 mono_raise_exception (mono_get_exception_divide_by_zero ());
286 else if (b == -1 && a == (0x80000000))
287 mono_raise_exception (mono_get_exception_arithmetic ());
294 mono_irem_un (guint32 a, guint32 b)
298 #ifdef MONO_ARCH_NEED_DIV_CHECK
300 mono_raise_exception (mono_get_exception_divide_by_zero ());
307 #ifdef MONO_ARCH_EMULATE_MUL_DIV
310 mono_imul (gint32 a, gint32 b)
318 mono_imul_ovf (gint32 a, gint32 b)
324 res = (gint64)a * (gint64)b;
326 if ((res > 0x7fffffffL) || (res < -2147483648))
327 mono_raise_exception (mono_get_exception_overflow ());
333 mono_imul_ovf_un (guint32 a, guint32 b)
339 res = (guint64)a * (guint64)b;
342 mono_raise_exception (mono_get_exception_overflow ());
348 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
350 mono_fdiv (double a, double b)
359 mono_lldiv (gint64 a, gint64 b)
363 #ifdef MONO_ARCH_NEED_DIV_CHECK
365 mono_raise_exception (mono_get_exception_divide_by_zero ());
366 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
367 mono_raise_exception (mono_get_exception_arithmetic ());
373 mono_llrem (gint64 a, gint64 b)
377 #ifdef MONO_ARCH_NEED_DIV_CHECK
379 mono_raise_exception (mono_get_exception_divide_by_zero ());
380 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
381 mono_raise_exception (mono_get_exception_arithmetic ());
387 mono_lldiv_un (guint64 a, guint64 b)
391 #ifdef MONO_ARCH_NEED_DIV_CHECK
393 mono_raise_exception (mono_get_exception_divide_by_zero ());
399 mono_llrem_un (guint64 a, guint64 b)
403 #ifdef MONO_ARCH_NEED_DIV_CHECK
405 mono_raise_exception (mono_get_exception_divide_by_zero ());
412 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
415 mono_lshl (guint64 a, gint32 shamt)
419 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
422 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
428 mono_lshr_un (guint64 a, gint32 shamt)
432 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
435 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
441 mono_lshr (gint64 a, gint32 shamt)
445 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
448 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
455 #ifdef MONO_ARCH_SOFT_FLOAT
458 mono_fsub (double a, double b)
464 mono_fadd (double a, double b)
470 mono_fmul (double a, double b)
482 mono_fconv_r4 (double a)
488 mono_conv_to_r8 (int a)
494 mono_conv_to_r4 (int a)
496 return (double)(float)a;
500 mono_fconv_i1 (double a)
506 mono_fconv_i2 (double a)
512 mono_fconv_i4 (double a)
518 mono_fconv_u1 (double a)
524 mono_fconv_u2 (double a)
530 mono_fcmp_eq (double a, double b)
536 mono_fcmp_ge (double a, double b)
542 mono_fcmp_gt (double a, double b)
548 mono_fcmp_le (double a, double b)
554 mono_fcmp_lt (double a, double b)
560 mono_fcmp_ne_un (double a, double b)
562 return isunordered (a, b) || a != b;
566 mono_fcmp_ge_un (double a, double b)
568 return isunordered (a, b) || a >= b;
572 mono_fcmp_gt_un (double a, double b)
574 return isunordered (a, b) || a > b;
578 mono_fcmp_le_un (double a, double b)
580 return isunordered (a, b) || a <= b;
584 mono_fcmp_lt_un (double a, double b)
586 return isunordered (a, b) || a < b;
590 mono_fceq (double a, double b)
596 mono_fcgt (double a, double b)
602 mono_fcgt_un (double a, double b)
604 return isunordered (a, b) || a > b;
608 mono_fclt (double a, double b)
614 mono_fclt_un (double a, double b)
616 return isunordered (a, b) || a < b;
620 mono_fload_r4 (float *ptr)
626 mono_fstore_r4 (double val, float *ptr)
631 /* returns the integer bitpattern that is passed in the regs or stack */
633 mono_fload_r4_arg (double val)
635 float v = (float)val;
636 return *(guint32*)&v;
642 mono_array_new_va (MonoMethod *cm, ...)
644 MonoDomain *domain = mono_domain_get ();
647 guint32 *lower_bounds;
654 pcount = mono_method_signature (cm)->param_count;
655 rank = cm->klass->rank;
659 lengths = alloca (sizeof (guint32) * pcount);
660 for (i = 0; i < pcount; ++i)
661 lengths [i] = d = va_arg(ap, int);
663 if (rank == pcount) {
664 /* Only lengths provided. */
665 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
666 lower_bounds = alloca (sizeof (guint32) * rank);
667 memset (lower_bounds, 0, sizeof (guint32) * rank);
672 g_assert (pcount == (rank * 2));
673 /* lower bounds are first. */
674 lower_bounds = lengths;
679 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
682 /* Specialized version of mono_array_new_va () which avoids varargs */
684 mono_array_new_1 (MonoMethod *cm, guint32 length)
686 MonoDomain *domain = mono_domain_get ();
688 guint32 *lower_bounds;
694 pcount = mono_method_signature (cm)->param_count;
695 rank = cm->klass->rank;
697 lengths [0] = length;
699 g_assert (rank == pcount);
701 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
702 lower_bounds = alloca (sizeof (guint32) * rank);
703 memset (lower_bounds, 0, sizeof (guint32) * rank);
708 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
712 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
714 MonoDomain *domain = mono_domain_get ();
716 guint32 *lower_bounds;
722 pcount = mono_method_signature (cm)->param_count;
723 rank = cm->klass->rank;
725 lengths [0] = length1;
726 lengths [1] = length2;
728 g_assert (rank == pcount);
730 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
731 lower_bounds = alloca (sizeof (guint32) * rank);
732 memset (lower_bounds, 0, sizeof (guint32) * rank);
737 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
741 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
748 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
750 mono_class_init (field->parent);
752 vtable = mono_class_vtable (domain, field->parent);
753 if (!vtable->initialized)
754 mono_runtime_class_init (vtable);
756 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
758 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
759 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
761 addr = (char*)vtable->data + field->offset;
767 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
769 MonoClass *handle_class;
773 res = mono_ldtoken (image, token, &handle_class, context);
774 mono_class_init (handle_class);
780 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
782 MonoMethodSignature *sig = mono_method_signature (method);
783 MonoGenericContext *generic_context;
785 if (sig->is_inflated) {
786 generic_context = mono_method_get_context (method);
788 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
789 g_assert (generic_container);
790 generic_context = &generic_container->context;
793 return mono_ldtoken_wrapper (image, token, generic_context);
797 mono_fconv_u8 (double v)
802 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
804 mono_fconv_i8 (double v)
806 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
812 mono_fconv_u4 (double v)
814 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
819 /* Solaris doesn't have trunc */
821 extern long double aintl (long double);
824 /* FIXME: This means we will never throw overflow exceptions */
827 #endif /* HAVE_TRUNC */
830 mono_fconv_ovf_i8 (double v)
838 if (isnan(v) || trunc (v) != res) {
839 mono_raise_exception (mono_get_exception_overflow ());
845 mono_fconv_ovf_u8 (double v)
851 * The soft-float implementation of some ARM devices have a buggy guin64 to double
852 * conversion that it looses precision even when the integer if fully representable
855 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
857 * To work around this issue we test for value boundaries instead.
859 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
860 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
861 mono_raise_exception (mono_get_exception_overflow ());
866 if (isnan(v) || trunc (v) != res) {
867 mono_raise_exception (mono_get_exception_overflow ());
873 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
875 mono_lconv_to_r8 (gint64 a)
881 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
883 mono_lconv_to_r4 (gint64 a)
889 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
891 mono_conv_to_r8_un (guint32 a)
897 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
899 mono_lconv_to_r8_un (guint64 a)
906 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
908 MonoMethod *vmethod, *inflated;
910 MonoGenericContext *context = mono_method_get_context (method);
912 mono_jit_stats.generic_virtual_invocations++;
915 mono_raise_exception (mono_get_exception_null_reference ());
916 vmethod = mono_object_get_virtual_method (obj, method);
918 /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the
919 declaring class have been inflated. We still need to fully inflate the method parameters.
921 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
924 g_assert (!vmethod->klass->generic_container);
925 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
926 g_assert (!context->method_inst || !context->method_inst->is_open);
927 inflated = mono_class_inflate_generic_method (vmethod, context);
928 if (mono_class_generic_sharing_enabled (inflated->klass) &&
929 mono_method_is_generic_sharable_impl (method, FALSE)) {
930 /* The method is shared generic code, so it needs a
932 inflated = mono_marshal_get_static_rgctx_invoke (inflated);
934 addr = mono_compile_method (inflated);
936 /* Since this is a virtual call, have to unbox vtypes */
937 if (obj->vtable->klass->valuetype)
938 *this_arg = mono_object_unbox (obj);
946 mono_helper_ldstr (MonoImage *image, guint32 idx)
948 return mono_ldstr (mono_domain_get (), image, idx);
952 mono_helper_ldstr_mscorlib (guint32 idx)
954 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
958 mono_helper_newobj_mscorlib (guint32 idx)
960 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
964 return mono_object_new (mono_domain_get (), klass);
968 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
969 * in generated code. So instead we emit a call to this function and place a gdb
978 mono_create_corlib_exception_0 (guint32 token)
980 return mono_exception_from_token (mono_defaults.corlib, token);
984 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
986 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
990 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
992 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
996 mono_object_castclass (MonoObject *obj, MonoClass *klass)
1001 if (mono_object_isinst (obj, klass))
1004 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1005 "System", "InvalidCastException"));