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.
13 #include "jit-icalls.h"
16 mono_ldftn (MonoMethod *method)
22 addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
24 return mono_create_ftnptr (mono_domain_get (), addr);
28 * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
29 * synchronized wrappers to avoid infinite recursion.
32 mono_ldftn_nosync (MonoMethod *method)
38 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
40 return mono_create_ftnptr (mono_domain_get (), addr);
44 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
51 mono_raise_exception (mono_get_exception_null_reference ());
53 res = mono_object_get_virtual_method (obj, method);
55 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
56 MonoGenericContext context = { NULL, NULL };
58 if (res->klass->generic_class)
59 context.class_inst = res->klass->generic_class->context.class_inst;
60 else if (res->klass->generic_container)
61 context.class_inst = res->klass->generic_container->context.class_inst;
62 context.method_inst = mono_method_get_context (method)->method_inst;
64 res = mono_class_inflate_generic_method (res, &context);
67 /* FIXME: only do this for methods which can be shared! */
68 if (res->is_inflated && mono_method_get_context (res)->method_inst &&
69 mono_class_generic_sharing_enabled (res->klass)) {
70 res = mono_marshal_get_static_rgctx_invoke (res);
73 return mono_ldftn (res);
77 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
79 return ldvirtfn_internal (obj, method, FALSE);
83 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
85 return ldvirtfn_internal (obj, method, TRUE);
89 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
93 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
94 mono_raise_exception (mono_get_exception_array_type_mismatch ());
97 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
100 mono_llmult (gint64 a, gint64 b)
102 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
107 mono_llmult_ovf_un (guint64 a, guint64 b)
110 guint32 ah = a >> 32;
112 guint32 bh = b >> 32;
117 // fixme: this is incredible slow
120 goto raise_exception;
122 res = (guint64)al * (guint64)bl;
124 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
127 goto raise_exception;
129 res += ((guint64)t1) << 32;
134 mono_raise_exception (mono_get_exception_overflow ());
139 mono_llmult_ovf (gint64 a, gint64 b)
146 Use Karatsuba algorithm where:
147 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
148 where Ah is the "high half" (most significant 32 bits) of a and
149 where Al is the "low half" (least significant 32 bits) of a and
150 where Bh is the "high half" of b and Bl is the "low half" and
151 where R is the Radix or "size of the half" (in our case 32 bits)
153 Note, for the product of two 64 bit numbers to fit into a 64
154 result, ah and/or bh must be 0. This will save us from doing
155 the AhBh term at all.
157 Also note that we refactor so that we don't overflow 64 bits with
158 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
166 /* need to work with absoulte values, so find out what the
167 resulting sign will be and convert any negative numbers
168 from two's complement
172 if (((guint32)ah == 0x80000000) && (al == 0)) {
173 /* This has no two's complement */
179 goto raise_exception;
182 /* flip the bits and add 1 */
193 if (((guint32)bh == 0x80000000) && (bl == 0)) {
194 /* This has no two's complement */
200 goto raise_exception;
203 /* flip the bits and add 1 */
213 /* we overflow for sure if both upper halves are greater
214 than zero because we would need to shift their
215 product 64 bits to the left and that will not fit
216 in a 64 bit result */
218 goto raise_exception;
219 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
220 goto raise_exception;
222 /* do the AlBl term first */
223 t1 = (gint64)al * (gint64)bl;
227 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
228 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
229 /* check for overflow */
231 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
232 goto raise_exception;
237 goto raise_exception;
245 mono_raise_exception (mono_get_exception_overflow ());
249 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
252 mono_idiv (gint32 a, gint32 b)
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
258 mono_raise_exception (mono_get_exception_divide_by_zero ());
259 else if (b == -1 && a == (0x80000000))
260 mono_raise_exception (mono_get_exception_arithmetic ());
266 mono_idiv_un (guint32 a, guint32 b)
270 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 mono_raise_exception (mono_get_exception_divide_by_zero ());
278 mono_irem (gint32 a, gint32 b)
282 #ifdef MONO_ARCH_NEED_DIV_CHECK
284 mono_raise_exception (mono_get_exception_divide_by_zero ());
285 else if (b == -1 && a == (0x80000000))
286 mono_raise_exception (mono_get_exception_arithmetic ());
293 mono_irem_un (guint32 a, guint32 b)
297 #ifdef MONO_ARCH_NEED_DIV_CHECK
299 mono_raise_exception (mono_get_exception_divide_by_zero ());
306 #ifdef MONO_ARCH_EMULATE_MUL_DIV
309 mono_imul (gint32 a, gint32 b)
317 mono_imul_ovf (gint32 a, gint32 b)
323 res = (gint64)a * (gint64)b;
325 if ((res > 0x7fffffffL) || (res < -2147483648))
326 mono_raise_exception (mono_get_exception_overflow ());
332 mono_imul_ovf_un (guint32 a, guint32 b)
338 res = (guint64)a * (guint64)b;
341 mono_raise_exception (mono_get_exception_overflow ());
347 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
349 mono_fdiv (double a, double b)
358 mono_lldiv (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_llrem (gint64 a, gint64 b)
376 #ifdef MONO_ARCH_NEED_DIV_CHECK
378 mono_raise_exception (mono_get_exception_divide_by_zero ());
379 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
380 mono_raise_exception (mono_get_exception_arithmetic ());
386 mono_lldiv_un (guint64 a, guint64 b)
390 #ifdef MONO_ARCH_NEED_DIV_CHECK
392 mono_raise_exception (mono_get_exception_divide_by_zero ());
398 mono_llrem_un (guint64 a, guint64 b)
402 #ifdef MONO_ARCH_NEED_DIV_CHECK
404 mono_raise_exception (mono_get_exception_divide_by_zero ());
411 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
414 mono_lshl (guint64 a, gint32 shamt)
418 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
421 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
427 mono_lshr_un (guint64 a, gint32 shamt)
431 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
434 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
440 mono_lshr (gint64 a, gint32 shamt)
444 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
447 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
454 #ifdef MONO_ARCH_SOFT_FLOAT
457 mono_fsub (double a, double b)
463 mono_fadd (double a, double b)
469 mono_fmul (double a, double b)
481 mono_fconv_r4 (double a)
487 mono_conv_to_r8 (int a)
493 mono_conv_to_r4 (int a)
495 return (double)(float)a;
499 mono_fconv_i1 (double a)
505 mono_fconv_i2 (double a)
511 mono_fconv_i4 (double a)
517 mono_fconv_u1 (double a)
523 mono_fconv_u2 (double a)
529 mono_fcmp_eq (double a, double b)
535 mono_fcmp_ge (double a, double b)
541 mono_fcmp_gt (double a, double b)
547 mono_fcmp_le (double a, double b)
553 mono_fcmp_lt (double a, double b)
559 mono_fcmp_ne_un (double a, double b)
561 return isunordered (a, b) || a != b;
565 mono_fcmp_ge_un (double a, double b)
567 return isunordered (a, b) || a >= b;
571 mono_fcmp_gt_un (double a, double b)
573 return isunordered (a, b) || a > b;
577 mono_fcmp_le_un (double a, double b)
579 return isunordered (a, b) || a <= b;
583 mono_fcmp_lt_un (double a, double b)
585 return isunordered (a, b) || a < b;
589 mono_fceq (double a, double b)
595 mono_fcgt (double a, double b)
601 mono_fcgt_un (double a, double b)
607 mono_fclt (double a, double b)
613 mono_fclt_un (double a, double b)
619 mono_fload_r4 (float *ptr)
625 mono_fstore_r4 (double val, float *ptr)
630 /* returns the integer bitpattern that is passed in the regs or stack */
632 mono_fload_r4_arg (double val)
634 float v = (float)val;
635 return *(guint32*)&v;
641 mono_array_new_va (MonoMethod *cm, ...)
643 MonoDomain *domain = mono_domain_get ();
646 guint32 *lower_bounds;
653 pcount = mono_method_signature (cm)->param_count;
654 rank = cm->klass->rank;
658 lengths = alloca (sizeof (guint32) * pcount);
659 for (i = 0; i < pcount; ++i)
660 lengths [i] = d = va_arg(ap, int);
662 if (rank == pcount) {
663 /* Only lengths provided. */
664 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
665 lower_bounds = alloca (sizeof (guint32) * rank);
666 memset (lower_bounds, 0, sizeof (guint32) * rank);
671 g_assert (pcount == (rank * 2));
672 /* lower bounds are first. */
673 lower_bounds = lengths;
678 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
681 /* Specialized version of mono_array_new_va () which avoids varargs */
683 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
685 MonoDomain *domain = mono_domain_get ();
687 guint32 *lower_bounds;
693 pcount = mono_method_signature (cm)->param_count;
694 rank = cm->klass->rank;
696 lengths [0] = length1;
697 lengths [1] = length2;
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_class_static_field_address (MonoDomain *domain, MonoClassField *field)
719 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
721 mono_class_init (field->parent);
723 vtable = mono_class_vtable (domain, field->parent);
724 if (!vtable->initialized)
725 mono_runtime_class_init (vtable);
727 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
729 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
730 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
732 addr = (char*)vtable->data + field->offset;
738 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
740 MonoClass *handle_class;
744 res = mono_ldtoken (image, token, &handle_class, context);
745 mono_class_init (handle_class);
751 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
753 MonoMethodSignature *sig = mono_method_signature (method);
754 MonoGenericContext *generic_context;
756 if (sig->is_inflated) {
757 generic_context = mono_method_get_context (method);
759 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
760 g_assert (generic_container);
761 generic_context = &generic_container->context;
764 return mono_ldtoken_wrapper (image, token, generic_context);
768 mono_fconv_u8 (double v)
773 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
775 mono_fconv_i8 (double v)
777 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
783 mono_fconv_u4 (double v)
785 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
790 /* Solaris doesn't have trunc */
792 extern long double aintl (long double);
795 /* FIXME: This means we will never throw overflow exceptions */
798 #endif /* HAVE_TRUNC */
801 mono_fconv_ovf_i8 (double v)
809 if (isnan(v) || trunc (v) != res) {
810 mono_raise_exception (mono_get_exception_overflow ());
816 mono_fconv_ovf_u8 (double v)
824 if (isnan(v) || trunc (v) != res) {
825 mono_raise_exception (mono_get_exception_overflow ());
830 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
832 mono_lconv_to_r8 (gint64 a)
838 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
840 mono_lconv_to_r4 (gint64 a)
846 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
848 mono_conv_to_r8_un (guint32 a)
854 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
856 mono_lconv_to_r8_un (guint64 a)
863 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
865 MonoMethod *vmethod, *inflated;
868 mono_jit_stats.generic_virtual_invocations++;
871 mono_raise_exception (mono_get_exception_null_reference ());
872 vmethod = mono_object_get_virtual_method (obj, method);
874 /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the
875 declaring class have been inflated. We still need to fully inflate the method parameters.
877 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
880 g_assert (!vmethod->klass->generic_container);
881 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
882 g_assert (!context->method_inst || !context->method_inst->is_open);
883 inflated = mono_class_inflate_generic_method (vmethod, context);
884 if (mono_class_generic_sharing_enabled (inflated->klass) &&
885 mono_method_is_generic_sharable_impl (method, FALSE)) {
886 /* The method is shared generic code, so it needs a
888 inflated = mono_marshal_get_static_rgctx_invoke (inflated);
890 addr = mono_compile_method (inflated);
892 /* Since this is a virtual call, have to unbox vtypes */
893 if (obj->vtable->klass->valuetype)
894 *this_arg = mono_object_unbox (obj);
902 mono_helper_compile_generic_method_wo_context (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
904 MonoGenericContext *context = mono_method_get_context (method);
906 return mono_helper_compile_generic_method (obj, method, context, this_arg);
910 mono_helper_ldstr (MonoImage *image, guint32 idx)
912 return mono_ldstr (mono_domain_get (), image, idx);
916 mono_helper_ldstr_mscorlib (guint32 idx)
918 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
922 mono_helper_newobj_mscorlib (guint32 idx)
924 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
928 return mono_object_new (mono_domain_get (), klass);
932 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
933 * in generated code. So instead we emit a call to this function and place a gdb
942 mono_create_corlib_exception_0 (guint32 token)
944 return mono_exception_from_token (mono_defaults.corlib, token);
948 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
950 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
954 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
956 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);