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.
9 * Copyright 2003-2011 Novell Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
19 #include "jit-icalls.h"
22 mono_ldftn (MonoMethod
*method
)
28 addr
= mono_create_jump_trampoline (mono_domain_get (), method
, FALSE
);
30 return mono_create_ftnptr (mono_domain_get (), addr
);
34 ldvirtfn_internal (MonoObject
*obj
, MonoMethod
*method
, gboolean gshared
)
41 mono_raise_exception (mono_get_exception_null_reference ());
43 res
= mono_object_get_virtual_method (obj
, method
);
45 if (gshared
&& method
->is_inflated
&& mono_method_get_context (method
)->method_inst
) {
46 MonoGenericContext context
= { NULL
, NULL
};
48 if (res
->klass
->generic_class
)
49 context
.class_inst
= res
->klass
->generic_class
->context
.class_inst
;
50 else if (res
->klass
->generic_container
)
51 context
.class_inst
= res
->klass
->generic_container
->context
.class_inst
;
52 context
.method_inst
= mono_method_get_context (method
)->method_inst
;
54 res
= mono_class_inflate_generic_method (res
, &context
);
57 /* An rgctx wrapper is added by the trampolines no need to do it here */
59 return mono_ldftn (res
);
63 mono_ldvirtfn (MonoObject
*obj
, MonoMethod
*method
)
65 return ldvirtfn_internal (obj
, method
, FALSE
);
69 mono_ldvirtfn_gshared (MonoObject
*obj
, MonoMethod
*method
)
71 return ldvirtfn_internal (obj
, method
, TRUE
);
75 mono_helper_stelem_ref_check (MonoArray
*array
, MonoObject
*val
)
80 mono_raise_exception (mono_get_exception_null_reference ());
81 if (val
&& !mono_object_isinst (val
, array
->obj
.vtable
->klass
->element_class
))
82 mono_raise_exception (mono_get_exception_array_type_mismatch ());
85 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
88 mono_llmult (gint64 a
, gint64 b
)
90 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
95 mono_llmult_ovf_un (guint64 a
, guint64 b
)
100 guint32 bh
= b
>> 32;
105 // fixme: this is incredible slow
108 goto raise_exception
;
110 res
= (guint64
)al
* (guint64
)bl
;
112 t1
= (guint64
)ah
* (guint64
)bl
+ (guint64
)al
* (guint64
)bh
;
115 goto raise_exception
;
117 res
+= ((guint64
)t1
) << 32;
122 mono_raise_exception (mono_get_exception_overflow ());
127 mono_llmult_ovf (gint64 a
, gint64 b
)
134 Use Karatsuba algorithm where:
135 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
136 where Ah is the "high half" (most significant 32 bits) of a and
137 where Al is the "low half" (least significant 32 bits) of a and
138 where Bh is the "high half" of b and Bl is the "low half" and
139 where R is the Radix or "size of the half" (in our case 32 bits)
141 Note, for the product of two 64 bit numbers to fit into a 64
142 result, ah and/or bh must be 0. This will save us from doing
143 the AhBh term at all.
145 Also note that we refactor so that we don't overflow 64 bits with
146 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
154 /* need to work with absoulte values, so find out what the
155 resulting sign will be and convert any negative numbers
156 from two's complement
160 if (((guint32
)ah
== 0x80000000) && (al
== 0)) {
161 /* This has no two's complement */
167 goto raise_exception
;
170 /* flip the bits and add 1 */
181 if (((guint32
)bh
== 0x80000000) && (bl
== 0)) {
182 /* This has no two's complement */
188 goto raise_exception
;
191 /* flip the bits and add 1 */
201 /* we overflow for sure if both upper halves are greater
202 than zero because we would need to shift their
203 product 64 bits to the left and that will not fit
204 in a 64 bit result */
206 goto raise_exception
;
207 if ((gint64
)((gint64
)ah
* (gint64
)bl
) > (gint64
)0x80000000 || (gint64
)((gint64
)al
* (gint64
)bh
) > (gint64
)0x80000000)
208 goto raise_exception
;
210 /* do the AlBl term first */
211 t1
= (gint64
)al
* (gint64
)bl
;
215 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
216 t1
+= (gint64
)(ah
- al
) * (gint64
)(bl
- bh
);
217 /* check for overflow */
219 if (t1
> (0x7FFFFFFFFFFFFFFFLL
- res
))
220 goto raise_exception
;
225 goto raise_exception
;
233 mono_raise_exception (mono_get_exception_overflow ());
237 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
240 mono_idiv (gint32 a
, gint32 b
)
244 #ifdef MONO_ARCH_NEED_DIV_CHECK
246 mono_raise_exception (mono_get_exception_divide_by_zero ());
247 else if (b
== -1 && a
== (0x80000000))
248 mono_raise_exception (mono_get_exception_overflow ());
254 mono_idiv_un (guint32 a
, guint32 b
)
258 #ifdef MONO_ARCH_NEED_DIV_CHECK
260 mono_raise_exception (mono_get_exception_divide_by_zero ());
266 mono_irem (gint32 a
, gint32 b
)
270 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 mono_raise_exception (mono_get_exception_divide_by_zero ());
273 else if (b
== -1 && a
== (0x80000000))
274 mono_raise_exception (mono_get_exception_overflow ());
281 mono_irem_un (guint32 a
, guint32 b
)
285 #ifdef MONO_ARCH_NEED_DIV_CHECK
287 mono_raise_exception (mono_get_exception_divide_by_zero ());
294 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
297 mono_imul (gint32 a
, gint32 b
)
305 mono_imul_ovf (gint32 a
, gint32 b
)
311 res
= (gint64
)a
* (gint64
)b
;
313 if ((res
> 0x7fffffffL
) || (res
< -2147483648LL))
314 mono_raise_exception (mono_get_exception_overflow ());
320 mono_imul_ovf_un (guint32 a
, guint32 b
)
326 res
= (guint64
)a
* (guint64
)b
;
329 mono_raise_exception (mono_get_exception_overflow ());
335 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
337 mono_fdiv (double a
, double b
)
346 mono_lldiv (gint64 a
, gint64 b
)
350 #ifdef MONO_ARCH_NEED_DIV_CHECK
352 mono_raise_exception (mono_get_exception_divide_by_zero ());
353 else if (b
== -1 && a
== (-9223372036854775807LL - 1LL))
354 mono_raise_exception (mono_get_exception_arithmetic ());
360 mono_llrem (gint64 a
, gint64 b
)
364 #ifdef MONO_ARCH_NEED_DIV_CHECK
366 mono_raise_exception (mono_get_exception_divide_by_zero ());
367 else if (b
== -1 && a
== (-9223372036854775807LL - 1LL))
368 mono_raise_exception (mono_get_exception_arithmetic ());
374 mono_lldiv_un (guint64 a
, guint64 b
)
378 #ifdef MONO_ARCH_NEED_DIV_CHECK
380 mono_raise_exception (mono_get_exception_divide_by_zero ());
386 mono_llrem_un (guint64 a
, guint64 b
)
390 #ifdef MONO_ARCH_NEED_DIV_CHECK
392 mono_raise_exception (mono_get_exception_divide_by_zero ());
399 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
402 mono_lshl (guint64 a
, gint32 shamt
)
406 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
409 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
415 mono_lshr_un (guint64 a
, gint32 shamt
)
419 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
422 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
428 mono_lshr (gint64 a
, gint32 shamt
)
432 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
435 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
442 #ifdef MONO_ARCH_SOFT_FLOAT
445 mono_fsub (double a
, double b
)
451 mono_fadd (double a
, double b
)
457 mono_fmul (double a
, double b
)
469 mono_fconv_r4 (double a
)
475 mono_conv_to_r8 (int a
)
481 mono_conv_to_r4 (int a
)
483 return (double)(float)a
;
487 mono_fconv_i1 (double a
)
493 mono_fconv_i2 (double a
)
499 mono_fconv_i4 (double a
)
505 mono_fconv_u1 (double a
)
511 mono_fconv_u2 (double a
)
517 mono_fcmp_eq (double a
, double b
)
523 mono_fcmp_ge (double a
, double b
)
529 mono_fcmp_gt (double a
, double b
)
535 mono_fcmp_le (double a
, double b
)
541 mono_fcmp_lt (double a
, double b
)
547 mono_fcmp_ne_un (double a
, double b
)
549 return isunordered (a
, b
) || a
!= b
;
553 mono_fcmp_ge_un (double a
, double b
)
555 return isunordered (a
, b
) || a
>= b
;
559 mono_fcmp_gt_un (double a
, double b
)
561 return isunordered (a
, b
) || a
> b
;
565 mono_fcmp_le_un (double a
, double b
)
567 return isunordered (a
, b
) || a
<= b
;
571 mono_fcmp_lt_un (double a
, double b
)
573 return isunordered (a
, b
) || a
< b
;
577 mono_fceq (double a
, double b
)
583 mono_fcgt (double a
, double b
)
589 mono_fcgt_un (double a
, double b
)
591 return isunordered (a
, b
) || a
> b
;
595 mono_fclt (double a
, double b
)
601 mono_fclt_un (double a
, double b
)
603 return isunordered (a
, b
) || a
< b
;
607 mono_isfinite (double a
)
612 g_assert_not_reached ();
618 mono_fload_r4 (float *ptr
)
624 mono_fstore_r4 (double val
, float *ptr
)
629 /* returns the integer bitpattern that is passed in the regs or stack */
631 mono_fload_r4_arg (double val
)
633 float v
= (float)val
;
634 return *(guint32
*)&v
;
640 mono_array_new_va (MonoMethod
*cm
, ...)
642 MonoDomain
*domain
= mono_domain_get ();
645 intptr_t *lower_bounds
;
652 pcount
= mono_method_signature (cm
)->param_count
;
653 rank
= cm
->klass
->rank
;
657 lengths
= alloca (sizeof (uintptr_t) * pcount
);
658 for (i
= 0; i
< pcount
; ++i
)
659 lengths
[i
] = d
= va_arg(ap
, int);
661 if (rank
== pcount
) {
662 /* Only lengths provided. */
663 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
664 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
665 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
670 g_assert (pcount
== (rank
* 2));
671 /* lower bounds are first. */
672 lower_bounds
= (intptr_t*)lengths
;
677 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
680 /* Specialized version of mono_array_new_va () which avoids varargs */
682 mono_array_new_1 (MonoMethod
*cm
, guint32 length
)
684 MonoDomain
*domain
= mono_domain_get ();
685 uintptr_t lengths
[1];
686 intptr_t *lower_bounds
;
692 pcount
= mono_method_signature (cm
)->param_count
;
693 rank
= cm
->klass
->rank
;
695 lengths
[0] = length
;
697 g_assert (rank
== pcount
);
699 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
700 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
701 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
706 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
710 mono_array_new_2 (MonoMethod
*cm
, guint32 length1
, guint32 length2
)
712 MonoDomain
*domain
= mono_domain_get ();
713 uintptr_t lengths
[2];
714 intptr_t *lower_bounds
;
720 pcount
= mono_method_signature (cm
)->param_count
;
721 rank
= cm
->klass
->rank
;
723 lengths
[0] = length1
;
724 lengths
[1] = length2
;
726 g_assert (rank
== pcount
);
728 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
729 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
730 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
735 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
739 mono_array_new_3 (MonoMethod
*cm
, guint32 length1
, guint32 length2
, guint32 length3
)
741 MonoDomain
*domain
= mono_domain_get ();
742 uintptr_t lengths
[3];
743 intptr_t *lower_bounds
;
749 pcount
= mono_method_signature (cm
)->param_count
;
750 rank
= cm
->klass
->rank
;
752 lengths
[0] = length1
;
753 lengths
[1] = length2
;
754 lengths
[2] = length3
;
756 g_assert (rank
== pcount
);
758 if (cm
->klass
->byval_arg
.type
== MONO_TYPE_ARRAY
) {
759 lower_bounds
= alloca (sizeof (intptr_t) * rank
);
760 memset (lower_bounds
, 0, sizeof (intptr_t) * rank
);
765 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
769 mono_class_static_field_address (MonoDomain
*domain
, MonoClassField
*field
)
776 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
778 mono_class_init (field
->parent
);
780 vtable
= mono_class_vtable_full (domain
, field
->parent
, TRUE
);
781 if (!vtable
->initialized
)
782 mono_runtime_class_init (vtable
);
784 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
786 if (domain
->special_static_fields
&& (addr
= g_hash_table_lookup (domain
->special_static_fields
, field
)))
787 addr
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
789 addr
= (char*)mono_vtable_get_static_field_data (vtable
) + field
->offset
;
795 mono_ldtoken_wrapper (MonoImage
*image
, int token
, MonoGenericContext
*context
)
797 MonoClass
*handle_class
;
801 res
= mono_ldtoken (image
, token
, &handle_class
, context
);
802 mono_class_init (handle_class
);
808 mono_ldtoken_wrapper_generic_shared (MonoImage
*image
, int token
, MonoMethod
*method
)
810 MonoMethodSignature
*sig
= mono_method_signature (method
);
811 MonoGenericContext
*generic_context
;
813 if (sig
->is_inflated
) {
814 generic_context
= mono_method_get_context (method
);
816 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
817 g_assert (generic_container
);
818 generic_context
= &generic_container
->context
;
821 return mono_ldtoken_wrapper (image
, token
, generic_context
);
825 mono_fconv_u8 (double v
)
830 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
832 mono_fconv_i8 (double v
)
834 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
840 mono_fconv_u4 (double v
)
842 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
847 /* Solaris doesn't have trunc */
849 extern long double aintl (long double);
852 /* FIXME: This means we will never throw overflow exceptions */
855 #endif /* HAVE_TRUNC */
858 mono_fconv_ovf_i8 (double v
)
866 if (isnan(v
) || trunc (v
) != res
) {
867 mono_raise_exception (mono_get_exception_overflow ());
873 mono_fconv_ovf_u8 (double v
)
879 * The soft-float implementation of some ARM devices have a buggy guin64 to double
880 * conversion that it looses precision even when the integer if fully representable
883 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
885 * To work around this issue we test for value boundaries instead.
887 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
888 if (isnan (v
) || !(v
>= -0.5 && v
<= ULLONG_MAX
+0.5)) {
889 mono_raise_exception (mono_get_exception_overflow ());
894 if (isnan(v
) || trunc (v
) != res
) {
895 mono_raise_exception (mono_get_exception_overflow ());
901 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
903 mono_lconv_to_r8 (gint64 a
)
909 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
911 mono_lconv_to_r4 (gint64 a
)
917 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
919 mono_conv_to_r8_un (guint32 a
)
925 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
927 mono_lconv_to_r8_un (guint64 a
)
933 #if defined(__native_client_codegen__) || defined(__native_client__)
934 /* When we cross-compile to Native Client we can't directly embed calls */
935 /* to the math library on the host. This will use the fmod on the target*/
937 mono_fmod(double a
, double b
)
944 mono_helper_compile_generic_method (MonoObject
*obj
, MonoMethod
*method
, gpointer
*this_arg
)
948 MonoGenericContext
*context
= mono_method_get_context (method
);
950 mono_jit_stats
.generic_virtual_invocations
++;
953 mono_raise_exception (mono_get_exception_null_reference ());
954 vmethod
= mono_object_get_virtual_method (obj
, method
);
955 g_assert (!vmethod
->klass
->generic_container
);
956 g_assert (!vmethod
->klass
->generic_class
|| !vmethod
->klass
->generic_class
->context
.class_inst
->is_open
);
957 g_assert (!context
->method_inst
|| !context
->method_inst
->is_open
);
959 addr
= mono_compile_method (vmethod
);
961 if (mono_method_needs_static_rgctx_invoke (vmethod
, FALSE
))
962 addr
= mono_create_static_rgctx_trampoline (vmethod
, addr
);
964 /* Since this is a virtual call, have to unbox vtypes */
965 if (obj
->vtable
->klass
->valuetype
)
966 *this_arg
= mono_object_unbox (obj
);
974 mono_helper_ldstr (MonoImage
*image
, guint32 idx
)
976 return mono_ldstr (mono_domain_get (), image
, idx
);
980 mono_helper_ldstr_mscorlib (guint32 idx
)
982 return mono_ldstr (mono_domain_get (), mono_defaults
.corlib
, idx
);
986 mono_helper_newobj_mscorlib (guint32 idx
)
988 MonoClass
*klass
= mono_class_get (mono_defaults
.corlib
, MONO_TOKEN_TYPE_DEF
| idx
);
992 return mono_object_new (mono_domain_get (), klass
);
996 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
997 * in generated code. So instead we emit a call to this function and place a gdb
1006 mono_create_corlib_exception_0 (guint32 token
)
1008 return mono_exception_from_token (mono_defaults
.corlib
, token
);
1012 mono_create_corlib_exception_1 (guint32 token
, MonoString
*arg
)
1014 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg
, NULL
);
1018 mono_create_corlib_exception_2 (guint32 token
, MonoString
*arg1
, MonoString
*arg2
)
1020 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg1
, arg2
);
1024 mono_object_castclass (MonoObject
*obj
, MonoClass
*klass
)
1026 MonoJitTlsData
*jit_tls
= NULL
;
1028 if (mini_get_debug_options ()->better_cast_details
) {
1029 jit_tls
= mono_native_tls_get_value (mono_jit_tls_id
);
1030 jit_tls
->class_cast_from
= NULL
;
1036 if (mono_object_isinst (obj
, klass
))
1039 if (mini_get_debug_options ()->better_cast_details
) {
1040 jit_tls
->class_cast_from
= obj
->vtable
->klass
;
1041 jit_tls
->class_cast_to
= klass
;
1044 mono_raise_exception (mono_exception_from_name (mono_defaults
.corlib
,
1045 "System", "InvalidCastException"));
1051 mono_object_castclass_with_cache (MonoObject
*obj
, MonoClass
*klass
, gpointer
*cache
)
1053 MonoJitTlsData
*jit_tls
= NULL
;
1054 gpointer cached_vtable
, obj_vtable
;
1056 if (mini_get_debug_options ()->better_cast_details
) {
1057 jit_tls
= mono_native_tls_get_value (mono_jit_tls_id
);
1058 jit_tls
->class_cast_from
= NULL
;
1064 cached_vtable
= *cache
;
1065 obj_vtable
= obj
->vtable
;
1067 if (cached_vtable
== obj_vtable
)
1070 if (mono_object_isinst (obj
, klass
)) {
1071 *cache
= obj_vtable
;
1075 if (mini_get_debug_options ()->better_cast_details
) {
1076 jit_tls
->class_cast_from
= obj
->vtable
->klass
;
1077 jit_tls
->class_cast_to
= klass
;
1080 mono_raise_exception (mono_exception_from_name (mono_defaults
.corlib
,
1081 "System", "InvalidCastException"));
1087 mono_object_isinst_with_cache (MonoObject
*obj
, MonoClass
*klass
, gpointer
*cache
)
1089 size_t cached_vtable
, obj_vtable
;
1094 cached_vtable
= (size_t)*cache
;
1095 obj_vtable
= (size_t)obj
->vtable
;
1097 if ((cached_vtable
& ~0x1) == obj_vtable
) {
1098 return (cached_vtable
& 0x1) ? NULL
: obj
;
1101 if (mono_object_isinst (obj
, klass
)) {
1102 *cache
= (gpointer
)obj_vtable
;
1106 *cache
= (gpointer
)(obj_vtable
| 0x1);
1112 mono_get_native_calli_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
, gpointer func
)
1114 MonoMarshalSpec
**mspecs
;
1115 MonoMethodPInvoke piinfo
;
1118 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
1119 memset (&piinfo
, 0, sizeof (piinfo
));
1121 m
= mono_marshal_get_native_func_wrapper (image
, sig
, &piinfo
, mspecs
, func
);
1123 return mono_compile_method (m
);