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 /* An rgctx wrapper is added by the trampolines no need to do it here */
57 return mono_ldftn (res);
61 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
63 return ldvirtfn_internal (obj, method, FALSE);
67 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
69 return ldvirtfn_internal (obj, method, TRUE);
73 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
78 mono_raise_exception (mono_get_exception_null_reference ());
79 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
80 mono_raise_exception (mono_get_exception_array_type_mismatch ());
83 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
86 mono_llmult (gint64 a, gint64 b)
88 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
93 mono_llmult_ovf_un (guint64 a, guint64 b)
103 // fixme: this is incredible slow
106 goto raise_exception;
108 res = (guint64)al * (guint64)bl;
110 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
113 goto raise_exception;
115 res += ((guint64)t1) << 32;
120 mono_raise_exception (mono_get_exception_overflow ());
125 mono_llmult_ovf (gint64 a, gint64 b)
132 Use Karatsuba algorithm where:
133 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
134 where Ah is the "high half" (most significant 32 bits) of a and
135 where Al is the "low half" (least significant 32 bits) of a and
136 where Bh is the "high half" of b and Bl is the "low half" and
137 where R is the Radix or "size of the half" (in our case 32 bits)
139 Note, for the product of two 64 bit numbers to fit into a 64
140 result, ah and/or bh must be 0. This will save us from doing
141 the AhBh term at all.
143 Also note that we refactor so that we don't overflow 64 bits with
144 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
152 /* need to work with absoulte values, so find out what the
153 resulting sign will be and convert any negative numbers
154 from two's complement
158 if (((guint32)ah == 0x80000000) && (al == 0)) {
159 /* This has no two's complement */
165 goto raise_exception;
168 /* flip the bits and add 1 */
179 if (((guint32)bh == 0x80000000) && (bl == 0)) {
180 /* This has no two's complement */
186 goto raise_exception;
189 /* flip the bits and add 1 */
199 /* we overflow for sure if both upper halves are greater
200 than zero because we would need to shift their
201 product 64 bits to the left and that will not fit
202 in a 64 bit result */
204 goto raise_exception;
205 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
206 goto raise_exception;
208 /* do the AlBl term first */
209 t1 = (gint64)al * (gint64)bl;
213 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
214 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
215 /* check for overflow */
217 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
218 goto raise_exception;
223 goto raise_exception;
231 mono_raise_exception (mono_get_exception_overflow ());
235 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
238 mono_idiv (gint32 a, gint32 b)
242 #ifdef MONO_ARCH_NEED_DIV_CHECK
244 mono_raise_exception (mono_get_exception_divide_by_zero ());
245 else if (b == -1 && a == (0x80000000))
246 mono_raise_exception (mono_get_exception_overflow ());
252 mono_idiv_un (guint32 a, guint32 b)
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
258 mono_raise_exception (mono_get_exception_divide_by_zero ());
264 mono_irem (gint32 a, gint32 b)
268 #ifdef MONO_ARCH_NEED_DIV_CHECK
270 mono_raise_exception (mono_get_exception_divide_by_zero ());
271 else if (b == -1 && a == (0x80000000))
272 mono_raise_exception (mono_get_exception_overflow ());
279 mono_irem_un (guint32 a, guint32 b)
283 #ifdef MONO_ARCH_NEED_DIV_CHECK
285 mono_raise_exception (mono_get_exception_divide_by_zero ());
292 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
295 mono_imul (gint32 a, gint32 b)
303 mono_imul_ovf (gint32 a, gint32 b)
309 res = (gint64)a * (gint64)b;
311 if ((res > 0x7fffffffL) || (res < -2147483648LL))
312 mono_raise_exception (mono_get_exception_overflow ());
318 mono_imul_ovf_un (guint32 a, guint32 b)
324 res = (guint64)a * (guint64)b;
327 mono_raise_exception (mono_get_exception_overflow ());
333 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
335 mono_fdiv (double a, double b)
344 mono_lldiv (gint64 a, gint64 b)
348 #ifdef MONO_ARCH_NEED_DIV_CHECK
350 mono_raise_exception (mono_get_exception_divide_by_zero ());
351 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
352 mono_raise_exception (mono_get_exception_arithmetic ());
358 mono_llrem (gint64 a, gint64 b)
362 #ifdef MONO_ARCH_NEED_DIV_CHECK
364 mono_raise_exception (mono_get_exception_divide_by_zero ());
365 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
366 mono_raise_exception (mono_get_exception_arithmetic ());
372 mono_lldiv_un (guint64 a, guint64 b)
376 #ifdef MONO_ARCH_NEED_DIV_CHECK
378 mono_raise_exception (mono_get_exception_divide_by_zero ());
384 mono_llrem_un (guint64 a, guint64 b)
388 #ifdef MONO_ARCH_NEED_DIV_CHECK
390 mono_raise_exception (mono_get_exception_divide_by_zero ());
397 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
400 mono_lshl (guint64 a, gint32 shamt)
404 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
407 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
413 mono_lshr_un (guint64 a, gint32 shamt)
417 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
420 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
426 mono_lshr (gint64 a, gint32 shamt)
430 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
433 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
440 #ifdef MONO_ARCH_SOFT_FLOAT
443 mono_fsub (double a, double b)
449 mono_fadd (double a, double b)
455 mono_fmul (double a, double b)
467 mono_fconv_r4 (double a)
473 mono_conv_to_r8 (int a)
479 mono_conv_to_r4 (int a)
481 return (double)(float)a;
485 mono_fconv_i1 (double a)
491 mono_fconv_i2 (double a)
497 mono_fconv_i4 (double a)
503 mono_fconv_u1 (double a)
509 mono_fconv_u2 (double a)
515 mono_fcmp_eq (double a, double b)
521 mono_fcmp_ge (double a, double b)
527 mono_fcmp_gt (double a, double b)
533 mono_fcmp_le (double a, double b)
539 mono_fcmp_lt (double a, double b)
545 mono_fcmp_ne_un (double a, double b)
547 return isunordered (a, b) || a != b;
551 mono_fcmp_ge_un (double a, double b)
553 return isunordered (a, b) || a >= b;
557 mono_fcmp_gt_un (double a, double b)
559 return isunordered (a, b) || a > b;
563 mono_fcmp_le_un (double a, double b)
565 return isunordered (a, b) || a <= b;
569 mono_fcmp_lt_un (double a, double b)
571 return isunordered (a, b) || a < b;
575 mono_fceq (double a, double b)
581 mono_fcgt (double a, double b)
587 mono_fcgt_un (double a, double b)
589 return isunordered (a, b) || a > b;
593 mono_fclt (double a, double b)
599 mono_fclt_un (double a, double b)
601 return isunordered (a, b) || a < b;
605 mono_isfinite (double a)
610 g_assert_not_reached ();
616 mono_fload_r4 (float *ptr)
622 mono_fstore_r4 (double val, float *ptr)
627 /* returns the integer bitpattern that is passed in the regs or stack */
629 mono_fload_r4_arg (double val)
631 float v = (float)val;
632 return *(guint32*)&v;
638 mono_array_new_va (MonoMethod *cm, ...)
640 MonoDomain *domain = mono_domain_get ();
643 intptr_t *lower_bounds;
650 pcount = mono_method_signature (cm)->param_count;
651 rank = cm->klass->rank;
655 lengths = alloca (sizeof (uintptr_t) * pcount);
656 for (i = 0; i < pcount; ++i)
657 lengths [i] = d = va_arg(ap, int);
659 if (rank == pcount) {
660 /* Only lengths provided. */
661 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
662 lower_bounds = alloca (sizeof (intptr_t) * rank);
663 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
668 g_assert (pcount == (rank * 2));
669 /* lower bounds are first. */
670 lower_bounds = (intptr_t*)lengths;
675 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
678 /* Specialized version of mono_array_new_va () which avoids varargs */
680 mono_array_new_1 (MonoMethod *cm, guint32 length)
682 MonoDomain *domain = mono_domain_get ();
683 uintptr_t lengths [1];
684 intptr_t *lower_bounds;
690 pcount = mono_method_signature (cm)->param_count;
691 rank = cm->klass->rank;
693 lengths [0] = length;
695 g_assert (rank == pcount);
697 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
698 lower_bounds = alloca (sizeof (intptr_t) * rank);
699 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
704 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
708 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
710 MonoDomain *domain = mono_domain_get ();
711 uintptr_t lengths [2];
712 intptr_t *lower_bounds;
718 pcount = mono_method_signature (cm)->param_count;
719 rank = cm->klass->rank;
721 lengths [0] = length1;
722 lengths [1] = length2;
724 g_assert (rank == pcount);
726 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
727 lower_bounds = alloca (sizeof (intptr_t) * rank);
728 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
733 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
737 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
739 MonoDomain *domain = mono_domain_get ();
740 uintptr_t lengths [3];
741 intptr_t *lower_bounds;
747 pcount = mono_method_signature (cm)->param_count;
748 rank = cm->klass->rank;
750 lengths [0] = length1;
751 lengths [1] = length2;
752 lengths [2] = length3;
754 g_assert (rank == pcount);
756 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
757 lower_bounds = alloca (sizeof (intptr_t) * rank);
758 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
763 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
767 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
774 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
776 mono_class_init (field->parent);
778 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
779 if (!vtable->initialized)
780 mono_runtime_class_init (vtable);
782 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
784 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
785 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
787 addr = (char*)vtable->data + field->offset;
793 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
795 MonoClass *handle_class;
799 res = mono_ldtoken (image, token, &handle_class, context);
800 mono_class_init (handle_class);
806 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
808 MonoMethodSignature *sig = mono_method_signature (method);
809 MonoGenericContext *generic_context;
811 if (sig->is_inflated) {
812 generic_context = mono_method_get_context (method);
814 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
815 g_assert (generic_container);
816 generic_context = &generic_container->context;
819 return mono_ldtoken_wrapper (image, token, generic_context);
823 mono_fconv_u8 (double v)
828 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
830 mono_fconv_i8 (double v)
832 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
838 mono_fconv_u4 (double v)
840 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
845 /* Solaris doesn't have trunc */
847 extern long double aintl (long double);
850 /* FIXME: This means we will never throw overflow exceptions */
853 #endif /* HAVE_TRUNC */
856 mono_fconv_ovf_i8 (double v)
864 if (isnan(v) || trunc (v) != res) {
865 mono_raise_exception (mono_get_exception_overflow ());
871 mono_fconv_ovf_u8 (double v)
877 * The soft-float implementation of some ARM devices have a buggy guin64 to double
878 * conversion that it looses precision even when the integer if fully representable
881 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
883 * To work around this issue we test for value boundaries instead.
885 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
886 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
887 mono_raise_exception (mono_get_exception_overflow ());
892 if (isnan(v) || trunc (v) != res) {
893 mono_raise_exception (mono_get_exception_overflow ());
899 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
901 mono_lconv_to_r8 (gint64 a)
907 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
909 mono_lconv_to_r4 (gint64 a)
915 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
917 mono_conv_to_r8_un (guint32 a)
923 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
925 mono_lconv_to_r8_un (guint64 a)
931 #if defined(__native_client_codegen__) || defined(__native_client__)
932 /* When we cross-compile to Native Client we can't directly embed calls */
933 /* to the math library on the host. This will use the fmod on the target*/
935 mono_fmod(double a, double b)
942 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
946 MonoGenericContext *context = mono_method_get_context (method);
948 mono_jit_stats.generic_virtual_invocations++;
951 mono_raise_exception (mono_get_exception_null_reference ());
952 vmethod = mono_object_get_virtual_method (obj, method);
953 g_assert (!vmethod->klass->generic_container);
954 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
955 g_assert (!context->method_inst || !context->method_inst->is_open);
957 addr = mono_compile_method (vmethod);
959 if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
960 addr = mono_create_static_rgctx_trampoline (vmethod, addr);
962 /* Since this is a virtual call, have to unbox vtypes */
963 if (obj->vtable->klass->valuetype)
964 *this_arg = mono_object_unbox (obj);
972 mono_helper_ldstr (MonoImage *image, guint32 idx)
974 return mono_ldstr (mono_domain_get (), image, idx);
978 mono_helper_ldstr_mscorlib (guint32 idx)
980 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
984 mono_helper_newobj_mscorlib (guint32 idx)
986 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
990 return mono_object_new (mono_domain_get (), klass);
994 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
995 * in generated code. So instead we emit a call to this function and place a gdb
1004 mono_create_corlib_exception_0 (guint32 token)
1006 return mono_exception_from_token (mono_defaults.corlib, token);
1010 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1012 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1016 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1018 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1022 mono_object_castclass (MonoObject *obj, MonoClass *klass)
1024 MonoJitTlsData *jit_tls = NULL;
1026 if (mini_get_debug_options ()->better_cast_details) {
1027 jit_tls = TlsGetValue (mono_jit_tls_id);
1028 jit_tls->class_cast_from = NULL;
1034 if (mono_object_isinst (obj, klass))
1037 if (mini_get_debug_options ()->better_cast_details) {
1038 jit_tls->class_cast_from = obj->vtable->klass;
1039 jit_tls->class_cast_to = klass;
1042 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1043 "System", "InvalidCastException"));
1049 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1051 MonoJitTlsData *jit_tls = NULL;
1052 gpointer cached_vtable, obj_vtable;
1054 if (mini_get_debug_options ()->better_cast_details) {
1055 jit_tls = TlsGetValue (mono_jit_tls_id);
1056 jit_tls->class_cast_from = NULL;
1062 cached_vtable = *cache;
1063 obj_vtable = obj->vtable;
1065 if (cached_vtable == obj_vtable)
1068 if (mono_object_isinst (obj, klass)) {
1069 *cache = obj_vtable;
1073 if (mini_get_debug_options ()->better_cast_details) {
1074 jit_tls->class_cast_from = obj->vtable->klass;
1075 jit_tls->class_cast_to = klass;
1078 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1079 "System", "InvalidCastException"));
1085 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1087 size_t cached_vtable, obj_vtable;
1092 cached_vtable = (size_t)*cache;
1093 obj_vtable = (size_t)obj->vtable;
1095 if ((cached_vtable & ~0x1) == obj_vtable) {
1096 return (cached_vtable & 0x1) ? NULL : obj;
1099 if (mono_object_isinst (obj, klass)) {
1100 *cache = (gpointer)obj_vtable;
1104 *cache = (gpointer)(obj_vtable | 0x1);
1110 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1112 MonoMarshalSpec **mspecs;
1113 MonoMethodPInvoke piinfo;
1116 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1117 memset (&piinfo, 0, sizeof (piinfo));
1119 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1121 return mono_compile_method (m);