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>
24 #include "mini-llvm-cpp.h"
28 mono_ldftn (MonoMethod *method)
33 // FIXME: No error handling
35 addr = mono_compile_method (method);
38 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
39 /* The caller doesn't pass it */
40 g_assert_not_reached ();
42 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
46 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
48 return mono_create_ftnptr (mono_domain_get (), addr);
52 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
58 mono_set_pending_exception (mono_get_exception_null_reference ());
62 res = mono_object_get_virtual_method (obj, method);
64 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
65 MonoGenericContext context = { NULL, NULL };
67 if (res->klass->generic_class)
68 context.class_inst = res->klass->generic_class->context.class_inst;
69 else if (res->klass->generic_container)
70 context.class_inst = res->klass->generic_container->context.class_inst;
71 context.method_inst = mono_method_get_context (method)->method_inst;
73 res = mono_class_inflate_generic_method_checked (res, &context, &error);
74 if (!mono_error_ok (&error)) {
75 mono_error_set_pending_exception (&error);
80 /* An rgctx wrapper is added by the trampolines no need to do it here */
82 return mono_ldftn (res);
86 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
88 return ldvirtfn_internal (obj, method, FALSE);
92 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
94 return ldvirtfn_internal (obj, method, TRUE);
98 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
101 mono_set_pending_exception (mono_get_exception_null_reference ());
104 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
105 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
110 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
113 mono_llmult (gint64 a, gint64 b)
119 mono_llmult_ovf_un (guint64 a, guint64 b)
122 guint32 ah = a >> 32;
124 guint32 bh = b >> 32;
127 // fixme: this is incredible slow
130 goto raise_exception;
132 res = (guint64)al * (guint64)bl;
134 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
137 goto raise_exception;
139 res += ((guint64)t1) << 32;
144 mono_set_pending_exception (mono_get_exception_overflow ());
149 mono_llmult_ovf (gint64 a, gint64 b)
156 Use Karatsuba algorithm where:
157 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
158 where Ah is the "high half" (most significant 32 bits) of a and
159 where Al is the "low half" (least significant 32 bits) of a and
160 where Bh is the "high half" of b and Bl is the "low half" and
161 where R is the Radix or "size of the half" (in our case 32 bits)
163 Note, for the product of two 64 bit numbers to fit into a 64
164 result, ah and/or bh must be 0. This will save us from doing
165 the AhBh term at all.
167 Also note that we refactor so that we don't overflow 64 bits with
168 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
174 /* need to work with absoulte values, so find out what the
175 resulting sign will be and convert any negative numbers
176 from two's complement
180 if (((guint32)ah == 0x80000000) && (al == 0)) {
181 /* This has no two's complement */
187 goto raise_exception;
190 /* flip the bits and add 1 */
201 if (((guint32)bh == 0x80000000) && (bl == 0)) {
202 /* This has no two's complement */
208 goto raise_exception;
211 /* flip the bits and add 1 */
221 /* we overflow for sure if both upper halves are greater
222 than zero because we would need to shift their
223 product 64 bits to the left and that will not fit
224 in a 64 bit result */
226 goto raise_exception;
227 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
228 goto raise_exception;
230 /* do the AlBl term first */
231 t1 = (gint64)al * (gint64)bl;
235 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
236 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
237 /* check for overflow */
239 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
240 goto raise_exception;
245 goto raise_exception;
253 mono_set_pending_exception (mono_get_exception_overflow ());
258 mono_lldiv (gint64 a, gint64 b)
260 #ifdef MONO_ARCH_NEED_DIV_CHECK
262 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
265 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
266 mono_set_pending_exception (mono_get_exception_arithmetic ());
274 mono_llrem (gint64 a, gint64 b)
276 #ifdef MONO_ARCH_NEED_DIV_CHECK
278 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
281 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
282 mono_set_pending_exception (mono_get_exception_arithmetic ());
290 mono_lldiv_un (guint64 a, guint64 b)
292 #ifdef MONO_ARCH_NEED_DIV_CHECK
294 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
302 mono_llrem_un (guint64 a, guint64 b)
304 #ifdef MONO_ARCH_NEED_DIV_CHECK
306 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
315 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
318 mono_lshl (guint64 a, gint32 shamt)
322 res = a << (shamt & 0x7f);
324 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
330 mono_lshr_un (guint64 a, gint32 shamt)
334 res = a >> (shamt & 0x7f);
336 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
342 mono_lshr (gint64 a, gint32 shamt)
346 res = a >> (shamt & 0x7f);
348 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
355 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
358 mono_idiv (gint32 a, gint32 b)
360 #ifdef MONO_ARCH_NEED_DIV_CHECK
362 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
365 else if (b == -1 && a == (0x80000000)) {
366 mono_set_pending_exception (mono_get_exception_overflow ());
374 mono_idiv_un (guint32 a, guint32 b)
376 #ifdef MONO_ARCH_NEED_DIV_CHECK
378 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
386 mono_irem (gint32 a, gint32 b)
388 #ifdef MONO_ARCH_NEED_DIV_CHECK
390 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
393 else if (b == -1 && a == (0x80000000)) {
394 mono_set_pending_exception (mono_get_exception_overflow ());
402 mono_irem_un (guint32 a, guint32 b)
404 #ifdef MONO_ARCH_NEED_DIV_CHECK
406 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
415 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
418 mono_imul (gint32 a, gint32 b)
424 mono_imul_ovf (gint32 a, gint32 b)
428 res = (gint64)a * (gint64)b;
430 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
431 mono_set_pending_exception (mono_get_exception_overflow ());
439 mono_imul_ovf_un (guint32 a, guint32 b)
443 res = (guint64)a * (guint64)b;
446 mono_set_pending_exception (mono_get_exception_overflow ());
454 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
456 mono_fdiv (double a, double b)
462 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
465 mono_fsub (double a, double b)
471 mono_fadd (double a, double b)
477 mono_fmul (double a, double b)
489 mono_fconv_r4 (double a)
495 mono_conv_to_r8 (int a)
501 mono_conv_to_r4 (int a)
503 return (double)(float)a;
507 mono_fconv_i1 (double a)
513 mono_fconv_i2 (double a)
519 mono_fconv_i4 (double a)
525 mono_fconv_u1 (double a)
531 mono_fconv_u2 (double a)
537 mono_fcmp_eq (double a, double b)
543 mono_fcmp_ge (double a, double b)
549 mono_fcmp_gt (double a, double b)
555 mono_fcmp_le (double a, double b)
561 mono_fcmp_lt (double a, double b)
567 mono_fcmp_ne_un (double a, double b)
569 return isunordered (a, b) || a != b;
573 mono_fcmp_ge_un (double a, double b)
575 return isunordered (a, b) || a >= b;
579 mono_fcmp_gt_un (double a, double b)
581 return isunordered (a, b) || a > b;
585 mono_fcmp_le_un (double a, double b)
587 return isunordered (a, b) || a <= b;
591 mono_fcmp_lt_un (double a, double b)
593 return isunordered (a, b) || a < b;
597 mono_fceq (double a, double b)
603 mono_fcgt (double a, double b)
609 mono_fcgt_un (double a, double b)
611 return isunordered (a, b) || a > b;
615 mono_fclt (double a, double b)
621 mono_fclt_un (double a, double b)
623 return isunordered (a, b) || a < b;
627 mono_isfinite (double a)
632 g_assert_not_reached ();
638 mono_fload_r4 (float *ptr)
644 mono_fstore_r4 (double val, float *ptr)
649 /* returns the integer bitpattern that is passed in the regs or stack */
651 mono_fload_r4_arg (double val)
653 float v = (float)val;
654 return *(guint32*)&v;
660 mono_array_new_va (MonoMethod *cm, ...)
664 MonoDomain *domain = mono_domain_get ();
667 intptr_t *lower_bounds;
672 pcount = mono_method_signature (cm)->param_count;
673 rank = cm->klass->rank;
677 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
678 for (i = 0; i < pcount; ++i)
679 lengths [i] = d = va_arg(ap, int);
681 if (rank == pcount) {
682 /* Only lengths provided. */
683 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
684 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
685 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
690 g_assert (pcount == (rank * 2));
691 /* lower bounds are first. */
692 lower_bounds = (intptr_t*)lengths;
697 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
699 if (!mono_error_ok (&error)) {
700 mono_error_set_pending_exception (&error);
707 /* Specialized version of mono_array_new_va () which avoids varargs */
709 mono_array_new_1 (MonoMethod *cm, guint32 length)
713 MonoDomain *domain = mono_domain_get ();
714 uintptr_t lengths [1];
715 intptr_t *lower_bounds;
719 pcount = mono_method_signature (cm)->param_count;
720 rank = cm->klass->rank;
722 lengths [0] = length;
724 g_assert (rank == pcount);
726 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
727 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
728 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
733 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
735 if (!mono_error_ok (&error)) {
736 mono_error_set_pending_exception (&error);
744 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
748 MonoDomain *domain = mono_domain_get ();
749 uintptr_t lengths [2];
750 intptr_t *lower_bounds;
754 pcount = mono_method_signature (cm)->param_count;
755 rank = cm->klass->rank;
757 lengths [0] = length1;
758 lengths [1] = length2;
760 g_assert (rank == pcount);
762 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
763 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
764 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
769 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
771 if (!mono_error_ok (&error)) {
772 mono_error_set_pending_exception (&error);
780 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
784 MonoDomain *domain = mono_domain_get ();
785 uintptr_t lengths [3];
786 intptr_t *lower_bounds;
790 pcount = mono_method_signature (cm)->param_count;
791 rank = cm->klass->rank;
793 lengths [0] = length1;
794 lengths [1] = length2;
795 lengths [2] = length3;
797 g_assert (rank == pcount);
799 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
800 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
801 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
806 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
808 if (!mono_error_ok (&error)) {
809 mono_error_set_pending_exception (&error);
817 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
821 MonoDomain *domain = mono_domain_get ();
822 uintptr_t lengths [4];
823 intptr_t *lower_bounds;
827 pcount = mono_method_signature (cm)->param_count;
828 rank = cm->klass->rank;
830 lengths [0] = length1;
831 lengths [1] = length2;
832 lengths [2] = length3;
833 lengths [3] = length4;
835 g_assert (rank == pcount);
837 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
838 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
839 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
844 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
846 if (!mono_error_ok (&error)) {
847 mono_error_set_pending_exception (&error);
855 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
860 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
862 mono_class_init (field->parent);
864 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
865 if (!vtable->initialized)
866 mono_runtime_class_init (vtable);
868 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
870 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
871 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
873 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
879 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
882 MonoClass *handle_class;
885 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
886 if (!mono_error_ok (&error)) {
887 mono_error_set_pending_exception (&error);
890 mono_class_init (handle_class);
896 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
898 MonoMethodSignature *sig = mono_method_signature (method);
899 MonoGenericContext *generic_context;
901 if (sig->is_inflated) {
902 generic_context = mono_method_get_context (method);
904 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
905 g_assert (generic_container);
906 generic_context = &generic_container->context;
909 return mono_ldtoken_wrapper (image, token, generic_context);
913 mono_fconv_u8 (double v)
919 mono_rconv_u8 (float v)
924 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
926 mono_fconv_i8 (double v)
933 mono_fconv_u4 (double v)
935 /* MS.NET behaves like this for some reason */
937 if (isinf (v) || isnan (v))
945 /* Solaris doesn't have trunc */
947 extern long double aintl (long double);
950 /* FIXME: This means we will never throw overflow exceptions */
953 #endif /* HAVE_TRUNC */
956 mono_fconv_ovf_i8 (double v)
962 if (isnan(v) || trunc (v) != res) {
963 mono_set_pending_exception (mono_get_exception_overflow ());
970 mono_fconv_ovf_u8 (double v)
975 * The soft-float implementation of some ARM devices have a buggy guin64 to double
976 * conversion that it looses precision even when the integer if fully representable
979 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
981 * To work around this issue we test for value boundaries instead.
983 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
984 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
985 mono_set_pending_exception (mono_get_exception_overflow ());
991 if (isnan(v) || trunc (v) != res) {
992 mono_set_pending_exception (mono_get_exception_overflow ());
999 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1001 mono_rconv_i8 (float v)
1008 mono_rconv_ovf_i8 (float v)
1014 if (isnan(v) || trunc (v) != res) {
1015 mono_set_pending_exception (mono_get_exception_overflow ());
1022 mono_rconv_ovf_u8 (float v)
1027 if (isnan(v) || trunc (v) != res) {
1028 mono_set_pending_exception (mono_get_exception_overflow ());
1034 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1036 mono_lconv_to_r8 (gint64 a)
1042 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1044 mono_lconv_to_r4 (gint64 a)
1050 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1052 mono_conv_to_r8_un (guint32 a)
1058 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1060 mono_lconv_to_r8_un (guint64 a)
1066 #if defined(__native_client_codegen__) || defined(__native_client__)
1067 /* When we cross-compile to Native Client we can't directly embed calls */
1068 /* to the math library on the host. This will use the fmod on the target*/
1070 mono_fmod(double a, double b)
1077 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1079 MonoMethod *vmethod;
1081 MonoGenericContext *context = mono_method_get_context (method);
1083 mono_jit_stats.generic_virtual_invocations++;
1086 mono_set_pending_exception (mono_get_exception_null_reference ());
1089 vmethod = mono_object_get_virtual_method (obj, method);
1090 g_assert (!vmethod->klass->generic_container);
1091 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1092 g_assert (!context->method_inst || !context->method_inst->is_open);
1094 addr = mono_compile_method (vmethod);
1096 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1098 /* Since this is a virtual call, have to unbox vtypes */
1099 if (obj->vtable->klass->valuetype)
1100 *this_arg = mono_object_unbox (obj);
1108 mono_helper_ldstr (MonoImage *image, guint32 idx)
1110 return mono_ldstr (mono_domain_get (), image, idx);
1114 mono_helper_ldstr_mscorlib (guint32 idx)
1116 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1120 mono_helper_newobj_mscorlib (guint32 idx)
1123 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1125 if (!mono_error_ok (&error)) {
1126 mono_error_set_pending_exception (&error);
1130 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1131 if (!mono_error_ok (&error))
1132 mono_error_set_pending_exception (&error);
1137 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1138 * in generated code. So instead we emit a call to this function and place a gdb
1147 mono_create_corlib_exception_0 (guint32 token)
1149 return mono_exception_from_token (mono_defaults.corlib, token);
1153 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1155 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1159 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1161 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1165 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1167 MonoJitTlsData *jit_tls = NULL;
1170 if (mini_get_debug_options ()->better_cast_details) {
1171 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1172 jit_tls->class_cast_from = NULL;
1178 oklass = obj->vtable->klass;
1179 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1181 if (mono_object_isinst (obj, klass))
1184 if (mini_get_debug_options ()->better_cast_details) {
1185 jit_tls->class_cast_from = oklass;
1186 jit_tls->class_cast_to = klass;
1189 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1190 "System", "InvalidCastException"));
1196 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1198 MonoJitTlsData *jit_tls = NULL;
1199 gpointer cached_vtable, obj_vtable;
1201 if (mini_get_debug_options ()->better_cast_details) {
1202 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1203 jit_tls->class_cast_from = NULL;
1209 cached_vtable = *cache;
1210 obj_vtable = obj->vtable;
1212 if (cached_vtable == obj_vtable)
1215 if (mono_object_isinst (obj, klass)) {
1216 *cache = obj_vtable;
1220 if (mini_get_debug_options ()->better_cast_details) {
1221 jit_tls->class_cast_from = obj->vtable->klass;
1222 jit_tls->class_cast_to = klass;
1225 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1226 "System", "InvalidCastException"));
1232 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1234 size_t cached_vtable, obj_vtable;
1239 cached_vtable = (size_t)*cache;
1240 obj_vtable = (size_t)obj->vtable;
1242 if ((cached_vtable & ~0x1) == obj_vtable) {
1243 return (cached_vtable & 0x1) ? NULL : obj;
1246 if (mono_object_isinst (obj, klass)) {
1247 *cache = (gpointer)obj_vtable;
1251 *cache = (gpointer)(obj_vtable | 0x1);
1257 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1259 MonoMarshalSpec **mspecs;
1260 MonoMethodPInvoke piinfo;
1263 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1264 memset (&piinfo, 0, sizeof (piinfo));
1266 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1268 return mono_compile_method (m);
1272 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1275 int vt_slot, iface_offset;
1277 mono_error_init (error);
1279 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1280 MonoObject *this_obj;
1282 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1283 this_obj = *(MonoObject**)mp;
1284 g_assert (this_obj);
1286 klass = this_obj->vtable->klass;
1289 if (mono_method_signature (cmethod)->pinvoke) {
1290 /* Object.GetType () */
1291 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1293 /* Lookup the virtual method */
1294 mono_class_setup_vtable (klass);
1295 g_assert (klass->vtable);
1296 vt_slot = mono_method_get_vtable_slot (cmethod);
1297 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1298 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1299 g_assert (iface_offset != -1);
1300 vt_slot += iface_offset;
1302 m = klass->vtable [vt_slot];
1303 if (cmethod->is_inflated)
1304 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1307 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1309 * Calling a non-vtype method with a vtype receiver, has to box.
1311 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1312 else if (klass->valuetype)
1314 * Calling a vtype method with a vtype receiver
1319 * Calling a non-vtype method
1321 *this_arg = *(gpointer*)mp;
1326 * mono_gsharedvt_constrained_call:
1328 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1329 * the arguments to the method in the format used by mono_runtime_invoke ().
1332 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1337 gpointer new_args [16];
1339 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1340 if (!mono_error_ok (&error)) {
1341 mono_error_set_pending_exception (&error);
1347 if (args && deref_arg) {
1348 new_args [0] = *(gpointer*)args [0];
1351 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1352 /* Object.GetType () */
1354 args [0] = this_arg;
1357 return mono_runtime_invoke (m, this_arg, args, NULL);
1361 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1363 if (klass->valuetype)
1364 mono_value_copy (dest, src, klass);
1366 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1370 mono_generic_class_init (MonoVTable *vtable)
1372 mono_runtime_class_init (vtable);
1376 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1381 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1382 if (!mono_error_ok (&error)) {
1383 mono_error_set_pending_exception (&error);
1390 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1395 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1396 if (!mono_error_ok (&error)) {
1397 mono_error_set_pending_exception (&error);
1404 * resolve_iface_call:
1406 * Return the executable code for the iface method IMT_METHOD called on THIS.
1407 * This function is called on a slowpath, so it doesn't need to be fast.
1408 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1412 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1415 gpointer *imt, *vtable_slot;
1416 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1417 gpointer addr, compiled_method, aot_addr;
1418 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1421 /* The caller will handle it */
1424 vt = this_obj->vtable;
1425 imt = (gpointer*)vt - MONO_IMT_SIZE;
1427 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1429 // FIXME: This can throw exceptions
1430 addr = compiled_method = mono_compile_method (impl_method);
1433 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1434 generic_virtual = imt_method;
1436 if (generic_virtual || variant_iface) {
1437 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1438 need_unbox_tramp = TRUE;
1440 if (impl_method->klass->valuetype)
1441 need_unbox_tramp = TRUE;
1444 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1446 if (generic_virtual || variant_iface) {
1447 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1449 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1458 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1460 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1464 is_generic_method_definition (MonoMethod *m)
1466 MonoGenericContext *context;
1469 if (!m->is_inflated)
1472 context = mono_method_get_context (m);
1473 if (!context->method_inst)
1475 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1483 * Return the executable code for calling vt->vtable [slot].
1484 * This function is called on a slowpath, so it doesn't need to be fast.
1485 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1489 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1491 MonoMethod *m, *generic_virtual = NULL;
1492 gpointer addr, compiled_method;
1493 gboolean need_unbox_tramp = FALSE;
1495 /* Same as in common_call_trampoline () */
1497 /* Avoid loading metadata or creating a generic vtable if possible */
1498 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1499 if (addr && !vt->klass->valuetype)
1500 return mono_create_ftnptr (mono_domain_get (), addr);
1502 m = mono_class_get_vtable_entry (vt->klass, slot);
1504 if (is_generic_method_definition (m)) {
1506 MonoGenericContext context = { NULL, NULL };
1507 MonoMethod *declaring;
1510 declaring = mono_method_get_declaring_generic_method (m);
1514 if (m->klass->generic_class)
1515 context.class_inst = m->klass->generic_class->context.class_inst;
1517 g_assert (!m->klass->generic_container);
1519 generic_virtual = imt_method;
1520 g_assert (generic_virtual);
1521 g_assert (generic_virtual->is_inflated);
1522 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1524 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1525 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1528 if (generic_virtual) {
1529 if (vt->klass->valuetype)
1530 need_unbox_tramp = TRUE;
1532 if (m->klass->valuetype)
1533 need_unbox_tramp = TRUE;
1536 // FIXME: This can throw exceptions
1537 addr = compiled_method = mono_compile_method (m);
1540 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1542 if (!gsharedvt && generic_virtual) {
1543 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1544 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1546 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1547 vt, vt->vtable + slot,
1548 generic_virtual, ftndesc);
1555 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1557 g_assert (this_obj);
1559 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1563 * mono_resolve_generic_virtual_call:
1565 * Resolve a generic virtual call.
1566 * This function is called on a slowpath, so it doesn't need to be fast.
1569 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1572 gpointer addr, compiled_method;
1573 gboolean need_unbox_tramp = FALSE;
1575 MonoGenericContext context = { NULL, NULL };
1576 MonoMethod *declaring;
1577 gpointer arg = NULL;
1579 m = mono_class_get_vtable_entry (vt->klass, slot);
1581 g_assert (is_generic_method_definition (m));
1584 declaring = mono_method_get_declaring_generic_method (m);
1588 if (m->klass->generic_class)
1589 context.class_inst = m->klass->generic_class->context.class_inst;
1591 g_assert (!m->klass->generic_container);
1593 g_assert (generic_virtual->is_inflated);
1594 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1596 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1597 g_assert (mono_error_ok (&error));
1599 if (vt->klass->valuetype)
1600 need_unbox_tramp = TRUE;
1602 // FIXME: This can throw exceptions
1603 addr = compiled_method = mono_compile_method (m);
1606 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1609 * This wastes memory but the memory usage is bounded since
1610 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1611 * this vtable slot so we are not called any more for this instantiation.
1613 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1615 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1616 vt, vt->vtable + slot,
1617 generic_virtual, ftndesc);
1622 * mono_resolve_generic_virtual_call:
1624 * Resolve a generic virtual/variant iface call on interfaces.
1625 * This function is called on a slowpath, so it doesn't need to be fast.
1628 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1630 MonoMethod *m, *variant_iface;
1631 gpointer addr, aot_addr, compiled_method;
1632 gboolean need_unbox_tramp = FALSE;
1633 gboolean need_rgctx_tramp;
1634 gpointer arg = NULL;
1637 imt = (gpointer*)vt - MONO_IMT_SIZE;
1639 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1641 if (vt->klass->valuetype)
1642 need_unbox_tramp = TRUE;
1644 // FIXME: This can throw exceptions
1645 addr = compiled_method = mono_compile_method (m);
1648 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1651 * This wastes memory but the memory usage is bounded since
1652 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1653 * this vtable slot so we are not called any more for this instantiation.
1655 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1657 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1659 variant_iface ? variant_iface : generic_virtual, ftndesc);
1664 * mono_init_vtable_slot:
1666 * Initialize slot SLOT of VTABLE.
1667 * Return the contents of the vtable slot.
1670 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1672 gpointer arg = NULL;
1676 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1677 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1680 mono_memory_barrier ();
1682 vtable->vtable [slot] = ftnptr;
1688 * mono_llvmonly_init_delegate:
1690 * Initialize a MonoDelegate object.
1691 * Similar to mono_delegate_ctor ().
1694 mono_llvmonly_init_delegate (MonoDelegate *del)
1696 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1699 * We store a MonoFtnDesc in del->method_code.
1700 * It would be better to store an ftndesc in del->method_ptr too,
1701 * but we don't have a a structure which could own its memory.
1703 if (G_UNLIKELY (!ftndesc)) {
1704 gpointer addr = mono_compile_method (del->method);
1705 gpointer arg = mini_get_delegate_arg (del->method, addr);
1707 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1708 mono_memory_barrier ();
1709 *del->method_code = (gpointer)ftndesc;
1711 del->method_ptr = ftndesc->addr;
1712 del->extra_arg = ftndesc->arg;
1716 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1720 method = mono_object_get_virtual_method (target, method);
1722 del->method = method;
1723 del->method_ptr = mono_compile_method (method);
1724 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1728 mono_get_assembly_object (MonoImage *image)
1730 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1734 mono_get_method_object (MonoMethod *method)
1736 return (MonoObject*)mono_method_get_object (mono_domain_get (), method, method->klass);
1740 mono_ckfinite (double d)
1742 if (isinf (d) || isnan (d))
1743 mono_set_pending_exception (mono_get_exception_arithmetic ());
1748 mono_llvmonly_set_calling_assembly (MonoImage *image)
1750 MonoJitTlsData *jit_tls = NULL;
1752 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1754 jit_tls->calling_image = image;
1759 get_executing (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1761 MonoMethod **dest = (MonoMethod **)data;
1763 /* skip unmanaged frames */
1768 if (!strcmp (m->klass->name_space, "System.Reflection"))
1777 get_caller_no_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1779 MonoMethod **dest = (MonoMethod **)data;
1781 /* skip unmanaged frames */
1785 if (m->wrapper_type != MONO_WRAPPER_NONE)
1788 if (m->klass->image == mono_defaults.corlib && !strcmp (m->klass->name_space, "System.Reflection"))
1803 mono_llvmonly_get_calling_assembly (void)
1805 MonoJitTlsData *jit_tls = NULL;
1808 MonoAssembly *assembly;
1811 mono_stack_walk_no_il (get_executing, &dest);
1813 mono_stack_walk_no_il (get_caller_no_reflection, &dest);
1816 /* Fall back to TLS */
1817 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1819 if (!jit_tls->calling_image) {
1820 mono_set_pending_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
1823 assembly = jit_tls->calling_image->assembly;
1825 assembly = dest->klass->image->assembly;
1827 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);
1831 * mono_interruption_checkpoint_from_trampoline:
1833 * Check whenever the thread has a pending exception, and throw it
1835 * Architectures should move away from calling this function and
1836 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1837 * rewrind to the parent frame, and throw the exception normally.
1840 mono_interruption_checkpoint_from_trampoline (void)
1844 ex = mono_thread_force_interruption_checkpoint_noraise ();
1846 mono_raise_exception (ex);