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.
17 #include "jit-icalls.h"
20 mono_ldftn (MonoMethod *method)
26 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
28 return mono_create_ftnptr (mono_domain_get (), addr);
32 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
39 mono_raise_exception (mono_get_exception_null_reference ());
41 res = mono_object_get_virtual_method (obj, method);
43 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
44 MonoGenericContext context = { NULL, NULL };
46 if (res->klass->generic_class)
47 context.class_inst = res->klass->generic_class->context.class_inst;
48 else if (res->klass->generic_container)
49 context.class_inst = res->klass->generic_container->context.class_inst;
50 context.method_inst = mono_method_get_context (method)->method_inst;
52 res = mono_class_inflate_generic_method (res, &context);
55 if (mono_method_needs_static_rgctx_invoke (res, FALSE))
56 res = mono_marshal_get_static_rgctx_invoke (res);
58 return mono_ldftn (res);
62 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
64 return ldvirtfn_internal (obj, method, FALSE);
68 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
70 return ldvirtfn_internal (obj, method, TRUE);
74 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
78 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
79 mono_raise_exception (mono_get_exception_array_type_mismatch ());
82 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
85 mono_llmult (gint64 a, gint64 b)
87 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
92 mono_llmult_ovf_un (guint64 a, guint64 b)
102 // fixme: this is incredible slow
105 goto raise_exception;
107 res = (guint64)al * (guint64)bl;
109 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
112 goto raise_exception;
114 res += ((guint64)t1) << 32;
119 mono_raise_exception (mono_get_exception_overflow ());
124 mono_llmult_ovf (gint64 a, gint64 b)
131 Use Karatsuba algorithm where:
132 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
133 where Ah is the "high half" (most significant 32 bits) of a and
134 where Al is the "low half" (least significant 32 bits) of a and
135 where Bh is the "high half" of b and Bl is the "low half" and
136 where R is the Radix or "size of the half" (in our case 32 bits)
138 Note, for the product of two 64 bit numbers to fit into a 64
139 result, ah and/or bh must be 0. This will save us from doing
140 the AhBh term at all.
142 Also note that we refactor so that we don't overflow 64 bits with
143 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
151 /* need to work with absoulte values, so find out what the
152 resulting sign will be and convert any negative numbers
153 from two's complement
157 if (((guint32)ah == 0x80000000) && (al == 0)) {
158 /* This has no two's complement */
164 goto raise_exception;
167 /* flip the bits and add 1 */
178 if (((guint32)bh == 0x80000000) && (bl == 0)) {
179 /* This has no two's complement */
185 goto raise_exception;
188 /* flip the bits and add 1 */
198 /* we overflow for sure if both upper halves are greater
199 than zero because we would need to shift their
200 product 64 bits to the left and that will not fit
201 in a 64 bit result */
203 goto raise_exception;
204 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
205 goto raise_exception;
207 /* do the AlBl term first */
208 t1 = (gint64)al * (gint64)bl;
212 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
213 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
214 /* check for overflow */
216 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
217 goto raise_exception;
222 goto raise_exception;
230 mono_raise_exception (mono_get_exception_overflow ());
234 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
237 mono_idiv (gint32 a, gint32 b)
241 #ifdef MONO_ARCH_NEED_DIV_CHECK
243 mono_raise_exception (mono_get_exception_divide_by_zero ());
244 else if (b == -1 && a == (0x80000000))
245 mono_raise_exception (mono_get_exception_arithmetic ());
251 mono_idiv_un (guint32 a, guint32 b)
255 #ifdef MONO_ARCH_NEED_DIV_CHECK
257 mono_raise_exception (mono_get_exception_divide_by_zero ());
263 mono_irem (gint32 a, gint32 b)
267 #ifdef MONO_ARCH_NEED_DIV_CHECK
269 mono_raise_exception (mono_get_exception_divide_by_zero ());
270 else if (b == -1 && a == (0x80000000))
271 mono_raise_exception (mono_get_exception_arithmetic ());
278 mono_irem_un (guint32 a, guint32 b)
282 #ifdef MONO_ARCH_NEED_DIV_CHECK
284 mono_raise_exception (mono_get_exception_divide_by_zero ());
291 #ifdef MONO_ARCH_EMULATE_MUL_DIV
294 mono_imul (gint32 a, gint32 b)
302 mono_imul_ovf (gint32 a, gint32 b)
308 res = (gint64)a * (gint64)b;
310 if ((res > 0x7fffffffL) || (res < -2147483648))
311 mono_raise_exception (mono_get_exception_overflow ());
317 mono_imul_ovf_un (guint32 a, guint32 b)
323 res = (guint64)a * (guint64)b;
326 mono_raise_exception (mono_get_exception_overflow ());
332 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
334 mono_fdiv (double a, double b)
343 mono_lldiv (gint64 a, gint64 b)
347 #ifdef MONO_ARCH_NEED_DIV_CHECK
349 mono_raise_exception (mono_get_exception_divide_by_zero ());
350 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
351 mono_raise_exception (mono_get_exception_arithmetic ());
357 mono_llrem (gint64 a, gint64 b)
361 #ifdef MONO_ARCH_NEED_DIV_CHECK
363 mono_raise_exception (mono_get_exception_divide_by_zero ());
364 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
365 mono_raise_exception (mono_get_exception_arithmetic ());
371 mono_lldiv_un (guint64 a, guint64 b)
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
377 mono_raise_exception (mono_get_exception_divide_by_zero ());
383 mono_llrem_un (guint64 a, guint64 b)
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
389 mono_raise_exception (mono_get_exception_divide_by_zero ());
396 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
399 mono_lshl (guint64 a, gint32 shamt)
403 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
406 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
412 mono_lshr_un (guint64 a, gint32 shamt)
416 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
419 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
425 mono_lshr (gint64 a, gint32 shamt)
429 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
432 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
439 #ifdef MONO_ARCH_SOFT_FLOAT
442 mono_fsub (double a, double b)
448 mono_fadd (double a, double b)
454 mono_fmul (double a, double b)
466 mono_fconv_r4 (double a)
472 mono_conv_to_r8 (int a)
478 mono_conv_to_r4 (int a)
480 return (double)(float)a;
484 mono_fconv_i1 (double a)
490 mono_fconv_i2 (double a)
496 mono_fconv_i4 (double a)
502 mono_fconv_u1 (double a)
508 mono_fconv_u2 (double a)
514 mono_fcmp_eq (double a, double b)
520 mono_fcmp_ge (double a, double b)
526 mono_fcmp_gt (double a, double b)
532 mono_fcmp_le (double a, double b)
538 mono_fcmp_lt (double a, double b)
544 mono_fcmp_ne_un (double a, double b)
546 return isunordered (a, b) || a != b;
550 mono_fcmp_ge_un (double a, double b)
552 return isunordered (a, b) || a >= b;
556 mono_fcmp_gt_un (double a, double b)
558 return isunordered (a, b) || a > b;
562 mono_fcmp_le_un (double a, double b)
564 return isunordered (a, b) || a <= b;
568 mono_fcmp_lt_un (double a, double b)
570 return isunordered (a, b) || a < b;
574 mono_fceq (double a, double b)
580 mono_fcgt (double a, double b)
586 mono_fcgt_un (double a, double b)
588 return isunordered (a, b) || a > b;
592 mono_fclt (double a, double b)
598 mono_fclt_un (double a, double b)
600 return isunordered (a, b) || a < b;
604 mono_fload_r4 (float *ptr)
610 mono_fstore_r4 (double val, float *ptr)
615 /* returns the integer bitpattern that is passed in the regs or stack */
617 mono_fload_r4_arg (double val)
619 float v = (float)val;
620 return *(guint32*)&v;
626 mono_array_new_va (MonoMethod *cm, ...)
628 MonoDomain *domain = mono_domain_get ();
631 guint32 *lower_bounds;
638 pcount = mono_method_signature (cm)->param_count;
639 rank = cm->klass->rank;
643 lengths = alloca (sizeof (guint32) * pcount);
644 for (i = 0; i < pcount; ++i)
645 lengths [i] = d = va_arg(ap, int);
647 if (rank == pcount) {
648 /* Only lengths provided. */
649 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
650 lower_bounds = alloca (sizeof (guint32) * rank);
651 memset (lower_bounds, 0, sizeof (guint32) * rank);
656 g_assert (pcount == (rank * 2));
657 /* lower bounds are first. */
658 lower_bounds = lengths;
663 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
666 /* Specialized version of mono_array_new_va () which avoids varargs */
668 mono_array_new_1 (MonoMethod *cm, guint32 length)
670 MonoDomain *domain = mono_domain_get ();
672 guint32 *lower_bounds;
678 pcount = mono_method_signature (cm)->param_count;
679 rank = cm->klass->rank;
681 lengths [0] = length;
683 g_assert (rank == pcount);
685 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
686 lower_bounds = alloca (sizeof (guint32) * rank);
687 memset (lower_bounds, 0, sizeof (guint32) * rank);
692 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
696 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
698 MonoDomain *domain = mono_domain_get ();
700 guint32 *lower_bounds;
706 pcount = mono_method_signature (cm)->param_count;
707 rank = cm->klass->rank;
709 lengths [0] = length1;
710 lengths [1] = length2;
712 g_assert (rank == pcount);
714 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
715 lower_bounds = alloca (sizeof (guint32) * rank);
716 memset (lower_bounds, 0, sizeof (guint32) * rank);
721 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
725 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
732 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
734 mono_class_init (field->parent);
736 vtable = mono_class_vtable (domain, field->parent);
737 if (!vtable->initialized)
738 mono_runtime_class_init (vtable);
740 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
742 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
743 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
745 addr = (char*)vtable->data + field->offset;
751 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
753 MonoClass *handle_class;
757 res = mono_ldtoken (image, token, &handle_class, context);
758 mono_class_init (handle_class);
764 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
766 MonoMethodSignature *sig = mono_method_signature (method);
767 MonoGenericContext *generic_context;
769 if (sig->is_inflated) {
770 generic_context = mono_method_get_context (method);
772 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
773 g_assert (generic_container);
774 generic_context = &generic_container->context;
777 return mono_ldtoken_wrapper (image, token, generic_context);
781 mono_fconv_u8 (double v)
786 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
788 mono_fconv_i8 (double v)
790 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
796 mono_fconv_u4 (double v)
798 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
803 /* Solaris doesn't have trunc */
805 extern long double aintl (long double);
808 /* FIXME: This means we will never throw overflow exceptions */
811 #endif /* HAVE_TRUNC */
814 mono_fconv_ovf_i8 (double v)
822 if (isnan(v) || trunc (v) != res) {
823 mono_raise_exception (mono_get_exception_overflow ());
829 mono_fconv_ovf_u8 (double v)
835 * The soft-float implementation of some ARM devices have a buggy guin64 to double
836 * conversion that it looses precision even when the integer if fully representable
839 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
841 * To work around this issue we test for value boundaries instead.
843 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
844 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
845 mono_raise_exception (mono_get_exception_overflow ());
850 if (isnan(v) || trunc (v) != res) {
851 mono_raise_exception (mono_get_exception_overflow ());
857 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
859 mono_lconv_to_r8 (gint64 a)
865 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
867 mono_lconv_to_r4 (gint64 a)
873 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
875 mono_conv_to_r8_un (guint32 a)
881 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
883 mono_lconv_to_r8_un (guint64 a)
890 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
892 MonoMethod *vmethod, *inflated;
894 MonoGenericContext *context = mono_method_get_context (method);
896 mono_jit_stats.generic_virtual_invocations++;
899 mono_raise_exception (mono_get_exception_null_reference ());
900 vmethod = mono_object_get_virtual_method (obj, method);
902 /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the
903 declaring class have been inflated. We still need to fully inflate the method parameters.
905 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
908 g_assert (!vmethod->klass->generic_container);
909 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
910 g_assert (!context->method_inst || !context->method_inst->is_open);
911 inflated = mono_class_inflate_generic_method (vmethod, context);
912 if (mono_method_needs_static_rgctx_invoke (inflated, FALSE))
913 inflated = mono_marshal_get_static_rgctx_invoke (inflated);
914 addr = mono_compile_method (inflated);
916 /* Since this is a virtual call, have to unbox vtypes */
917 if (obj->vtable->klass->valuetype)
918 *this_arg = mono_object_unbox (obj);
926 mono_helper_ldstr (MonoImage *image, guint32 idx)
928 return mono_ldstr (mono_domain_get (), image, idx);
932 mono_helper_ldstr_mscorlib (guint32 idx)
934 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
938 mono_helper_newobj_mscorlib (guint32 idx)
940 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
944 return mono_object_new (mono_domain_get (), klass);
948 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
949 * in generated code. So instead we emit a call to this function and place a gdb
958 mono_create_corlib_exception_0 (guint32 token)
960 return mono_exception_from_token (mono_defaults.corlib, token);
964 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
966 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
970 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
972 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
976 mono_object_castclass (MonoObject *obj, MonoClass *klass)
981 if (mono_object_isinst (obj, klass))
984 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
985 "System", "InvalidCastException"));