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)
34 // FIXME: No error handling
36 addr = mono_compile_method (method);
39 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
40 /* The caller doesn't pass it */
41 g_assert_not_reached ();
43 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
47 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
49 return mono_create_ftnptr (mono_domain_get (), addr);
53 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
59 mono_set_pending_exception (mono_get_exception_null_reference ());
63 res = mono_object_get_virtual_method (obj, method);
65 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
66 MonoGenericContext context = { NULL, NULL };
68 if (res->klass->generic_class)
69 context.class_inst = res->klass->generic_class->context.class_inst;
70 else if (res->klass->generic_container)
71 context.class_inst = res->klass->generic_container->context.class_inst;
72 context.method_inst = mono_method_get_context (method)->method_inst;
74 res = mono_class_inflate_generic_method_checked (res, &context, &error);
75 if (!mono_error_ok (&error)) {
76 mono_error_set_pending_exception (&error);
81 /* An rgctx wrapper is added by the trampolines no need to do it here */
83 return mono_ldftn (res);
87 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
89 return ldvirtfn_internal (obj, method, FALSE);
93 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
95 return ldvirtfn_internal (obj, method, TRUE);
99 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
102 mono_set_pending_exception (mono_get_exception_null_reference ());
105 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
106 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
111 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
114 mono_llmult (gint64 a, gint64 b)
120 mono_llmult_ovf_un (guint64 a, guint64 b)
123 guint32 ah = a >> 32;
125 guint32 bh = b >> 32;
128 // fixme: this is incredible slow
131 goto raise_exception;
133 res = (guint64)al * (guint64)bl;
135 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
138 goto raise_exception;
140 res += ((guint64)t1) << 32;
145 mono_set_pending_exception (mono_get_exception_overflow ());
150 mono_llmult_ovf (gint64 a, gint64 b)
157 Use Karatsuba algorithm where:
158 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
159 where Ah is the "high half" (most significant 32 bits) of a and
160 where Al is the "low half" (least significant 32 bits) of a and
161 where Bh is the "high half" of b and Bl is the "low half" and
162 where R is the Radix or "size of the half" (in our case 32 bits)
164 Note, for the product of two 64 bit numbers to fit into a 64
165 result, ah and/or bh must be 0. This will save us from doing
166 the AhBh term at all.
168 Also note that we refactor so that we don't overflow 64 bits with
169 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
175 /* need to work with absoulte values, so find out what the
176 resulting sign will be and convert any negative numbers
177 from two's complement
181 if (((guint32)ah == 0x80000000) && (al == 0)) {
182 /* This has no two's complement */
188 goto raise_exception;
191 /* flip the bits and add 1 */
202 if (((guint32)bh == 0x80000000) && (bl == 0)) {
203 /* This has no two's complement */
209 goto raise_exception;
212 /* flip the bits and add 1 */
222 /* we overflow for sure if both upper halves are greater
223 than zero because we would need to shift their
224 product 64 bits to the left and that will not fit
225 in a 64 bit result */
227 goto raise_exception;
228 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
229 goto raise_exception;
231 /* do the AlBl term first */
232 t1 = (gint64)al * (gint64)bl;
236 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
237 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
238 /* check for overflow */
240 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
241 goto raise_exception;
246 goto raise_exception;
254 mono_set_pending_exception (mono_get_exception_overflow ());
259 mono_lldiv (gint64 a, gint64 b)
261 #ifdef MONO_ARCH_NEED_DIV_CHECK
263 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
266 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
267 mono_set_pending_exception (mono_get_exception_arithmetic ());
275 mono_llrem (gint64 a, gint64 b)
277 #ifdef MONO_ARCH_NEED_DIV_CHECK
279 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
282 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
283 mono_set_pending_exception (mono_get_exception_arithmetic ());
291 mono_lldiv_un (guint64 a, guint64 b)
293 #ifdef MONO_ARCH_NEED_DIV_CHECK
295 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
303 mono_llrem_un (guint64 a, guint64 b)
305 #ifdef MONO_ARCH_NEED_DIV_CHECK
307 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
316 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
319 mono_lshl (guint64 a, gint32 shamt)
323 res = a << (shamt & 0x7f);
325 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
331 mono_lshr_un (guint64 a, gint32 shamt)
335 res = a >> (shamt & 0x7f);
337 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
343 mono_lshr (gint64 a, gint32 shamt)
347 res = a >> (shamt & 0x7f);
349 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
356 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
359 mono_idiv (gint32 a, gint32 b)
361 #ifdef MONO_ARCH_NEED_DIV_CHECK
363 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
366 else if (b == -1 && a == (0x80000000)) {
367 mono_set_pending_exception (mono_get_exception_overflow ());
375 mono_idiv_un (guint32 a, guint32 b)
377 #ifdef MONO_ARCH_NEED_DIV_CHECK
379 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
387 mono_irem (gint32 a, gint32 b)
389 #ifdef MONO_ARCH_NEED_DIV_CHECK
391 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
394 else if (b == -1 && a == (0x80000000)) {
395 mono_set_pending_exception (mono_get_exception_overflow ());
403 mono_irem_un (guint32 a, guint32 b)
405 #ifdef MONO_ARCH_NEED_DIV_CHECK
407 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
416 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
419 mono_imul (gint32 a, gint32 b)
425 mono_imul_ovf (gint32 a, gint32 b)
429 res = (gint64)a * (gint64)b;
431 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
432 mono_set_pending_exception (mono_get_exception_overflow ());
440 mono_imul_ovf_un (guint32 a, guint32 b)
444 res = (guint64)a * (guint64)b;
447 mono_set_pending_exception (mono_get_exception_overflow ());
455 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
457 mono_fdiv (double a, double b)
463 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
466 mono_fsub (double a, double b)
472 mono_fadd (double a, double b)
478 mono_fmul (double a, double b)
490 mono_fconv_r4 (double a)
496 mono_conv_to_r8 (int a)
502 mono_conv_to_r4 (int a)
504 return (double)(float)a;
508 mono_fconv_i1 (double a)
514 mono_fconv_i2 (double a)
520 mono_fconv_i4 (double a)
526 mono_fconv_u1 (double a)
532 mono_fconv_u2 (double a)
538 mono_fcmp_eq (double a, double b)
544 mono_fcmp_ge (double a, double b)
550 mono_fcmp_gt (double a, double b)
556 mono_fcmp_le (double a, double b)
562 mono_fcmp_lt (double a, double b)
568 mono_fcmp_ne_un (double a, double b)
570 return isunordered (a, b) || a != b;
574 mono_fcmp_ge_un (double a, double b)
576 return isunordered (a, b) || a >= b;
580 mono_fcmp_gt_un (double a, double b)
582 return isunordered (a, b) || a > b;
586 mono_fcmp_le_un (double a, double b)
588 return isunordered (a, b) || a <= b;
592 mono_fcmp_lt_un (double a, double b)
594 return isunordered (a, b) || a < b;
598 mono_fceq (double a, double b)
604 mono_fcgt (double a, double b)
610 mono_fcgt_un (double a, double b)
612 return isunordered (a, b) || a > b;
616 mono_fclt (double a, double b)
622 mono_fclt_un (double a, double b)
624 return isunordered (a, b) || a < b;
628 mono_isfinite (double a)
633 g_assert_not_reached ();
639 mono_fload_r4 (float *ptr)
645 mono_fstore_r4 (double val, float *ptr)
650 /* returns the integer bitpattern that is passed in the regs or stack */
652 mono_fload_r4_arg (double val)
654 float v = (float)val;
655 return *(guint32*)&v;
661 mono_array_new_va (MonoMethod *cm, ...)
665 MonoDomain *domain = mono_domain_get ();
668 intptr_t *lower_bounds;
673 pcount = mono_method_signature (cm)->param_count;
674 rank = cm->klass->rank;
678 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
679 for (i = 0; i < pcount; ++i)
680 lengths [i] = d = va_arg(ap, int);
682 if (rank == pcount) {
683 /* Only lengths provided. */
684 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
685 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
686 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
691 g_assert (pcount == (rank * 2));
692 /* lower bounds are first. */
693 lower_bounds = (intptr_t*)lengths;
698 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
700 if (!mono_error_ok (&error)) {
701 mono_error_set_pending_exception (&error);
708 /* Specialized version of mono_array_new_va () which avoids varargs */
710 mono_array_new_1 (MonoMethod *cm, guint32 length)
714 MonoDomain *domain = mono_domain_get ();
715 uintptr_t lengths [1];
716 intptr_t *lower_bounds;
720 pcount = mono_method_signature (cm)->param_count;
721 rank = cm->klass->rank;
723 lengths [0] = length;
725 g_assert (rank == pcount);
727 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
728 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
729 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
734 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
736 if (!mono_error_ok (&error)) {
737 mono_error_set_pending_exception (&error);
745 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
749 MonoDomain *domain = mono_domain_get ();
750 uintptr_t lengths [2];
751 intptr_t *lower_bounds;
755 pcount = mono_method_signature (cm)->param_count;
756 rank = cm->klass->rank;
758 lengths [0] = length1;
759 lengths [1] = length2;
761 g_assert (rank == pcount);
763 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
764 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
765 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
770 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
772 if (!mono_error_ok (&error)) {
773 mono_error_set_pending_exception (&error);
781 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
785 MonoDomain *domain = mono_domain_get ();
786 uintptr_t lengths [3];
787 intptr_t *lower_bounds;
791 pcount = mono_method_signature (cm)->param_count;
792 rank = cm->klass->rank;
794 lengths [0] = length1;
795 lengths [1] = length2;
796 lengths [2] = length3;
798 g_assert (rank == pcount);
800 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
801 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
802 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
807 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
809 if (!mono_error_ok (&error)) {
810 mono_error_set_pending_exception (&error);
818 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
822 MonoDomain *domain = mono_domain_get ();
823 uintptr_t lengths [4];
824 intptr_t *lower_bounds;
828 pcount = mono_method_signature (cm)->param_count;
829 rank = cm->klass->rank;
831 lengths [0] = length1;
832 lengths [1] = length2;
833 lengths [2] = length3;
834 lengths [3] = length4;
836 g_assert (rank == pcount);
838 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
839 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
840 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
845 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
847 if (!mono_error_ok (&error)) {
848 mono_error_set_pending_exception (&error);
856 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
861 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
863 mono_class_init (field->parent);
865 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
866 if (!vtable->initialized)
867 mono_runtime_class_init (vtable);
869 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
871 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
872 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
874 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
880 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
883 MonoClass *handle_class;
886 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
887 if (!mono_error_ok (&error)) {
888 mono_error_set_pending_exception (&error);
891 mono_class_init (handle_class);
897 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
899 MonoMethodSignature *sig = mono_method_signature (method);
900 MonoGenericContext *generic_context;
902 if (sig->is_inflated) {
903 generic_context = mono_method_get_context (method);
905 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
906 g_assert (generic_container);
907 generic_context = &generic_container->context;
910 return mono_ldtoken_wrapper (image, token, generic_context);
914 mono_fconv_u8 (double v)
920 mono_rconv_u8 (float v)
925 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
927 mono_fconv_i8 (double v)
934 mono_fconv_u4 (double v)
936 /* MS.NET behaves like this for some reason */
938 if (isinf (v) || isnan (v))
946 /* Solaris doesn't have trunc */
948 extern long double aintl (long double);
951 /* FIXME: This means we will never throw overflow exceptions */
954 #endif /* HAVE_TRUNC */
957 mono_fconv_ovf_i8 (double v)
963 if (isnan(v) || trunc (v) != res) {
964 mono_set_pending_exception (mono_get_exception_overflow ());
971 mono_fconv_ovf_u8 (double v)
976 * The soft-float implementation of some ARM devices have a buggy guin64 to double
977 * conversion that it looses precision even when the integer if fully representable
980 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
982 * To work around this issue we test for value boundaries instead.
984 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
985 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
986 mono_set_pending_exception (mono_get_exception_overflow ());
992 if (isnan(v) || trunc (v) != res) {
993 mono_set_pending_exception (mono_get_exception_overflow ());
1000 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1002 mono_rconv_i8 (float v)
1009 mono_rconv_ovf_i8 (float v)
1015 if (isnan(v) || trunc (v) != res) {
1016 mono_set_pending_exception (mono_get_exception_overflow ());
1023 mono_rconv_ovf_u8 (float v)
1028 if (isnan(v) || trunc (v) != res) {
1029 mono_set_pending_exception (mono_get_exception_overflow ());
1035 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1037 mono_lconv_to_r8 (gint64 a)
1043 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1045 mono_lconv_to_r4 (gint64 a)
1051 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1053 mono_conv_to_r8_un (guint32 a)
1059 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1061 mono_lconv_to_r8_un (guint64 a)
1067 #if defined(__native_client_codegen__) || defined(__native_client__)
1068 /* When we cross-compile to Native Client we can't directly embed calls */
1069 /* to the math library on the host. This will use the fmod on the target*/
1071 mono_fmod(double a, double b)
1078 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1080 MonoMethod *vmethod;
1082 MonoGenericContext *context = mono_method_get_context (method);
1084 mono_jit_stats.generic_virtual_invocations++;
1087 mono_set_pending_exception (mono_get_exception_null_reference ());
1090 vmethod = mono_object_get_virtual_method (obj, method);
1091 g_assert (!vmethod->klass->generic_container);
1092 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1093 g_assert (!context->method_inst || !context->method_inst->is_open);
1095 addr = mono_compile_method (vmethod);
1097 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1099 /* Since this is a virtual call, have to unbox vtypes */
1100 if (obj->vtable->klass->valuetype)
1101 *this_arg = mono_object_unbox (obj);
1109 mono_helper_ldstr (MonoImage *image, guint32 idx)
1111 return mono_ldstr (mono_domain_get (), image, idx);
1115 mono_helper_ldstr_mscorlib (guint32 idx)
1117 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1121 mono_helper_newobj_mscorlib (guint32 idx)
1124 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1126 if (!mono_error_ok (&error)) {
1127 mono_error_set_pending_exception (&error);
1131 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1132 if (!mono_error_ok (&error))
1133 mono_error_set_pending_exception (&error);
1138 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1139 * in generated code. So instead we emit a call to this function and place a gdb
1148 mono_create_corlib_exception_0 (guint32 token)
1150 return mono_exception_from_token (mono_defaults.corlib, token);
1154 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1156 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1160 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1162 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1166 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1168 MonoJitTlsData *jit_tls = NULL;
1171 if (mini_get_debug_options ()->better_cast_details) {
1172 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1173 jit_tls->class_cast_from = NULL;
1179 oklass = obj->vtable->klass;
1180 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1182 if (mono_object_isinst (obj, klass))
1185 if (mini_get_debug_options ()->better_cast_details) {
1186 jit_tls->class_cast_from = oklass;
1187 jit_tls->class_cast_to = klass;
1190 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1191 "System", "InvalidCastException"));
1197 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1199 MonoJitTlsData *jit_tls = NULL;
1200 gpointer cached_vtable, obj_vtable;
1202 if (mini_get_debug_options ()->better_cast_details) {
1203 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1204 jit_tls->class_cast_from = NULL;
1210 cached_vtable = *cache;
1211 obj_vtable = obj->vtable;
1213 if (cached_vtable == obj_vtable)
1216 if (mono_object_isinst (obj, klass)) {
1217 *cache = obj_vtable;
1221 if (mini_get_debug_options ()->better_cast_details) {
1222 jit_tls->class_cast_from = obj->vtable->klass;
1223 jit_tls->class_cast_to = klass;
1226 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1227 "System", "InvalidCastException"));
1233 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1235 size_t cached_vtable, obj_vtable;
1240 cached_vtable = (size_t)*cache;
1241 obj_vtable = (size_t)obj->vtable;
1243 if ((cached_vtable & ~0x1) == obj_vtable) {
1244 return (cached_vtable & 0x1) ? NULL : obj;
1247 if (mono_object_isinst (obj, klass)) {
1248 *cache = (gpointer)obj_vtable;
1252 *cache = (gpointer)(obj_vtable | 0x1);
1258 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1260 MonoMarshalSpec **mspecs;
1261 MonoMethodPInvoke piinfo;
1264 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1265 memset (&piinfo, 0, sizeof (piinfo));
1267 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1269 return mono_compile_method (m);
1273 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1276 int vt_slot, iface_offset;
1278 mono_error_init (error);
1280 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1281 MonoObject *this_obj;
1283 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1284 this_obj = *(MonoObject**)mp;
1285 g_assert (this_obj);
1287 klass = this_obj->vtable->klass;
1290 if (mono_method_signature (cmethod)->pinvoke) {
1291 /* Object.GetType () */
1292 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1294 /* Lookup the virtual method */
1295 mono_class_setup_vtable (klass);
1296 g_assert (klass->vtable);
1297 vt_slot = mono_method_get_vtable_slot (cmethod);
1298 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1299 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1300 g_assert (iface_offset != -1);
1301 vt_slot += iface_offset;
1303 m = klass->vtable [vt_slot];
1304 if (cmethod->is_inflated)
1305 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1308 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1310 * Calling a non-vtype method with a vtype receiver, has to box.
1312 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1313 else if (klass->valuetype)
1315 * Calling a vtype method with a vtype receiver
1320 * Calling a non-vtype method
1322 *this_arg = *(gpointer*)mp;
1327 * mono_gsharedvt_constrained_call:
1329 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1330 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1333 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1339 gpointer new_args [16];
1341 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1342 if (!mono_error_ok (&error)) {
1343 mono_error_set_pending_exception (&error);
1349 if (args && deref_arg) {
1350 new_args [0] = *(gpointer*)args [0];
1353 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1354 /* Object.GetType () */
1356 args [0] = this_arg;
1360 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1361 if (!mono_error_ok (&error)) {
1362 mono_error_set_pending_exception (&error);
1370 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1372 if (klass->valuetype)
1373 mono_value_copy (dest, src, klass);
1375 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1379 mono_generic_class_init (MonoVTable *vtable)
1381 mono_runtime_class_init (vtable);
1385 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1390 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1391 if (!mono_error_ok (&error)) {
1392 mono_error_set_pending_exception (&error);
1399 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1404 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1405 if (!mono_error_ok (&error)) {
1406 mono_error_set_pending_exception (&error);
1413 * resolve_iface_call:
1415 * Return the executable code for the iface method IMT_METHOD called on THIS.
1416 * This function is called on a slowpath, so it doesn't need to be fast.
1417 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1421 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1424 gpointer *imt, *vtable_slot;
1425 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1426 gpointer addr, compiled_method, aot_addr;
1427 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1430 /* The caller will handle it */
1433 vt = this_obj->vtable;
1434 imt = (gpointer*)vt - MONO_IMT_SIZE;
1436 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1438 // FIXME: This can throw exceptions
1439 addr = compiled_method = mono_compile_method (impl_method);
1442 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1443 generic_virtual = imt_method;
1445 if (generic_virtual || variant_iface) {
1446 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1447 need_unbox_tramp = TRUE;
1449 if (impl_method->klass->valuetype)
1450 need_unbox_tramp = TRUE;
1453 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1455 if (generic_virtual || variant_iface) {
1456 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1458 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1467 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1469 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1473 is_generic_method_definition (MonoMethod *m)
1475 MonoGenericContext *context;
1478 if (!m->is_inflated)
1481 context = mono_method_get_context (m);
1482 if (!context->method_inst)
1484 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1492 * Return the executable code for calling vt->vtable [slot].
1493 * This function is called on a slowpath, so it doesn't need to be fast.
1494 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1498 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1500 MonoMethod *m, *generic_virtual = NULL;
1501 gpointer addr, compiled_method;
1502 gboolean need_unbox_tramp = FALSE;
1504 /* Same as in common_call_trampoline () */
1506 /* Avoid loading metadata or creating a generic vtable if possible */
1507 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1508 if (addr && !vt->klass->valuetype)
1509 return mono_create_ftnptr (mono_domain_get (), addr);
1511 m = mono_class_get_vtable_entry (vt->klass, slot);
1513 if (is_generic_method_definition (m)) {
1515 MonoGenericContext context = { NULL, NULL };
1516 MonoMethod *declaring;
1519 declaring = mono_method_get_declaring_generic_method (m);
1523 if (m->klass->generic_class)
1524 context.class_inst = m->klass->generic_class->context.class_inst;
1526 g_assert (!m->klass->generic_container);
1528 generic_virtual = imt_method;
1529 g_assert (generic_virtual);
1530 g_assert (generic_virtual->is_inflated);
1531 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1533 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1534 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1537 if (generic_virtual) {
1538 if (vt->klass->valuetype)
1539 need_unbox_tramp = TRUE;
1541 if (m->klass->valuetype)
1542 need_unbox_tramp = TRUE;
1545 // FIXME: This can throw exceptions
1546 addr = compiled_method = mono_compile_method (m);
1549 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1551 if (!gsharedvt && generic_virtual) {
1552 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1553 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1555 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1556 vt, vt->vtable + slot,
1557 generic_virtual, ftndesc);
1564 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1566 g_assert (this_obj);
1568 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1572 * mono_resolve_generic_virtual_call:
1574 * Resolve a generic virtual call.
1575 * This function is called on a slowpath, so it doesn't need to be fast.
1578 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1581 gpointer addr, compiled_method;
1582 gboolean need_unbox_tramp = FALSE;
1584 MonoGenericContext context = { NULL, NULL };
1585 MonoMethod *declaring;
1586 gpointer arg = NULL;
1588 m = mono_class_get_vtable_entry (vt->klass, slot);
1590 g_assert (is_generic_method_definition (m));
1593 declaring = mono_method_get_declaring_generic_method (m);
1597 if (m->klass->generic_class)
1598 context.class_inst = m->klass->generic_class->context.class_inst;
1600 g_assert (!m->klass->generic_container);
1602 g_assert (generic_virtual->is_inflated);
1603 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1605 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1606 g_assert (mono_error_ok (&error));
1608 if (vt->klass->valuetype)
1609 need_unbox_tramp = TRUE;
1611 // FIXME: This can throw exceptions
1612 addr = compiled_method = mono_compile_method (m);
1615 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1618 * This wastes memory but the memory usage is bounded since
1619 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1620 * this vtable slot so we are not called any more for this instantiation.
1622 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1624 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1625 vt, vt->vtable + slot,
1626 generic_virtual, ftndesc);
1631 * mono_resolve_generic_virtual_call:
1633 * Resolve a generic virtual/variant iface call on interfaces.
1634 * This function is called on a slowpath, so it doesn't need to be fast.
1637 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1639 MonoMethod *m, *variant_iface;
1640 gpointer addr, aot_addr, compiled_method;
1641 gboolean need_unbox_tramp = FALSE;
1642 gboolean need_rgctx_tramp;
1643 gpointer arg = NULL;
1646 imt = (gpointer*)vt - MONO_IMT_SIZE;
1648 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1650 if (vt->klass->valuetype)
1651 need_unbox_tramp = TRUE;
1653 // FIXME: This can throw exceptions
1654 addr = compiled_method = mono_compile_method (m);
1657 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1660 * This wastes memory but the memory usage is bounded since
1661 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1662 * this vtable slot so we are not called any more for this instantiation.
1664 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1666 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1668 variant_iface ? variant_iface : generic_virtual, ftndesc);
1673 * mono_init_vtable_slot:
1675 * Initialize slot SLOT of VTABLE.
1676 * Return the contents of the vtable slot.
1679 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1681 gpointer arg = NULL;
1685 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1686 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1689 mono_memory_barrier ();
1691 vtable->vtable [slot] = ftnptr;
1697 * mono_llvmonly_init_delegate:
1699 * Initialize a MonoDelegate object.
1700 * Similar to mono_delegate_ctor ().
1703 mono_llvmonly_init_delegate (MonoDelegate *del)
1705 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1708 * We store a MonoFtnDesc in del->method_code.
1709 * It would be better to store an ftndesc in del->method_ptr too,
1710 * but we don't have a a structure which could own its memory.
1712 if (G_UNLIKELY (!ftndesc)) {
1713 gpointer addr = mono_compile_method (del->method);
1715 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1716 addr = mono_aot_get_unbox_trampoline (del->method);
1718 gpointer arg = mini_get_delegate_arg (del->method, addr);
1720 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1721 mono_memory_barrier ();
1722 *del->method_code = (gpointer)ftndesc;
1724 del->method_ptr = ftndesc->addr;
1725 del->extra_arg = ftndesc->arg;
1729 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1733 method = mono_object_get_virtual_method (target, method);
1735 del->method = method;
1736 del->method_ptr = mono_compile_method (method);
1737 if (method->klass->valuetype)
1738 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1739 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1743 mono_get_assembly_object (MonoImage *image)
1747 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1749 mono_error_set_pending_exception (&error);
1754 mono_get_method_object (MonoMethod *method)
1757 MonoObject * result;
1758 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1759 mono_error_set_pending_exception (&error);
1764 mono_ckfinite (double d)
1766 if (isinf (d) || isnan (d))
1767 mono_set_pending_exception (mono_get_exception_arithmetic ());
1772 * mono_interruption_checkpoint_from_trampoline:
1774 * Check whenever the thread has a pending exception, and throw it
1776 * Architectures should move away from calling this function and
1777 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1778 * rewrind to the parent frame, and throw the exception normally.
1781 mono_interruption_checkpoint_from_trampoline (void)
1785 ex = mono_thread_force_interruption_checkpoint_noraise ();
1787 mono_raise_exception (ex);