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 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
49 mono_raise_exception (mono_get_exception_null_reference ());
51 method = mono_object_get_virtual_method (obj, method);
53 return mono_ldftn (method);
57 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
61 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
62 mono_raise_exception (mono_get_exception_array_type_mismatch ());
65 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
68 mono_llmult (gint64 a, gint64 b)
70 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
75 mono_llmult_ovf_un (guint64 a, guint64 b)
85 // fixme: this is incredible slow
90 res = (guint64)al * (guint64)bl;
92 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
97 res += ((guint64)t1) << 32;
102 mono_raise_exception (mono_get_exception_overflow ());
107 mono_llmult_ovf (gint64 a, gint64 b)
114 Use Karatsuba algorithm where:
115 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
116 where Ah is the "high half" (most significant 32 bits) of a and
117 where Al is the "low half" (least significant 32 bits) of a and
118 where Bh is the "high half" of b and Bl is the "low half" and
119 where R is the Radix or "size of the half" (in our case 32 bits)
121 Note, for the product of two 64 bit numbers to fit into a 64
122 result, ah and/or bh must be 0. This will save us from doing
123 the AhBh term at all.
125 Also note that we refactor so that we don't overflow 64 bits with
126 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
134 /* need to work with absoulte values, so find out what the
135 resulting sign will be and convert any negative numbers
136 from two's complement
140 if (((guint32)ah == 0x80000000) && (al == 0)) {
141 /* This has no two's complement */
147 goto raise_exception;
150 /* flip the bits and add 1 */
161 if (((guint32)bh == 0x80000000) && (bl == 0)) {
162 /* This has no two's complement */
168 goto raise_exception;
171 /* flip the bits and add 1 */
181 /* we overflow for sure if both upper halves are greater
182 than zero because we would need to shift their
183 product 64 bits to the left and that will not fit
184 in a 64 bit result */
186 goto raise_exception;
187 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
188 goto raise_exception;
190 /* do the AlBl term first */
191 t1 = (gint64)al * (gint64)bl;
195 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
196 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
197 /* check for overflow */
199 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
200 goto raise_exception;
205 goto raise_exception;
213 mono_raise_exception (mono_get_exception_overflow ());
217 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
220 mono_idiv (gint32 a, gint32 b)
224 #ifdef MONO_ARCH_NEED_DIV_CHECK
226 mono_raise_exception (mono_get_exception_divide_by_zero ());
227 else if (b == -1 && a == (0x80000000))
228 mono_raise_exception (mono_get_exception_arithmetic ());
234 mono_idiv_un (guint32 a, guint32 b)
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
240 mono_raise_exception (mono_get_exception_divide_by_zero ());
246 mono_irem (gint32 a, gint32 b)
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
252 mono_raise_exception (mono_get_exception_divide_by_zero ());
253 else if (b == -1 && a == (0x80000000))
254 mono_raise_exception (mono_get_exception_arithmetic ());
261 mono_irem_un (guint32 a, guint32 b)
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
267 mono_raise_exception (mono_get_exception_divide_by_zero ());
274 #ifdef MONO_ARCH_EMULATE_MUL_DIV
277 mono_imul (gint32 a, gint32 b)
285 mono_imul_ovf (gint32 a, gint32 b)
291 res = (gint64)a * (gint64)b;
293 if ((res > 0x7fffffffL) || (res < -2147483648))
294 mono_raise_exception (mono_get_exception_overflow ());
300 mono_imul_ovf_un (guint32 a, guint32 b)
306 res = (guint64)a * (guint64)b;
309 mono_raise_exception (mono_get_exception_overflow ());
315 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
317 mono_fdiv (double a, double b)
326 mono_lldiv (gint64 a, gint64 b)
330 #ifdef MONO_ARCH_NEED_DIV_CHECK
332 mono_raise_exception (mono_get_exception_divide_by_zero ());
333 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
334 mono_raise_exception (mono_get_exception_arithmetic ());
340 mono_llrem (gint64 a, gint64 b)
344 #ifdef MONO_ARCH_NEED_DIV_CHECK
346 mono_raise_exception (mono_get_exception_divide_by_zero ());
347 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
348 mono_raise_exception (mono_get_exception_arithmetic ());
354 mono_lldiv_un (guint64 a, guint64 b)
358 #ifdef MONO_ARCH_NEED_DIV_CHECK
360 mono_raise_exception (mono_get_exception_divide_by_zero ());
366 mono_llrem_un (guint64 a, guint64 b)
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
372 mono_raise_exception (mono_get_exception_divide_by_zero ());
379 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
382 mono_lshl (guint64 a, gint32 shamt)
386 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
389 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
395 mono_lshr_un (guint64 a, gint32 shamt)
399 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
402 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
408 mono_lshr (gint64 a, gint32 shamt)
412 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
415 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
422 #ifdef MONO_ARCH_SOFT_FLOAT
425 mono_fsub (double a, double b)
431 mono_fadd (double a, double b)
437 mono_fmul (double a, double b)
449 mono_fconv_r4 (double a)
455 mono_conv_to_r8 (int a)
461 mono_conv_to_r4 (int a)
463 return (double)(float)a;
467 mono_fconv_i1 (double a)
473 mono_fconv_i2 (double a)
479 mono_fconv_i4 (double a)
485 mono_fconv_u1 (double a)
491 mono_fconv_u2 (double a)
497 mono_fcmp_eq (double a, double b)
503 mono_fcmp_ge (double a, double b)
509 mono_fcmp_gt (double a, double b)
515 mono_fcmp_le (double a, double b)
521 mono_fcmp_lt (double a, double b)
527 mono_fcmp_ne_un (double a, double b)
529 return isunordered (a, b) || a != b;
533 mono_fcmp_ge_un (double a, double b)
535 return isunordered (a, b) || a >= b;
539 mono_fcmp_gt_un (double a, double b)
541 return isunordered (a, b) || a > b;
545 mono_fcmp_le_un (double a, double b)
547 return isunordered (a, b) || a <= b;
551 mono_fcmp_lt_un (double a, double b)
553 return isunordered (a, b) || a < b;
557 mono_fceq (double a, double b)
563 mono_fcgt (double a, double b)
569 mono_fcgt_un (double a, double b)
575 mono_fclt (double a, double b)
581 mono_fclt_un (double a, double b)
587 mono_fload_r4 (float *ptr)
593 mono_fstore_r4 (double val, float *ptr)
598 /* returns the integer bitpattern that is passed in the regs or stack */
600 mono_fload_r4_arg (double val)
602 float v = (float)val;
603 return *(guint32*)&v;
609 mono_array_new_va (MonoMethod *cm, ...)
611 MonoDomain *domain = mono_domain_get ();
614 guint32 *lower_bounds;
621 pcount = mono_method_signature (cm)->param_count;
622 rank = cm->klass->rank;
626 lengths = alloca (sizeof (guint32) * pcount);
627 for (i = 0; i < pcount; ++i)
628 lengths [i] = d = va_arg(ap, int);
630 if (rank == pcount) {
631 /* Only lengths provided. */
632 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
633 lower_bounds = alloca (sizeof (guint32) * rank);
634 memset (lower_bounds, 0, sizeof (guint32) * rank);
639 g_assert (pcount == (rank * 2));
640 /* lower bounds are first. */
641 lower_bounds = lengths;
646 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
650 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
657 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
659 mono_class_init (field->parent);
661 vtable = mono_class_vtable (domain, field->parent);
662 if (!vtable->initialized)
663 mono_runtime_class_init (vtable);
665 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
667 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
668 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
670 addr = (char*)vtable->data + field->offset;
676 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
678 MonoClass *handle_class;
682 res = mono_ldtoken (image, token, &handle_class, context);
683 mono_class_init (handle_class);
689 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
691 MonoMethodSignature *sig = mono_method_signature (method);
692 MonoGenericContext *generic_context;
694 if (sig->is_inflated) {
695 generic_context = mono_method_get_context (method);
697 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
698 g_assert (generic_container);
699 generic_context = &generic_container->context;
702 return mono_ldtoken_wrapper (image, token, generic_context);
706 mono_fconv_u8 (double v)
711 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
713 mono_fconv_i8 (double v)
715 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
721 mono_fconv_u4 (double v)
723 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
728 /* Solaris doesn't have trunc */
730 extern long double aintl (long double);
733 /* FIXME: This means we will never throw overflow exceptions */
736 #endif /* HAVE_TRUNC */
739 mono_fconv_ovf_i8 (double v)
747 if (isnan(v) || trunc (v) != res) {
748 mono_raise_exception (mono_get_exception_overflow ());
754 mono_fconv_ovf_u8 (double v)
762 if (isnan(v) || trunc (v) != res) {
763 mono_raise_exception (mono_get_exception_overflow ());
768 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
770 mono_lconv_to_r8 (gint64 a)
776 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
778 mono_lconv_to_r4 (gint64 a)
784 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
786 mono_conv_to_r8_un (guint32 a)
792 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
794 mono_lconv_to_r8_un (guint64 a)
801 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
803 MonoMethod *vmethod, *inflated;
806 mono_jit_stats.generic_virtual_invocations++;
809 mono_raise_exception (mono_get_exception_null_reference ());
810 vmethod = mono_object_get_virtual_method (obj, method);
812 /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the
813 declaring class have been inflated. We still need to fully inflate the method parameters.
815 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
818 g_assert (!vmethod->klass->generic_container);
819 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
820 g_assert (!context->method_inst || !context->method_inst->is_open);
821 inflated = mono_class_inflate_generic_method (vmethod, context);
822 addr = mono_compile_method (inflated);
824 /* Since this is a virtual call, have to unbox vtypes */
825 if (obj->vtable->klass->valuetype)
826 *this_arg = mono_object_unbox (obj);
834 mono_helper_ldstr (MonoImage *image, guint32 idx)
836 return mono_ldstr (mono_domain_get (), image, idx);
840 mono_helper_ldstr_mscorlib (guint32 idx)
842 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
846 mono_helper_newobj_mscorlib (guint32 idx)
848 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
852 return mono_object_new (mono_domain_get (), klass);
856 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
857 * in generated code. So instead we emit a call to this function and place a gdb
866 mono_create_corlib_exception_0 (guint32 token)
868 return mono_exception_from_token (mono_defaults.corlib, token);
872 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
874 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
878 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
880 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);