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 return mono_object_new (mono_domain_get (), klass);
1134 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1135 * in generated code. So instead we emit a call to this function and place a gdb
1144 mono_create_corlib_exception_0 (guint32 token)
1146 return mono_exception_from_token (mono_defaults.corlib, token);
1150 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1152 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1156 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1158 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1162 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1164 MonoJitTlsData *jit_tls = NULL;
1167 if (mini_get_debug_options ()->better_cast_details) {
1168 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1169 jit_tls->class_cast_from = NULL;
1175 oklass = obj->vtable->klass;
1176 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1178 if (mono_object_isinst (obj, klass))
1181 if (mini_get_debug_options ()->better_cast_details) {
1182 jit_tls->class_cast_from = oklass;
1183 jit_tls->class_cast_to = klass;
1186 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1187 "System", "InvalidCastException"));
1193 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1195 MonoJitTlsData *jit_tls = NULL;
1196 gpointer cached_vtable, obj_vtable;
1198 if (mini_get_debug_options ()->better_cast_details) {
1199 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1200 jit_tls->class_cast_from = NULL;
1206 cached_vtable = *cache;
1207 obj_vtable = obj->vtable;
1209 if (cached_vtable == obj_vtable)
1212 if (mono_object_isinst (obj, klass)) {
1213 *cache = obj_vtable;
1217 if (mini_get_debug_options ()->better_cast_details) {
1218 jit_tls->class_cast_from = obj->vtable->klass;
1219 jit_tls->class_cast_to = klass;
1222 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1223 "System", "InvalidCastException"));
1229 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1231 size_t cached_vtable, obj_vtable;
1236 cached_vtable = (size_t)*cache;
1237 obj_vtable = (size_t)obj->vtable;
1239 if ((cached_vtable & ~0x1) == obj_vtable) {
1240 return (cached_vtable & 0x1) ? NULL : obj;
1243 if (mono_object_isinst (obj, klass)) {
1244 *cache = (gpointer)obj_vtable;
1248 *cache = (gpointer)(obj_vtable | 0x1);
1254 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1256 MonoMarshalSpec **mspecs;
1257 MonoMethodPInvoke piinfo;
1260 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1261 memset (&piinfo, 0, sizeof (piinfo));
1263 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1265 return mono_compile_method (m);
1269 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1272 int vt_slot, iface_offset;
1274 mono_error_init (error);
1276 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1277 MonoObject *this_obj;
1279 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1280 this_obj = *(MonoObject**)mp;
1281 g_assert (this_obj);
1283 klass = this_obj->vtable->klass;
1286 if (mono_method_signature (cmethod)->pinvoke) {
1287 /* Object.GetType () */
1288 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1290 /* Lookup the virtual method */
1291 mono_class_setup_vtable (klass);
1292 g_assert (klass->vtable);
1293 vt_slot = mono_method_get_vtable_slot (cmethod);
1294 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1295 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1296 g_assert (iface_offset != -1);
1297 vt_slot += iface_offset;
1299 m = klass->vtable [vt_slot];
1300 if (cmethod->is_inflated)
1301 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1304 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1306 * Calling a non-vtype method with a vtype receiver, has to box.
1308 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1309 else if (klass->valuetype)
1311 * Calling a vtype method with a vtype receiver
1316 * Calling a non-vtype method
1318 *this_arg = *(gpointer*)mp;
1323 * mono_gsharedvt_constrained_call:
1325 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1326 * the arguments to the method in the format used by mono_runtime_invoke ().
1329 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1334 gpointer new_args [16];
1336 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1337 if (!mono_error_ok (&error)) {
1338 mono_error_set_pending_exception (&error);
1344 if (args && deref_arg) {
1345 new_args [0] = *(gpointer*)args [0];
1348 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1349 /* Object.GetType () */
1351 args [0] = this_arg;
1354 return mono_runtime_invoke (m, this_arg, args, NULL);
1358 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1360 if (klass->valuetype)
1361 mono_value_copy (dest, src, klass);
1363 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1367 mono_generic_class_init (MonoVTable *vtable)
1369 mono_runtime_class_init (vtable);
1373 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1378 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1379 if (!mono_error_ok (&error)) {
1380 mono_error_set_pending_exception (&error);
1387 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1392 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1393 if (!mono_error_ok (&error)) {
1394 mono_error_set_pending_exception (&error);
1401 * resolve_iface_call:
1403 * Return the executable code for the iface method IMT_METHOD called on THIS.
1404 * This function is called on a slowpath, so it doesn't need to be fast.
1405 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1409 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1412 gpointer *imt, *vtable_slot;
1413 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1414 gpointer addr, compiled_method, aot_addr;
1415 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1418 /* The caller will handle it */
1421 vt = this_obj->vtable;
1422 imt = (gpointer*)vt - MONO_IMT_SIZE;
1424 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1426 // FIXME: This can throw exceptions
1427 addr = compiled_method = mono_compile_method (impl_method);
1430 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1431 generic_virtual = imt_method;
1433 if (generic_virtual || variant_iface) {
1434 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1435 need_unbox_tramp = TRUE;
1437 if (impl_method->klass->valuetype)
1438 need_unbox_tramp = TRUE;
1441 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1443 if (generic_virtual || variant_iface) {
1444 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1446 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1455 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1457 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1461 is_generic_method_definition (MonoMethod *m)
1463 MonoGenericContext *context;
1466 if (!m->is_inflated)
1469 context = mono_method_get_context (m);
1470 if (!context->method_inst)
1472 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1480 * Return the executable code for calling vt->vtable [slot].
1481 * This function is called on a slowpath, so it doesn't need to be fast.
1482 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1486 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1488 MonoMethod *m, *generic_virtual = NULL;
1489 gpointer addr, compiled_method;
1490 gboolean need_unbox_tramp = FALSE;
1492 /* Same as in common_call_trampoline () */
1494 /* Avoid loading metadata or creating a generic vtable if possible */
1495 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1496 if (addr && !vt->klass->valuetype)
1497 return mono_create_ftnptr (mono_domain_get (), addr);
1499 m = mono_class_get_vtable_entry (vt->klass, slot);
1501 if (is_generic_method_definition (m)) {
1503 MonoGenericContext context = { NULL, NULL };
1504 MonoMethod *declaring;
1507 declaring = mono_method_get_declaring_generic_method (m);
1511 if (m->klass->generic_class)
1512 context.class_inst = m->klass->generic_class->context.class_inst;
1514 g_assert (!m->klass->generic_container);
1516 generic_virtual = imt_method;
1517 g_assert (generic_virtual);
1518 g_assert (generic_virtual->is_inflated);
1519 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1521 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1522 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1525 if (generic_virtual) {
1526 if (vt->klass->valuetype)
1527 need_unbox_tramp = TRUE;
1529 if (m->klass->valuetype)
1530 need_unbox_tramp = TRUE;
1533 // FIXME: This can throw exceptions
1534 addr = compiled_method = mono_compile_method (m);
1537 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1539 if (!gsharedvt && generic_virtual) {
1540 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1541 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1543 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1544 vt, vt->vtable + slot,
1545 generic_virtual, ftndesc);
1552 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1554 g_assert (this_obj);
1556 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1560 * mono_resolve_generic_virtual_call:
1562 * Resolve a generic virtual call.
1563 * This function is called on a slowpath, so it doesn't need to be fast.
1566 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1569 gpointer addr, compiled_method;
1570 gboolean need_unbox_tramp = FALSE;
1572 MonoGenericContext context = { NULL, NULL };
1573 MonoMethod *declaring;
1574 gpointer arg = NULL;
1576 m = mono_class_get_vtable_entry (vt->klass, slot);
1578 g_assert (is_generic_method_definition (m));
1581 declaring = mono_method_get_declaring_generic_method (m);
1585 if (m->klass->generic_class)
1586 context.class_inst = m->klass->generic_class->context.class_inst;
1588 g_assert (!m->klass->generic_container);
1590 g_assert (generic_virtual->is_inflated);
1591 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1593 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1594 g_assert (mono_error_ok (&error));
1596 if (vt->klass->valuetype)
1597 need_unbox_tramp = TRUE;
1599 // FIXME: This can throw exceptions
1600 addr = compiled_method = mono_compile_method (m);
1603 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1606 * This wastes memory but the memory usage is bounded since
1607 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1608 * this vtable slot so we are not called any more for this instantiation.
1610 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1612 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1613 vt, vt->vtable + slot,
1614 generic_virtual, ftndesc);
1619 * mono_resolve_generic_virtual_call:
1621 * Resolve a generic virtual/variant iface call on interfaces.
1622 * This function is called on a slowpath, so it doesn't need to be fast.
1625 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1627 MonoMethod *m, *variant_iface;
1628 gpointer addr, aot_addr, compiled_method;
1629 gboolean need_unbox_tramp = FALSE;
1630 gboolean need_rgctx_tramp;
1631 gpointer arg = NULL;
1634 imt = (gpointer*)vt - MONO_IMT_SIZE;
1636 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1638 if (vt->klass->valuetype)
1639 need_unbox_tramp = TRUE;
1641 // FIXME: This can throw exceptions
1642 addr = compiled_method = mono_compile_method (m);
1645 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1648 * This wastes memory but the memory usage is bounded since
1649 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1650 * this vtable slot so we are not called any more for this instantiation.
1652 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1654 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1656 variant_iface ? variant_iface : generic_virtual, ftndesc);
1661 * mono_init_vtable_slot:
1663 * Initialize slot SLOT of VTABLE.
1664 * Return the contents of the vtable slot.
1667 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1669 gpointer arg = NULL;
1673 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1674 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1677 mono_memory_barrier ();
1679 vtable->vtable [slot] = ftnptr;
1685 * mono_llvmonly_init_delegate:
1687 * Initialize a MonoDelegate object.
1688 * Similar to mono_delegate_ctor ().
1691 mono_llvmonly_init_delegate (MonoDelegate *del)
1693 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1696 * We store a MonoFtnDesc in del->method_code.
1697 * It would be better to store an ftndesc in del->method_ptr too,
1698 * but we don't have a a structure which could own its memory.
1700 if (G_UNLIKELY (!ftndesc)) {
1701 gpointer addr = mono_compile_method (del->method);
1702 gpointer arg = mini_get_delegate_arg (del->method, addr);
1704 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1705 mono_memory_barrier ();
1706 *del->method_code = (gpointer)ftndesc;
1708 del->method_ptr = ftndesc->addr;
1709 del->extra_arg = ftndesc->arg;
1713 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1717 method = mono_object_get_virtual_method (target, method);
1719 del->method = method;
1720 del->method_ptr = mono_compile_method (method);
1721 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1725 mono_get_assembly_object (MonoImage *image)
1727 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1731 mono_get_method_object (MonoMethod *method)
1733 return (MonoObject*)mono_method_get_object (mono_domain_get (), method, method->klass);
1737 mono_ckfinite (double d)
1739 if (isinf (d) || isnan (d))
1740 mono_set_pending_exception (mono_get_exception_arithmetic ());
1745 mono_llvmonly_set_calling_assembly (MonoImage *image)
1747 MonoJitTlsData *jit_tls = NULL;
1749 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1751 jit_tls->calling_image = image;
1756 get_executing (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1758 MonoMethod **dest = (MonoMethod **)data;
1760 /* skip unmanaged frames */
1765 if (!strcmp (m->klass->name_space, "System.Reflection"))
1774 get_caller_no_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1776 MonoMethod **dest = (MonoMethod **)data;
1778 /* skip unmanaged frames */
1782 if (m->wrapper_type != MONO_WRAPPER_NONE)
1785 if (m->klass->image == mono_defaults.corlib && !strcmp (m->klass->name_space, "System.Reflection"))
1800 mono_llvmonly_get_calling_assembly (void)
1802 MonoJitTlsData *jit_tls = NULL;
1805 MonoAssembly *assembly;
1808 mono_stack_walk_no_il (get_executing, &dest);
1810 mono_stack_walk_no_il (get_caller_no_reflection, &dest);
1813 /* Fall back to TLS */
1814 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1816 if (!jit_tls->calling_image) {
1817 mono_set_pending_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
1820 assembly = jit_tls->calling_image->assembly;
1822 assembly = dest->klass->image->assembly;
1824 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);
1828 * mono_interruption_checkpoint_from_trampoline:
1830 * Check whenever the thread has a pending exception, and throw it
1832 * Architectures should move away from calling this function and
1833 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1834 * rewrind to the parent frame, and throw the exception normally.
1837 mono_interruption_checkpoint_from_trampoline (void)
1841 ex = mono_thread_force_interruption_checkpoint_noraise ();
1843 mono_raise_exception (ex);