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 guint32
*lower_bounds
;
648 pcount
= mono_method_signature (cm
)->param_count
;
649 rank
= cm
->klass
->rank
;
653 lengths
= alloca (sizeof (guint32
) * 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 (guint32
) * rank
);
661 memset (lower_bounds
, 0, sizeof (guint32
) * rank
);
666 g_assert (pcount
== (rank
* 2));
667 /* lower bounds are first. */
668 lower_bounds
= 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 ();
682 guint32
*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 (guint32
) * rank
);
697 memset (lower_bounds
, 0, sizeof (guint32
) * 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 ();
710 guint32
*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 (guint32
) * rank
);
726 memset (lower_bounds
, 0, sizeof (guint32
) * rank
);
731 return mono_array_new_full (domain
, cm
->klass
, lengths
, lower_bounds
);
735 mono_class_static_field_address (MonoDomain
*domain
, MonoClassField
*field
)
742 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
744 mono_class_init (field
->parent
);
746 vtable
= mono_class_vtable_full (domain
, field
->parent
, TRUE
);
747 if (!vtable
->initialized
)
748 mono_runtime_class_init (vtable
);
750 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
752 if (domain
->special_static_fields
&& (addr
= g_hash_table_lookup (domain
->special_static_fields
, field
)))
753 addr
= mono_get_special_static_data (GPOINTER_TO_UINT (addr
));
755 addr
= (char*)vtable
->data
+ field
->offset
;
761 mono_ldtoken_wrapper (MonoImage
*image
, int token
, MonoGenericContext
*context
)
763 MonoClass
*handle_class
;
767 res
= mono_ldtoken (image
, token
, &handle_class
, context
);
768 mono_class_init (handle_class
);
774 mono_ldtoken_wrapper_generic_shared (MonoImage
*image
, int token
, MonoMethod
*method
)
776 MonoMethodSignature
*sig
= mono_method_signature (method
);
777 MonoGenericContext
*generic_context
;
779 if (sig
->is_inflated
) {
780 generic_context
= mono_method_get_context (method
);
782 MonoGenericContainer
*generic_container
= mono_method_get_generic_container (method
);
783 g_assert (generic_container
);
784 generic_context
= &generic_container
->context
;
787 return mono_ldtoken_wrapper (image
, token
, generic_context
);
791 mono_fconv_u8 (double v
)
796 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
798 mono_fconv_i8 (double v
)
800 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
806 mono_fconv_u4 (double v
)
808 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
813 /* Solaris doesn't have trunc */
815 extern long double aintl (long double);
818 /* FIXME: This means we will never throw overflow exceptions */
821 #endif /* HAVE_TRUNC */
824 mono_fconv_ovf_i8 (double v
)
832 if (isnan(v
) || trunc (v
) != res
) {
833 mono_raise_exception (mono_get_exception_overflow ());
839 mono_fconv_ovf_u8 (double v
)
845 * The soft-float implementation of some ARM devices have a buggy guin64 to double
846 * conversion that it looses precision even when the integer if fully representable
849 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
851 * To work around this issue we test for value boundaries instead.
853 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT
854 if (isnan (v
) || !(v
>= -0.5 && v
<= ULLONG_MAX
+0.5)) {
855 mono_raise_exception (mono_get_exception_overflow ());
860 if (isnan(v
) || trunc (v
) != res
) {
861 mono_raise_exception (mono_get_exception_overflow ());
867 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
869 mono_lconv_to_r8 (gint64 a
)
875 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
877 mono_lconv_to_r4 (gint64 a
)
883 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
885 mono_conv_to_r8_un (guint32 a
)
891 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
893 mono_lconv_to_r8_un (guint64 a
)
900 mono_helper_compile_generic_method (MonoObject
*obj
, MonoMethod
*method
, gpointer
*this_arg
)
904 MonoGenericContext
*context
= mono_method_get_context (method
);
906 mono_jit_stats
.generic_virtual_invocations
++;
909 mono_raise_exception (mono_get_exception_null_reference ());
910 vmethod
= mono_object_get_virtual_method (obj
, method
);
911 g_assert (!vmethod
->klass
->generic_container
);
912 g_assert (!vmethod
->klass
->generic_class
|| !vmethod
->klass
->generic_class
->context
.class_inst
->is_open
);
913 g_assert (!context
->method_inst
|| !context
->method_inst
->is_open
);
915 addr
= mono_compile_method (vmethod
);
917 if (mono_method_needs_static_rgctx_invoke (vmethod
, FALSE
))
918 addr
= mono_create_static_rgctx_trampoline (vmethod
, addr
);
920 /* Since this is a virtual call, have to unbox vtypes */
921 if (obj
->vtable
->klass
->valuetype
)
922 *this_arg
= mono_object_unbox (obj
);
930 mono_helper_ldstr (MonoImage
*image
, guint32 idx
)
932 return mono_ldstr (mono_domain_get (), image
, idx
);
936 mono_helper_ldstr_mscorlib (guint32 idx
)
938 return mono_ldstr (mono_domain_get (), mono_defaults
.corlib
, idx
);
942 mono_helper_newobj_mscorlib (guint32 idx
)
944 MonoClass
*klass
= mono_class_get (mono_defaults
.corlib
, MONO_TOKEN_TYPE_DEF
| idx
);
948 return mono_object_new (mono_domain_get (), klass
);
952 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
953 * in generated code. So instead we emit a call to this function and place a gdb
962 mono_create_corlib_exception_0 (guint32 token
)
964 return mono_exception_from_token (mono_defaults
.corlib
, token
);
968 mono_create_corlib_exception_1 (guint32 token
, MonoString
*arg
)
970 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg
, NULL
);
974 mono_create_corlib_exception_2 (guint32 token
, MonoString
*arg1
, MonoString
*arg2
)
976 return mono_exception_from_token_two_strings (mono_defaults
.corlib
, token
, arg1
, arg2
);
980 mono_object_castclass (MonoObject
*obj
, MonoClass
*klass
)
985 if (mono_object_isinst (obj
, klass
))
988 mono_raise_exception (mono_exception_from_name (mono_defaults
.corlib
,
989 "System", "InvalidCastException"));
995 mono_get_native_calli_wrapper (MonoImage
*image
, MonoMethodSignature
*sig
, gpointer func
)
997 MonoMarshalSpec
**mspecs
;
998 MonoMethodPInvoke piinfo
;
1001 mspecs
= g_new0 (MonoMarshalSpec
*, sig
->param_count
+ 1);
1002 memset (&piinfo
, 0, sizeof (piinfo
));
1004 m
= mono_marshal_get_native_func_wrapper (image
, sig
, &piinfo
, mspecs
, func
);
1006 return mono_compile_method (m
);