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 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
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 < -2147483648LL))
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_isfinite (double a)
609 g_assert_not_reached ();
615 mono_fload_r4 (float *ptr)
621 mono_fstore_r4 (double val, float *ptr)
626 /* returns the integer bitpattern that is passed in the regs or stack */
628 mono_fload_r4_arg (double val)
630 float v = (float)val;
631 return *(guint32*)&v;
637 mono_array_new_va (MonoMethod *cm, ...)
639 MonoDomain *domain = mono_domain_get ();
642 guint32 *lower_bounds;
649 pcount = mono_method_signature (cm)->param_count;
650 rank = cm->klass->rank;
654 lengths = alloca (sizeof (guint32) * pcount);
655 for (i = 0; i < pcount; ++i)
656 lengths [i] = d = va_arg(ap, int);
658 if (rank == pcount) {
659 /* Only lengths provided. */
660 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
661 lower_bounds = alloca (sizeof (guint32) * rank);
662 memset (lower_bounds, 0, sizeof (guint32) * rank);
667 g_assert (pcount == (rank * 2));
668 /* lower bounds are first. */
669 lower_bounds = lengths;
674 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
677 /* Specialized version of mono_array_new_va () which avoids varargs */
679 mono_array_new_1 (MonoMethod *cm, guint32 length)
681 MonoDomain *domain = mono_domain_get ();
683 guint32 *lower_bounds;
689 pcount = mono_method_signature (cm)->param_count;
690 rank = cm->klass->rank;
692 lengths [0] = length;
694 g_assert (rank == pcount);
696 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
697 lower_bounds = alloca (sizeof (guint32) * rank);
698 memset (lower_bounds, 0, sizeof (guint32) * rank);
703 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
707 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
709 MonoDomain *domain = mono_domain_get ();
711 guint32 *lower_bounds;
717 pcount = mono_method_signature (cm)->param_count;
718 rank = cm->klass->rank;
720 lengths [0] = length1;
721 lengths [1] = length2;
723 g_assert (rank == pcount);
725 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
726 lower_bounds = alloca (sizeof (guint32) * rank);
727 memset (lower_bounds, 0, sizeof (guint32) * rank);
732 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
736 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
743 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
745 mono_class_init (field->parent);
747 vtable = mono_class_vtable (domain, field->parent);
748 if (!vtable->initialized)
749 mono_runtime_class_init (vtable);
751 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
753 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
754 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
756 addr = (char*)vtable->data + field->offset;
762 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
764 MonoClass *handle_class;
768 res = mono_ldtoken (image, token, &handle_class, context);
769 mono_class_init (handle_class);
775 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
777 MonoMethodSignature *sig = mono_method_signature (method);
778 MonoGenericContext *generic_context;
780 if (sig->is_inflated) {
781 generic_context = mono_method_get_context (method);
783 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
784 g_assert (generic_container);
785 generic_context = &generic_container->context;
788 return mono_ldtoken_wrapper (image, token, generic_context);
792 mono_fconv_u8 (double v)
797 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
799 mono_fconv_i8 (double v)
801 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
807 mono_fconv_u4 (double v)
809 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
814 /* Solaris doesn't have trunc */
816 extern long double aintl (long double);
819 /* FIXME: This means we will never throw overflow exceptions */
822 #endif /* HAVE_TRUNC */
825 mono_fconv_ovf_i8 (double v)
833 if (isnan(v) || trunc (v) != res) {
834 mono_raise_exception (mono_get_exception_overflow ());
840 mono_fconv_ovf_u8 (double v)
846 * The soft-float implementation of some ARM devices have a buggy guin64 to double
847 * conversion that it looses precision even when the integer if fully representable
850 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
852 * To work around this issue we test for value boundaries instead.
854 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
855 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
856 mono_raise_exception (mono_get_exception_overflow ());
861 if (isnan(v) || trunc (v) != res) {
862 mono_raise_exception (mono_get_exception_overflow ());
868 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
870 mono_lconv_to_r8 (gint64 a)
876 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
878 mono_lconv_to_r4 (gint64 a)
884 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
886 mono_conv_to_r8_un (guint32 a)
892 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
894 mono_lconv_to_r8_un (guint64 a)
901 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
905 MonoGenericContext *context = mono_method_get_context (method);
907 mono_jit_stats.generic_virtual_invocations++;
910 mono_raise_exception (mono_get_exception_null_reference ());
911 vmethod = mono_object_get_virtual_method (obj, method);
912 g_assert (!vmethod->klass->generic_container);
913 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
914 g_assert (!context->method_inst || !context->method_inst->is_open);
915 if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
916 vmethod = mono_marshal_get_static_rgctx_invoke (vmethod);
917 addr = mono_compile_method (vmethod);
919 /* Since this is a virtual call, have to unbox vtypes */
920 if (obj->vtable->klass->valuetype)
921 *this_arg = mono_object_unbox (obj);
929 mono_helper_ldstr (MonoImage *image, guint32 idx)
931 return mono_ldstr (mono_domain_get (), image, idx);
935 mono_helper_ldstr_mscorlib (guint32 idx)
937 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
941 mono_helper_newobj_mscorlib (guint32 idx)
943 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
947 return mono_object_new (mono_domain_get (), klass);
951 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
952 * in generated code. So instead we emit a call to this function and place a gdb
961 mono_create_corlib_exception_0 (guint32 token)
963 return mono_exception_from_token (mono_defaults.corlib, token);
967 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
969 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
973 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
975 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
979 mono_object_castclass (MonoObject *obj, MonoClass *klass)
984 if (mono_object_isinst (obj, klass))
987 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
988 "System", "InvalidCastException"));