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)
1272 int vt_slot, iface_offset;
1274 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1275 MonoObject *this_obj;
1277 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1278 this_obj = *(MonoObject**)mp;
1279 g_assert (this_obj);
1281 klass = this_obj->vtable->klass;
1284 if (mono_method_signature (cmethod)->pinvoke) {
1285 /* Object.GetType () */
1286 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1288 /* Lookup the virtual method */
1289 mono_class_setup_vtable (klass);
1290 g_assert (klass->vtable);
1291 vt_slot = mono_method_get_vtable_slot (cmethod);
1292 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1293 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1294 g_assert (iface_offset != -1);
1295 vt_slot += iface_offset;
1297 m = klass->vtable [vt_slot];
1298 if (cmethod->is_inflated)
1299 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1302 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1304 * Calling a non-vtype method with a vtype receiver, has to box.
1306 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1307 else if (klass->valuetype)
1309 * Calling a vtype method with a vtype receiver
1314 * Calling a non-vtype method
1316 *this_arg = *(gpointer*)mp;
1321 * mono_gsharedvt_constrained_call:
1323 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1324 * the arguments to the method in the format used by mono_runtime_invoke ().
1327 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1331 gpointer new_args [16];
1333 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1336 if (args && deref_arg) {
1337 new_args [0] = *(gpointer*)args [0];
1340 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1341 /* Object.GetType () */
1343 args [0] = this_arg;
1346 return mono_runtime_invoke (m, this_arg, args, NULL);
1350 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1352 if (klass->valuetype)
1353 mono_value_copy (dest, src, klass);
1355 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1359 mono_generic_class_init (MonoVTable *vtable)
1361 mono_runtime_class_init (vtable);
1365 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1367 return mono_class_fill_runtime_generic_context (vtable, index);
1371 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1373 return mono_method_fill_runtime_generic_context (mrgctx, index);
1377 * resolve_iface_call:
1379 * Return the executable code for the iface method IMT_METHOD called on THIS.
1380 * This function is called on a slowpath, so it doesn't need to be fast.
1381 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1385 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1388 gpointer *imt, *vtable_slot;
1389 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1390 gpointer addr, compiled_method, aot_addr;
1391 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1394 /* The caller will handle it */
1397 vt = this_obj->vtable;
1398 imt = (gpointer*)vt - MONO_IMT_SIZE;
1400 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1402 // FIXME: This can throw exceptions
1403 addr = compiled_method = mono_compile_method (impl_method);
1406 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1407 generic_virtual = imt_method;
1409 if (generic_virtual || variant_iface) {
1410 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1411 need_unbox_tramp = TRUE;
1413 if (impl_method->klass->valuetype)
1414 need_unbox_tramp = TRUE;
1417 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1419 if (generic_virtual || variant_iface) {
1420 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1422 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1431 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1433 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1437 is_generic_method_definition (MonoMethod *m)
1439 MonoGenericContext *context;
1442 if (!m->is_inflated)
1445 context = mono_method_get_context (m);
1446 if (!context->method_inst)
1448 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1456 * Return the executable code for calling vt->vtable [slot].
1457 * This function is called on a slowpath, so it doesn't need to be fast.
1458 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1462 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1464 MonoMethod *m, *generic_virtual = NULL;
1465 gpointer addr, compiled_method;
1466 gboolean need_unbox_tramp = FALSE;
1468 /* Same as in common_call_trampoline () */
1470 /* Avoid loading metadata or creating a generic vtable if possible */
1471 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1472 if (addr && !vt->klass->valuetype)
1473 return mono_create_ftnptr (mono_domain_get (), addr);
1475 m = mono_class_get_vtable_entry (vt->klass, slot);
1477 if (is_generic_method_definition (m)) {
1479 MonoGenericContext context = { NULL, NULL };
1480 MonoMethod *declaring;
1483 declaring = mono_method_get_declaring_generic_method (m);
1487 if (m->klass->generic_class)
1488 context.class_inst = m->klass->generic_class->context.class_inst;
1490 g_assert (!m->klass->generic_container);
1492 generic_virtual = imt_method;
1493 g_assert (generic_virtual);
1494 g_assert (generic_virtual->is_inflated);
1495 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1497 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1498 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1501 if (generic_virtual) {
1502 if (vt->klass->valuetype)
1503 need_unbox_tramp = TRUE;
1505 if (m->klass->valuetype)
1506 need_unbox_tramp = TRUE;
1509 // FIXME: This can throw exceptions
1510 addr = compiled_method = mono_compile_method (m);
1513 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1515 if (!gsharedvt && generic_virtual) {
1516 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1517 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1519 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1520 vt, vt->vtable + slot,
1521 generic_virtual, ftndesc);
1528 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1530 g_assert (this_obj);
1532 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1536 * mono_resolve_generic_virtual_call:
1538 * Resolve a generic virtual call.
1539 * This function is called on a slowpath, so it doesn't need to be fast.
1542 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1545 gpointer addr, compiled_method;
1546 gboolean need_unbox_tramp = FALSE;
1548 MonoGenericContext context = { NULL, NULL };
1549 MonoMethod *declaring;
1550 gpointer arg = NULL;
1552 m = mono_class_get_vtable_entry (vt->klass, slot);
1554 g_assert (is_generic_method_definition (m));
1557 declaring = mono_method_get_declaring_generic_method (m);
1561 if (m->klass->generic_class)
1562 context.class_inst = m->klass->generic_class->context.class_inst;
1564 g_assert (!m->klass->generic_container);
1566 g_assert (generic_virtual->is_inflated);
1567 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1569 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1570 g_assert (mono_error_ok (&error));
1572 if (vt->klass->valuetype)
1573 need_unbox_tramp = TRUE;
1575 // FIXME: This can throw exceptions
1576 addr = compiled_method = mono_compile_method (m);
1579 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1582 * This wastes memory but the memory usage is bounded since
1583 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1584 * this vtable slot so we are not called any more for this instantiation.
1586 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1588 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1589 vt, vt->vtable + slot,
1590 generic_virtual, ftndesc);
1595 * mono_resolve_generic_virtual_call:
1597 * Resolve a generic virtual/variant iface call on interfaces.
1598 * This function is called on a slowpath, so it doesn't need to be fast.
1601 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1603 MonoMethod *m, *variant_iface;
1604 gpointer addr, aot_addr, compiled_method;
1605 gboolean need_unbox_tramp = FALSE;
1606 gboolean need_rgctx_tramp;
1607 gpointer arg = NULL;
1610 imt = (gpointer*)vt - MONO_IMT_SIZE;
1612 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1614 if (vt->klass->valuetype)
1615 need_unbox_tramp = TRUE;
1617 // FIXME: This can throw exceptions
1618 addr = compiled_method = mono_compile_method (m);
1621 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1624 * This wastes memory but the memory usage is bounded since
1625 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1626 * this vtable slot so we are not called any more for this instantiation.
1628 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1630 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1632 variant_iface ? variant_iface : generic_virtual, ftndesc);
1637 * mono_init_vtable_slot:
1639 * Initialize slot SLOT of VTABLE.
1640 * Return the contents of the vtable slot.
1643 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1645 gpointer arg = NULL;
1649 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1650 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1653 mono_memory_barrier ();
1655 vtable->vtable [slot] = ftnptr;
1661 * mono_llvmonly_init_delegate:
1663 * Initialize a MonoDelegate object.
1664 * Similar to mono_delegate_ctor ().
1667 mono_llvmonly_init_delegate (MonoDelegate *del)
1669 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1672 * We store a MonoFtnDesc in del->method_code.
1673 * It would be better to store an ftndesc in del->method_ptr too,
1674 * but we don't have a a structure which could own its memory.
1676 if (G_UNLIKELY (!ftndesc)) {
1677 gpointer addr = mono_compile_method (del->method);
1678 gpointer arg = mini_get_delegate_arg (del->method, addr);
1680 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1681 mono_memory_barrier ();
1682 *del->method_code = (gpointer)ftndesc;
1684 del->method_ptr = ftndesc->addr;
1685 del->extra_arg = ftndesc->arg;
1689 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1693 method = mono_object_get_virtual_method (target, method);
1695 del->method = method;
1696 del->method_ptr = mono_compile_method (method);
1697 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1701 mono_get_assembly_object (MonoImage *image)
1703 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1707 mono_get_method_object (MonoMethod *method)
1709 return (MonoObject*)mono_method_get_object (mono_domain_get (), method, method->klass);
1713 mono_ckfinite (double d)
1715 if (isinf (d) || isnan (d))
1716 mono_set_pending_exception (mono_get_exception_arithmetic ());
1721 mono_llvmonly_set_calling_assembly (MonoImage *image)
1723 MonoJitTlsData *jit_tls = NULL;
1725 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1727 jit_tls->calling_image = image;
1731 mono_llvmonly_get_calling_assembly (void)
1733 MonoJitTlsData *jit_tls = NULL;
1735 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1737 if (!jit_tls->calling_image) {
1738 mono_set_pending_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
1741 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);
1745 * mono_interruption_checkpoint_from_trampoline:
1747 * Check whenever the thread has a pending exception, and throw it
1749 * Architectures should move away from calling this function and
1750 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1751 * rewrind to the parent frame, and throw the exception normally.
1754 mono_interruption_checkpoint_from_trampoline (void)
1758 ex = mono_thread_force_interruption_checkpoint_noraise ();
1760 mono_raise_exception (ex);