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"
20 #include <mono/utils/mono-error-internals.h>
21 #include <mono/metadata/threads-types.h>
22 #include <mono/metadata/reflection-internals.h>
25 #include "mini-llvm-cpp.h"
29 mono_ldftn (MonoMethod *method)
35 // FIXME: No error handling
37 addr = mono_compile_method (method);
40 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
41 /* The caller doesn't pass it */
42 g_assert_not_reached ();
44 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
48 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
49 if (!mono_error_ok (&error)) {
50 mono_error_set_pending_exception (&error);
53 return mono_create_ftnptr (mono_domain_get (), addr);
57 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
63 mono_set_pending_exception (mono_get_exception_null_reference ());
67 res = mono_object_get_virtual_method (obj, method);
69 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
70 MonoGenericContext context = { NULL, NULL };
72 if (res->klass->generic_class)
73 context.class_inst = res->klass->generic_class->context.class_inst;
74 else if (res->klass->generic_container)
75 context.class_inst = res->klass->generic_container->context.class_inst;
76 context.method_inst = mono_method_get_context (method)->method_inst;
78 res = mono_class_inflate_generic_method_checked (res, &context, &error);
79 if (!mono_error_ok (&error)) {
80 mono_error_set_pending_exception (&error);
85 /* An rgctx wrapper is added by the trampolines no need to do it here */
87 return mono_ldftn (res);
91 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
93 return ldvirtfn_internal (obj, method, FALSE);
97 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
99 return ldvirtfn_internal (obj, method, TRUE);
103 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
107 mono_set_pending_exception (mono_get_exception_null_reference ());
110 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
111 if (mono_error_set_pending_exception (&error))
113 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
118 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
121 mono_llmult (gint64 a, gint64 b)
127 mono_llmult_ovf_un (guint64 a, guint64 b)
130 guint32 ah = a >> 32;
132 guint32 bh = b >> 32;
135 // fixme: this is incredible slow
138 goto raise_exception;
140 res = (guint64)al * (guint64)bl;
142 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
145 goto raise_exception;
147 res += ((guint64)t1) << 32;
152 mono_set_pending_exception (mono_get_exception_overflow ());
157 mono_llmult_ovf (gint64 a, gint64 b)
164 Use Karatsuba algorithm where:
165 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
166 where Ah is the "high half" (most significant 32 bits) of a and
167 where Al is the "low half" (least significant 32 bits) of a and
168 where Bh is the "high half" of b and Bl is the "low half" and
169 where R is the Radix or "size of the half" (in our case 32 bits)
171 Note, for the product of two 64 bit numbers to fit into a 64
172 result, ah and/or bh must be 0. This will save us from doing
173 the AhBh term at all.
175 Also note that we refactor so that we don't overflow 64 bits with
176 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
182 /* need to work with absoulte values, so find out what the
183 resulting sign will be and convert any negative numbers
184 from two's complement
188 if (((guint32)ah == 0x80000000) && (al == 0)) {
189 /* This has no two's complement */
195 goto raise_exception;
198 /* flip the bits and add 1 */
209 if (((guint32)bh == 0x80000000) && (bl == 0)) {
210 /* This has no two's complement */
216 goto raise_exception;
219 /* flip the bits and add 1 */
229 /* we overflow for sure if both upper halves are greater
230 than zero because we would need to shift their
231 product 64 bits to the left and that will not fit
232 in a 64 bit result */
234 goto raise_exception;
235 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
236 goto raise_exception;
238 /* do the AlBl term first */
239 t1 = (gint64)al * (gint64)bl;
243 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
244 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
245 /* check for overflow */
247 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
248 goto raise_exception;
253 goto raise_exception;
261 mono_set_pending_exception (mono_get_exception_overflow ());
266 mono_lldiv (gint64 a, gint64 b)
268 #ifdef MONO_ARCH_NEED_DIV_CHECK
270 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
273 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
274 mono_set_pending_exception (mono_get_exception_arithmetic ());
282 mono_llrem (gint64 a, gint64 b)
284 #ifdef MONO_ARCH_NEED_DIV_CHECK
286 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
289 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
290 mono_set_pending_exception (mono_get_exception_arithmetic ());
298 mono_lldiv_un (guint64 a, guint64 b)
300 #ifdef MONO_ARCH_NEED_DIV_CHECK
302 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
310 mono_llrem_un (guint64 a, guint64 b)
312 #ifdef MONO_ARCH_NEED_DIV_CHECK
314 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
323 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
326 mono_lshl (guint64 a, gint32 shamt)
330 res = a << (shamt & 0x7f);
332 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
338 mono_lshr_un (guint64 a, gint32 shamt)
342 res = a >> (shamt & 0x7f);
344 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
350 mono_lshr (gint64 a, gint32 shamt)
354 res = a >> (shamt & 0x7f);
356 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
363 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
366 mono_idiv (gint32 a, gint32 b)
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
370 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
373 else if (b == -1 && a == (0x80000000)) {
374 mono_set_pending_exception (mono_get_exception_overflow ());
382 mono_idiv_un (guint32 a, guint32 b)
384 #ifdef MONO_ARCH_NEED_DIV_CHECK
386 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
394 mono_irem (gint32 a, gint32 b)
396 #ifdef MONO_ARCH_NEED_DIV_CHECK
398 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
401 else if (b == -1 && a == (0x80000000)) {
402 mono_set_pending_exception (mono_get_exception_overflow ());
410 mono_irem_un (guint32 a, guint32 b)
412 #ifdef MONO_ARCH_NEED_DIV_CHECK
414 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
423 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
426 mono_imul (gint32 a, gint32 b)
432 mono_imul_ovf (gint32 a, gint32 b)
436 res = (gint64)a * (gint64)b;
438 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
439 mono_set_pending_exception (mono_get_exception_overflow ());
447 mono_imul_ovf_un (guint32 a, guint32 b)
451 res = (guint64)a * (guint64)b;
454 mono_set_pending_exception (mono_get_exception_overflow ());
462 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
464 mono_fdiv (double a, double b)
470 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
473 mono_fsub (double a, double b)
479 mono_fadd (double a, double b)
485 mono_fmul (double a, double b)
497 mono_fconv_r4 (double a)
503 mono_conv_to_r8 (int a)
509 mono_conv_to_r4 (int a)
511 return (double)(float)a;
515 mono_fconv_i1 (double a)
521 mono_fconv_i2 (double a)
527 mono_fconv_i4 (double a)
533 mono_fconv_u1 (double a)
539 mono_fconv_u2 (double a)
545 mono_fcmp_eq (double a, double b)
551 mono_fcmp_ge (double a, double b)
557 mono_fcmp_gt (double a, double b)
563 mono_fcmp_le (double a, double b)
569 mono_fcmp_lt (double a, double b)
575 mono_fcmp_ne_un (double a, double b)
577 return isunordered (a, b) || a != b;
581 mono_fcmp_ge_un (double a, double b)
583 return isunordered (a, b) || a >= b;
587 mono_fcmp_gt_un (double a, double b)
589 return isunordered (a, b) || a > b;
593 mono_fcmp_le_un (double a, double b)
595 return isunordered (a, b) || a <= b;
599 mono_fcmp_lt_un (double a, double b)
601 return isunordered (a, b) || a < b;
605 mono_fceq (double a, double b)
611 mono_fcgt (double a, double b)
617 mono_fcgt_un (double a, double b)
619 return isunordered (a, b) || a > b;
623 mono_fclt (double a, double b)
629 mono_fclt_un (double a, double b)
631 return isunordered (a, b) || a < b;
635 mono_isfinite (double a)
640 g_assert_not_reached ();
646 mono_fload_r4 (float *ptr)
652 mono_fstore_r4 (double val, float *ptr)
657 /* returns the integer bitpattern that is passed in the regs or stack */
659 mono_fload_r4_arg (double val)
661 float v = (float)val;
662 return *(guint32*)&v;
668 mono_array_new_va (MonoMethod *cm, ...)
672 MonoDomain *domain = mono_domain_get ();
675 intptr_t *lower_bounds;
680 pcount = mono_method_signature (cm)->param_count;
681 rank = cm->klass->rank;
685 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
686 for (i = 0; i < pcount; ++i)
687 lengths [i] = d = va_arg(ap, int);
689 if (rank == pcount) {
690 /* Only lengths provided. */
691 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
692 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
693 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
698 g_assert (pcount == (rank * 2));
699 /* lower bounds are first. */
700 lower_bounds = (intptr_t*)lengths;
705 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
707 if (!mono_error_ok (&error)) {
708 mono_error_set_pending_exception (&error);
715 /* Specialized version of mono_array_new_va () which avoids varargs */
717 mono_array_new_1 (MonoMethod *cm, guint32 length)
721 MonoDomain *domain = mono_domain_get ();
722 uintptr_t lengths [1];
723 intptr_t *lower_bounds;
727 pcount = mono_method_signature (cm)->param_count;
728 rank = cm->klass->rank;
730 lengths [0] = length;
732 g_assert (rank == pcount);
734 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
735 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
736 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
741 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
743 if (!mono_error_ok (&error)) {
744 mono_error_set_pending_exception (&error);
752 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
756 MonoDomain *domain = mono_domain_get ();
757 uintptr_t lengths [2];
758 intptr_t *lower_bounds;
762 pcount = mono_method_signature (cm)->param_count;
763 rank = cm->klass->rank;
765 lengths [0] = length1;
766 lengths [1] = length2;
768 g_assert (rank == pcount);
770 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
771 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
772 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
777 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
779 if (!mono_error_ok (&error)) {
780 mono_error_set_pending_exception (&error);
788 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
792 MonoDomain *domain = mono_domain_get ();
793 uintptr_t lengths [3];
794 intptr_t *lower_bounds;
798 pcount = mono_method_signature (cm)->param_count;
799 rank = cm->klass->rank;
801 lengths [0] = length1;
802 lengths [1] = length2;
803 lengths [2] = length3;
805 g_assert (rank == pcount);
807 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
808 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
809 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
814 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
816 if (!mono_error_ok (&error)) {
817 mono_error_set_pending_exception (&error);
825 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
829 MonoDomain *domain = mono_domain_get ();
830 uintptr_t lengths [4];
831 intptr_t *lower_bounds;
835 pcount = mono_method_signature (cm)->param_count;
836 rank = cm->klass->rank;
838 lengths [0] = length1;
839 lengths [1] = length2;
840 lengths [2] = length3;
841 lengths [3] = length4;
843 g_assert (rank == pcount);
845 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
846 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
847 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
852 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
854 if (!mono_error_ok (&error)) {
855 mono_error_set_pending_exception (&error);
863 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
869 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
871 mono_class_init (field->parent);
873 vtable = mono_class_vtable_full (domain, field->parent, &error);
874 if (!is_ok (&error)) {
875 mono_error_set_pending_exception (&error);
878 if (!vtable->initialized) {
879 if (!mono_runtime_class_init_full (vtable, &error)) {
880 mono_error_set_pending_exception (&error);
885 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
887 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
888 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
890 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
896 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
899 MonoClass *handle_class;
902 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
903 if (!mono_error_ok (&error)) {
904 mono_error_set_pending_exception (&error);
907 mono_class_init (handle_class);
913 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
915 MonoMethodSignature *sig = mono_method_signature (method);
916 MonoGenericContext *generic_context;
918 if (sig->is_inflated) {
919 generic_context = mono_method_get_context (method);
921 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
922 g_assert (generic_container);
923 generic_context = &generic_container->context;
926 return mono_ldtoken_wrapper (image, token, generic_context);
930 mono_fconv_u8 (double v)
936 mono_rconv_u8 (float v)
941 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
943 mono_fconv_i8 (double v)
950 mono_fconv_u4 (double v)
952 /* MS.NET behaves like this for some reason */
954 if (isinf (v) || isnan (v))
962 /* Solaris doesn't have trunc */
964 extern long double aintl (long double);
967 /* FIXME: This means we will never throw overflow exceptions */
970 #endif /* HAVE_TRUNC */
973 mono_fconv_ovf_i8 (double v)
979 if (isnan(v) || trunc (v) != res) {
980 mono_set_pending_exception (mono_get_exception_overflow ());
987 mono_fconv_ovf_u8 (double v)
992 * The soft-float implementation of some ARM devices have a buggy guin64 to double
993 * conversion that it looses precision even when the integer if fully representable
996 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
998 * To work around this issue we test for value boundaries instead.
1000 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1001 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1002 mono_set_pending_exception (mono_get_exception_overflow ());
1008 if (isnan(v) || trunc (v) != res) {
1009 mono_set_pending_exception (mono_get_exception_overflow ());
1016 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1018 mono_rconv_i8 (float v)
1025 mono_rconv_ovf_i8 (float v)
1031 if (isnan(v) || trunc (v) != res) {
1032 mono_set_pending_exception (mono_get_exception_overflow ());
1039 mono_rconv_ovf_u8 (float v)
1044 if (isnan(v) || trunc (v) != res) {
1045 mono_set_pending_exception (mono_get_exception_overflow ());
1051 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1053 mono_lconv_to_r8 (gint64 a)
1059 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1061 mono_lconv_to_r4 (gint64 a)
1067 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1069 mono_conv_to_r8_un (guint32 a)
1075 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1077 mono_lconv_to_r8_un (guint64 a)
1083 #if defined(__native_client_codegen__) || defined(__native_client__)
1084 /* When we cross-compile to Native Client we can't directly embed calls */
1085 /* to the math library on the host. This will use the fmod on the target*/
1087 mono_fmod(double a, double b)
1094 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1096 MonoMethod *vmethod;
1098 MonoGenericContext *context = mono_method_get_context (method);
1100 mono_jit_stats.generic_virtual_invocations++;
1103 mono_set_pending_exception (mono_get_exception_null_reference ());
1106 vmethod = mono_object_get_virtual_method (obj, method);
1107 g_assert (!vmethod->klass->generic_container);
1108 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1109 g_assert (!context->method_inst || !context->method_inst->is_open);
1111 addr = mono_compile_method (vmethod);
1113 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1115 /* Since this is a virtual call, have to unbox vtypes */
1116 if (obj->vtable->klass->valuetype)
1117 *this_arg = mono_object_unbox (obj);
1125 mono_helper_ldstr (MonoImage *image, guint32 idx)
1127 return mono_ldstr (mono_domain_get (), image, idx);
1131 mono_helper_ldstr_mscorlib (guint32 idx)
1133 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1137 mono_helper_newobj_mscorlib (guint32 idx)
1140 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1142 if (!mono_error_ok (&error)) {
1143 mono_error_set_pending_exception (&error);
1147 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1148 if (!mono_error_ok (&error))
1149 mono_error_set_pending_exception (&error);
1154 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1155 * in generated code. So instead we emit a call to this function and place a gdb
1164 mono_create_corlib_exception_0 (guint32 token)
1166 return mono_exception_from_token (mono_defaults.corlib, token);
1170 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1172 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1176 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1178 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1182 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1185 MonoJitTlsData *jit_tls = NULL;
1188 if (mini_get_debug_options ()->better_cast_details) {
1189 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1190 jit_tls->class_cast_from = NULL;
1196 oklass = obj->vtable->klass;
1197 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1199 if (mono_object_isinst_checked (obj, klass, &error))
1201 if (mono_error_set_pending_exception (&error))
1204 if (mini_get_debug_options ()->better_cast_details) {
1205 jit_tls->class_cast_from = oklass;
1206 jit_tls->class_cast_to = klass;
1209 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1210 "System", "InvalidCastException"));
1216 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1219 MonoJitTlsData *jit_tls = NULL;
1220 gpointer cached_vtable, obj_vtable;
1222 if (mini_get_debug_options ()->better_cast_details) {
1223 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1224 jit_tls->class_cast_from = NULL;
1230 cached_vtable = *cache;
1231 obj_vtable = obj->vtable;
1233 if (cached_vtable == obj_vtable)
1236 if (mono_object_isinst_checked (obj, klass, &error)) {
1237 *cache = obj_vtable;
1240 if (mono_error_set_pending_exception (&error))
1243 if (mini_get_debug_options ()->better_cast_details) {
1244 jit_tls->class_cast_from = obj->vtable->klass;
1245 jit_tls->class_cast_to = klass;
1248 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1249 "System", "InvalidCastException"));
1255 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1258 size_t cached_vtable, obj_vtable;
1263 cached_vtable = (size_t)*cache;
1264 obj_vtable = (size_t)obj->vtable;
1266 if ((cached_vtable & ~0x1) == obj_vtable) {
1267 return (cached_vtable & 0x1) ? NULL : obj;
1270 if (mono_object_isinst_checked (obj, klass, &error)) {
1271 *cache = (gpointer)obj_vtable;
1274 if (mono_error_set_pending_exception (&error))
1277 *cache = (gpointer)(obj_vtable | 0x1);
1283 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1285 MonoMarshalSpec **mspecs;
1286 MonoMethodPInvoke piinfo;
1289 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1290 memset (&piinfo, 0, sizeof (piinfo));
1292 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1294 return mono_compile_method (m);
1298 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1301 int vt_slot, iface_offset;
1303 mono_error_init (error);
1305 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1306 MonoObject *this_obj;
1308 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1309 this_obj = *(MonoObject**)mp;
1310 g_assert (this_obj);
1312 klass = this_obj->vtable->klass;
1315 if (mono_method_signature (cmethod)->pinvoke) {
1316 /* Object.GetType () */
1317 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1319 /* Lookup the virtual method */
1320 mono_class_setup_vtable (klass);
1321 g_assert (klass->vtable);
1322 vt_slot = mono_method_get_vtable_slot (cmethod);
1323 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1324 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1325 g_assert (iface_offset != -1);
1326 vt_slot += iface_offset;
1328 m = klass->vtable [vt_slot];
1329 if (cmethod->is_inflated)
1330 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1333 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1335 * Calling a non-vtype method with a vtype receiver, has to box.
1337 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1338 else if (klass->valuetype)
1340 * Calling a vtype method with a vtype receiver
1345 * Calling a non-vtype method
1347 *this_arg = *(gpointer*)mp;
1352 * mono_gsharedvt_constrained_call:
1354 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1355 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1358 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1364 gpointer new_args [16];
1366 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1367 if (!mono_error_ok (&error)) {
1368 mono_error_set_pending_exception (&error);
1374 if (args && deref_arg) {
1375 new_args [0] = *(gpointer*)args [0];
1378 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1379 /* Object.GetType () */
1381 args [0] = this_arg;
1385 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1386 if (!mono_error_ok (&error)) {
1387 mono_error_set_pending_exception (&error);
1395 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1397 if (klass->valuetype)
1398 mono_value_copy (dest, src, klass);
1400 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1404 ves_icall_runtime_class_init (MonoVTable *vtable)
1406 MONO_REQ_GC_UNSAFE_MODE;
1409 mono_runtime_class_init_full (vtable, &error);
1410 mono_error_set_pending_exception (&error);
1415 mono_generic_class_init (MonoVTable *vtable)
1418 mono_runtime_class_init_full (vtable, &error);
1419 mono_error_set_pending_exception (&error);
1423 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1428 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1429 if (!mono_error_ok (&error)) {
1430 mono_error_set_pending_exception (&error);
1437 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1442 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1443 if (!mono_error_ok (&error)) {
1444 mono_error_set_pending_exception (&error);
1451 * resolve_iface_call:
1453 * Return the executable code for the iface method IMT_METHOD called on THIS.
1454 * This function is called on a slowpath, so it doesn't need to be fast.
1455 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1459 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1462 gpointer *imt, *vtable_slot;
1463 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1464 gpointer addr, compiled_method, aot_addr;
1465 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1468 /* The caller will handle it */
1471 vt = this_obj->vtable;
1472 imt = (gpointer*)vt - MONO_IMT_SIZE;
1474 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1476 // FIXME: This can throw exceptions
1477 addr = compiled_method = mono_compile_method (impl_method);
1480 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1481 generic_virtual = imt_method;
1483 if (generic_virtual || variant_iface) {
1484 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1485 need_unbox_tramp = TRUE;
1487 if (impl_method->klass->valuetype)
1488 need_unbox_tramp = TRUE;
1491 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1493 if (generic_virtual || variant_iface) {
1494 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1496 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1505 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1507 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1511 is_generic_method_definition (MonoMethod *m)
1513 MonoGenericContext *context;
1516 if (!m->is_inflated)
1519 context = mono_method_get_context (m);
1520 if (!context->method_inst)
1522 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1530 * Return the executable code for calling vt->vtable [slot].
1531 * This function is called on a slowpath, so it doesn't need to be fast.
1532 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1536 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1538 MonoMethod *m, *generic_virtual = NULL;
1539 gpointer addr, compiled_method;
1540 gboolean need_unbox_tramp = FALSE;
1542 /* Same as in common_call_trampoline () */
1544 /* Avoid loading metadata or creating a generic vtable if possible */
1545 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1546 if (addr && !vt->klass->valuetype)
1547 return mono_create_ftnptr (mono_domain_get (), addr);
1549 m = mono_class_get_vtable_entry (vt->klass, slot);
1551 if (is_generic_method_definition (m)) {
1553 MonoGenericContext context = { NULL, NULL };
1554 MonoMethod *declaring;
1557 declaring = mono_method_get_declaring_generic_method (m);
1561 if (m->klass->generic_class)
1562 context.class_inst = m->klass->generic_class->context.class_inst;
1564 g_assert (!m->klass->generic_container);
1566 generic_virtual = imt_method;
1567 g_assert (generic_virtual);
1568 g_assert (generic_virtual->is_inflated);
1569 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1571 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1572 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1575 if (generic_virtual) {
1576 if (vt->klass->valuetype)
1577 need_unbox_tramp = TRUE;
1579 if (m->klass->valuetype)
1580 need_unbox_tramp = TRUE;
1583 // FIXME: This can throw exceptions
1584 addr = compiled_method = mono_compile_method (m);
1587 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1589 if (!gsharedvt && generic_virtual) {
1590 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1591 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1593 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1594 vt, vt->vtable + slot,
1595 generic_virtual, ftndesc);
1602 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1604 g_assert (this_obj);
1606 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1610 * mono_resolve_generic_virtual_call:
1612 * Resolve a generic virtual call.
1613 * This function is called on a slowpath, so it doesn't need to be fast.
1616 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1619 gpointer addr, compiled_method;
1620 gboolean need_unbox_tramp = FALSE;
1622 MonoGenericContext context = { NULL, NULL };
1623 MonoMethod *declaring;
1624 gpointer arg = NULL;
1626 m = mono_class_get_vtable_entry (vt->klass, slot);
1628 g_assert (is_generic_method_definition (m));
1631 declaring = mono_method_get_declaring_generic_method (m);
1635 if (m->klass->generic_class)
1636 context.class_inst = m->klass->generic_class->context.class_inst;
1638 g_assert (!m->klass->generic_container);
1640 g_assert (generic_virtual->is_inflated);
1641 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1643 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1644 g_assert (mono_error_ok (&error));
1646 if (vt->klass->valuetype)
1647 need_unbox_tramp = TRUE;
1649 // FIXME: This can throw exceptions
1650 addr = compiled_method = mono_compile_method (m);
1653 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1656 * This wastes memory but the memory usage is bounded since
1657 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1658 * this vtable slot so we are not called any more for this instantiation.
1660 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1662 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1663 vt, vt->vtable + slot,
1664 generic_virtual, ftndesc);
1669 * mono_resolve_generic_virtual_call:
1671 * Resolve a generic virtual/variant iface call on interfaces.
1672 * This function is called on a slowpath, so it doesn't need to be fast.
1675 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1677 MonoMethod *m, *variant_iface;
1678 gpointer addr, aot_addr, compiled_method;
1679 gboolean need_unbox_tramp = FALSE;
1680 gboolean need_rgctx_tramp;
1681 gpointer arg = NULL;
1684 imt = (gpointer*)vt - MONO_IMT_SIZE;
1686 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1688 if (vt->klass->valuetype)
1689 need_unbox_tramp = TRUE;
1691 // FIXME: This can throw exceptions
1692 addr = compiled_method = mono_compile_method (m);
1695 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1698 * This wastes memory but the memory usage is bounded since
1699 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1700 * this vtable slot so we are not called any more for this instantiation.
1702 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1704 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1706 variant_iface ? variant_iface : generic_virtual, ftndesc);
1711 * mono_init_vtable_slot:
1713 * Initialize slot SLOT of VTABLE.
1714 * Return the contents of the vtable slot.
1717 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1719 gpointer arg = NULL;
1723 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1724 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1727 mono_memory_barrier ();
1729 vtable->vtable [slot] = ftnptr;
1735 * mono_llvmonly_init_delegate:
1737 * Initialize a MonoDelegate object.
1738 * Similar to mono_delegate_ctor ().
1741 mono_llvmonly_init_delegate (MonoDelegate *del)
1743 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1746 * We store a MonoFtnDesc in del->method_code.
1747 * It would be better to store an ftndesc in del->method_ptr too,
1748 * but we don't have a a structure which could own its memory.
1750 if (G_UNLIKELY (!ftndesc)) {
1751 gpointer addr = mono_compile_method (del->method);
1753 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1754 addr = mono_aot_get_unbox_trampoline (del->method);
1756 gpointer arg = mini_get_delegate_arg (del->method, addr);
1758 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1759 mono_memory_barrier ();
1760 *del->method_code = (gpointer)ftndesc;
1762 del->method_ptr = ftndesc->addr;
1763 del->extra_arg = ftndesc->arg;
1767 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1771 method = mono_object_get_virtual_method (target, method);
1773 del->method = method;
1774 del->method_ptr = mono_compile_method (method);
1775 if (method->klass->valuetype)
1776 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1777 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1781 mono_get_assembly_object (MonoImage *image)
1785 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1787 mono_error_set_pending_exception (&error);
1792 mono_get_method_object (MonoMethod *method)
1795 MonoObject * result;
1796 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1797 mono_error_set_pending_exception (&error);
1802 mono_ckfinite (double d)
1804 if (isinf (d) || isnan (d))
1805 mono_set_pending_exception (mono_get_exception_arithmetic ());
1810 * mono_interruption_checkpoint_from_trampoline:
1812 * Check whenever the thread has a pending exception, and throw it
1814 * Architectures should move away from calling this function and
1815 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1816 * rewrind to the parent frame, and throw the exception normally.
1819 mono_interruption_checkpoint_from_trampoline (void)
1823 ex = mono_thread_force_interruption_checkpoint_noraise ();
1825 mono_raise_exception (ex);