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
)
77 if (val
&& !mono_object_isinst (val
, array
->obj
.vtable
->klass
->element_class
))
78 mono_raise_exception (mono_get_exception_array_type_mismatch ());
81 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
84 mono_llmult (gint64 a
, gint64 b
)
86 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
91 mono_llmult_ovf_un (guint64 a
, guint64 b
)
101 // fixme: this is incredible slow
104 goto raise_exception
;
106 res
= (guint64
)al
* (guint64
)bl
;
108 t1
= (guint64
)ah
* (guint64
)bl
+ (guint64
)al
* (guint64
)bh
;
111 goto raise_exception
;
113 res
+= ((guint64
)t1
) << 32;
118 mono_raise_exception (mono_get_exception_overflow ());
123 mono_llmult_ovf (gint64 a
, gint64 b
)
130 Use Karatsuba algorithm where:
131 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
132 where Ah is the "high half" (most significant 32 bits) of a and
133 where Al is the "low half" (least significant 32 bits) of a and
134 where Bh is the "high half" of b and Bl is the "low half" and
135 where R is the Radix or "size of the half" (in our case 32 bits)
137 Note, for the product of two 64 bit numbers to fit into a 64
138 result, ah and/or bh must be 0. This will save us from doing
139 the AhBh term at all.
141 Also note that we refactor so that we don't overflow 64 bits with
142 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
150 /* need to work with absoulte values, so find out what the
151 resulting sign will be and convert any negative numbers
152 from two's complement
156 if (((guint32
)ah
== 0x80000000) && (al
== 0)) {
157 /* This has no two's complement */
163 goto raise_exception
;
166 /* flip the bits and add 1 */
177 if (((guint32
)bh
== 0x80000000) && (bl
== 0)) {
178 /* This has no two's complement */
184 goto raise_exception
;
187 /* flip the bits and add 1 */
197 /* we overflow for sure if both upper halves are greater
198 than zero because we would need to shift their
199 product 64 bits to the left and that will not fit
200 in a 64 bit result */
202 goto raise_exception
;
203 if ((gint64
)((gint64
)ah
* (gint64
)bl
) > (gint64
)0x80000000 || (gint64
)((gint64
)al
* (gint64
)bh
) > (gint64
)0x80000000)
204 goto raise_exception
;
206 /* do the AlBl term first */
207 t1
= (gint64
)al
* (gint64
)bl
;
211 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
212 t1
+= (gint64
)(ah
- al
) * (gint64
)(bl
- bh
);
213 /* check for overflow */
215 if (t1
> (0x7FFFFFFFFFFFFFFFLL
- res
))
216 goto raise_exception
;
221 goto raise_exception
;
229 mono_raise_exception (mono_get_exception_overflow ());
233 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
236 mono_idiv (gint32 a
, gint32 b
)
240 #ifdef MONO_ARCH_NEED_DIV_CHECK
242 mono_raise_exception (mono_get_exception_divide_by_zero ());
243 else if (b
== -1 && a
== (0x80000000))
244 mono_raise_exception (mono_get_exception_arithmetic ());
250 mono_idiv_un (guint32 a
, guint32 b
)
254 #ifdef MONO_ARCH_NEED_DIV_CHECK
256 mono_raise_exception (mono_get_exception_divide_by_zero ());
262 mono_irem (gint32 a
, gint32 b
)
266 #ifdef MONO_ARCH_NEED_DIV_CHECK
268 mono_raise_exception (mono_get_exception_divide_by_zero ());
269 else if (b
== -1 && a
== (0x80000000))
270 mono_raise_exception (mono_get_exception_arithmetic ());
277 mono_irem_un (guint32 a
, guint32 b
)
281 #ifdef MONO_ARCH_NEED_DIV_CHECK
283 mono_raise_exception (mono_get_exception_divide_by_zero ());
290 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
293 mono_imul (gint32 a
, gint32 b
)
301 mono_imul_ovf (gint32 a
, gint32 b
)
307 res
= (gint64
)a
* (gint64
)b
;
309 if ((res
> 0x7fffffffL
) || (res
< -2147483648LL))
310 mono_raise_exception (mono_get_exception_overflow ());
316 mono_imul_ovf_un (guint32 a
, guint32 b
)
322 res
= (guint64
)a
* (guint64
)b
;
325 mono_raise_exception (mono_get_exception_overflow ());
331 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
333 mono_fdiv (double a
, double b
)
342 mono_lldiv (gint64 a
, gint64 b
)
346 #ifdef MONO_ARCH_NEED_DIV_CHECK
348 mono_raise_exception (mono_get_exception_divide_by_zero ());
349 else if (b
== -1 && a
== (-9223372036854775807LL - 1LL))
350 mono_raise_exception (mono_get_exception_arithmetic ());
356 mono_llrem (gint64 a
, gint64 b
)
360 #ifdef MONO_ARCH_NEED_DIV_CHECK
362 mono_raise_exception (mono_get_exception_divide_by_zero ());
363 else if (b
== -1 && a
== (-9223372036854775807LL - 1LL))
364 mono_raise_exception (mono_get_exception_arithmetic ());
370 mono_lldiv_un (guint64 a
, guint64 b
)
374 #ifdef MONO_ARCH_NEED_DIV_CHECK
376 mono_raise_exception (mono_get_exception_divide_by_zero ());
382 mono_llrem_un (guint64 a
, guint64 b
)
386 #ifdef MONO_ARCH_NEED_DIV_CHECK
388 mono_raise_exception (mono_get_exception_divide_by_zero ());
395 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
398 mono_lshl (guint64 a
, gint32 shamt
)
402 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
405 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
411 mono_lshr_un (guint64 a
, gint32 shamt
)
415 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
418 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
424 mono_lshr (gint64 a
, gint32 shamt
)
428 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
431 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
438 #ifdef MONO_ARCH_SOFT_FLOAT
441 mono_fsub (double a
, double b
)
447 mono_fadd (double a
, double b
)
453 mono_fmul (double a
, double b
)
465 mono_fconv_r4 (double a
)
471 mono_conv_to_r8 (int a
)
477 mono_conv_to_r4 (int a
)
479 return (double)(float)a
;
483 mono_fconv_i1 (double a
)
489 mono_fconv_i2 (double a
)
495 mono_fconv_i4 (double a
)
501 mono_fconv_u1 (double a
)
507 mono_fconv_u2 (double a
)
513 mono_fcmp_eq (double a
, double b
)
519 mono_fcmp_ge (double a
, double b
)
525 mono_fcmp_gt (double a
, double b
)
531 mono_fcmp_le (double a
, double b
)
537 mono_fcmp_lt (double a
, double b
)
543 mono_fcmp_ne_un (double a
, double b
)
545 return isunordered (a
, b
) || a
!= b
;
549 mono_fcmp_ge_un (double a
, double b
)
551 return isunordered (a
, b
) || a
>= b
;
555 mono_fcmp_gt_un (double a
, double b
)
557 return isunordered (a
, b
) || a
> b
;
561 mono_fcmp_le_un (double a
, double b
)
563 return isunordered (a
, b
) || a
<= b
;
567 mono_fcmp_lt_un (double a
, double b
)
569 return isunordered (a
, b
) || a
< b
;
573 mono_fceq (double a
, double b
)
579 mono_fcgt (double a
, double b
)
585 mono_fcgt_un (double a
, double b
)
587 return isunordered (a
, b
) || a
> b
;
591 mono_fclt (double a
, double b
)
597 mono_fclt_un (double a
, double b
)
599 return isunordered (a
, b
) || a
< b
;
603 mono_isfinite (double a
)
608 g_assert_not_reached ();
614 mono_fload_r4 (float *ptr
)
620 mono_fstore_r4 (double val
, float *ptr
)
625 /* returns the integer bitpattern that is passed in the regs or stack */
627 mono_fload_r4_arg (double val
)
629 float v
= (float)val
;
630 return *(guint32
*)&v
;
636 mono_array_new_va (MonoMethod
*cm
, ...)
638 MonoDomain
*domain
= mono_domain_get ();
641 intptr_t *lower_bounds
;
648 pcount
= mono_method_signature (cm
)->param_count
;
649 rank
= cm
->klass
->rank
;
653 lengths
= alloca (sizeof (uintptr_t) * pcount
);
654 for (i
= 0; i
< pcount
; ++i
)
655 lengths
[i
] = d
= va_arg(ap
, int);
657 if (rank
== pcount
) {
658 /* Only lengths provided. */
659 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
660 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
661 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
666 g_assert (pcount
== (rank
* 2));
667 /* lower bounds are first. */
668 lower_bounds
= (intptr_t*)lengths
;
673 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
676 /* Specialized version of mono_array_new_va () which avoids varargs */
678 mono_array_new_1 (MonoMethod
*cm
, guint32 length
)
680 MonoDomain
*domain
= mono_domain_get ();
681 uintptr_t lengths
[1];
682 intptr_t *lower_bounds
;
688 pcount
= mono_method_signature (cm
)->param_count
;
689 rank
= cm
->klass
->rank
;
691 lengths
[0] = length
;
693 g_assert (rank
== pcount
);
695 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
696 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
697 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
702 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
706 mono_array_new_2 (MonoMethod
*cm
, guint32 length1
, guint32 length2
)
708 MonoDomain
*domain
= mono_domain_get ();
709 uintptr_t lengths
[2];
710 intptr_t *lower_bounds
;
716 pcount
= mono_method_signature (cm
)->param_count
;
717 rank
= cm
->klass
->rank
;
719 lengths
[0] = length1
;
720 lengths
[1] = length2
;
722 g_assert (rank
== pcount
);
724 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
725 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
726 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
731 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
735 mono_array_new_3 (MonoMethod
*cm
, guint32 length1
, guint32 length2
, guint32 length3
)
737 MonoDomain
*domain
= mono_domain_get ();
738 uintptr_t lengths
[3];
739 intptr_t *lower_bounds
;
745 pcount
= mono_method_signature (cm
)->param_count
;
746 rank
= cm
->klass
->rank
;
748 lengths
[0] = length1
;
749 lengths
[1] = length2
;
750 lengths
[2] = length3
;
752 g_assert (rank
== pcount
);
754 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
755 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
756 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
761 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
765 mono_class_static_field_address (MonoDomain
*domain
, MonoClassField
*field
)
772 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
774 mono_class_init (field
->parent
);
776 vtable
= mono_class_vtable_full (domain
, field
->parent
, TRUE
);
777 if (!vtable
->initialized
)
778 mono_runtime_class_init (vtable
);
780 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
782 if (domain
->special_static_fields
&& (addr
= g_hash_table_lookup (domain
->special_static_fields
, field
)))
783 addr
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
785 addr
= (char*)vtable
->data
+ field
->offset
;
791 mono_ldtoken_wrapper (MonoImage
*image
, int token
, MonoGenericContext
*context
)
793 MonoClass
*handle_class
;
797 res
= mono_ldtoken (image
, token
, &handle_class
, context
);
798 mono_class_init (handle_class
);
804 mono_ldtoken_wrapper_generic_shared (MonoImage
*image
, int token
, MonoMethod
*method
)
806 MonoMethodSignature
*sig
= mono_method_signature (method
);
807 MonoGenericContext
*generic_context
;
809 if (sig
->is_inflated
) {
810 generic_context
= mono_method_get_context (method
);
812 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
813 g_assert (generic_container
);
814 generic_context
= &generic_container
->context
;
817 return mono_ldtoken_wrapper (image
, token
, generic_context
);
821 mono_fconv_u8 (double v
)
826 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
828 mono_fconv_i8 (double v
)
830 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
836 mono_fconv_u4 (double v
)
838 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
843 /* Solaris doesn't have trunc */
845 extern long double aintl (long double);
848 /* FIXME: This means we will never throw overflow exceptions */
851 #endif /* HAVE_TRUNC */
854 mono_fconv_ovf_i8 (double v
)
862 if (isnan(v
) || trunc (v
) != res
) {
863 mono_raise_exception (mono_get_exception_overflow ());
869 mono_fconv_ovf_u8 (double v
)
875 * The soft-float implementation of some ARM devices have a buggy guin64 to double
876 * conversion that it looses precision even when the integer if fully representable
879 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
881 * To work around this issue we test for value boundaries instead.
883 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
884 if (isnan (v
) || !(v
>= -0.5 && v
<= ULLONG_MAX
+0.5)) {
885 mono_raise_exception (mono_get_exception_overflow ());
890 if (isnan(v
) || trunc (v
) != res
) {
891 mono_raise_exception (mono_get_exception_overflow ());
897 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
899 mono_lconv_to_r8 (gint64 a
)
905 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
907 mono_lconv_to_r4 (gint64 a
)
913 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
915 mono_conv_to_r8_un (guint32 a
)
921 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
923 mono_lconv_to_r8_un (guint64 a
)
930 mono_helper_compile_generic_method (MonoObject
*obj
, MonoMethod
*method
, gpointer
*this_arg
)
934 MonoGenericContext
*context
= mono_method_get_context (method
);
936 mono_jit_stats
.generic_virtual_invocations
++;
939 mono_raise_exception (mono_get_exception_null_reference ());
940 vmethod
= mono_object_get_virtual_method (obj
, method
);
941 g_assert (!vmethod
->klass
->generic_container
);
942 g_assert (!vmethod
->klass
->generic_class
|| !vmethod
->klass
->generic_class
->context
.class_inst
->is_open
);
943 g_assert (!context
->method_inst
|| !context
->method_inst
->is_open
);
945 addr
= mono_compile_method (vmethod
);
947 if (mono_method_needs_static_rgctx_invoke (vmethod
, FALSE
))
948 addr
= mono_create_static_rgctx_trampoline (vmethod
, addr
);
950 /* Since this is a virtual call, have to unbox vtypes */
951 if (obj
->vtable
->klass
->valuetype
)
952 *this_arg
= mono_object_unbox (obj
);
960 mono_helper_ldstr (MonoImage
*image
, guint32 idx
)
962 return mono_ldstr (mono_domain_get (), image
, idx
);
966 mono_helper_ldstr_mscorlib (guint32 idx
)
968 return mono_ldstr (mono_domain_get (), mono_defaults
.corlib
, idx
);
972 mono_helper_newobj_mscorlib (guint32 idx
)
974 MonoClass
*klass
= mono_class_get (mono_defaults
.corlib
, MONO_TOKEN_TYPE_DEF
| idx
);
978 return mono_object_new (mono_domain_get (), klass
);
982 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
983 * in generated code. So instead we emit a call to this function and place a gdb
992 mono_create_corlib_exception_0 (guint32 token
)
994 return mono_exception_from_token (mono_defaults
.corlib
, token
);
998 mono_create_corlib_exception_1 (guint32 token
, MonoString
*arg
)
1000 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg
, NULL
);
1004 mono_create_corlib_exception_2 (guint32 token
, MonoString
*arg1
, MonoString
*arg2
)
1006 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg1
, arg2
);
1010 mono_object_castclass (MonoObject
*obj
, MonoClass
*klass
)
1015 if (mono_object_isinst (obj
, klass
))
1018 mono_raise_exception (mono_exception_from_name (mono_defaults
.corlib
,
1019 "System", "InvalidCastException"));
1025 mono_get_native_calli_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
, gpointer func
)
1027 MonoMarshalSpec
**mspecs
;
1028 MonoMethodPInvoke piinfo
;
1031 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
1032 memset (&piinfo
, 0, sizeof (piinfo
));
1034 m
= mono_marshal_get_native_func_wrapper (image
, sig
, &piinfo
, mspecs
, func
);
1036 return mono_compile_method (m
);