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>
23 #include "mini-llvm-cpp.h"
27 mono_ldftn (MonoMethod *method)
32 // FIXME: No error handling
34 addr = mono_compile_method (method);
37 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
38 /* The caller doesn't pass it */
39 g_assert_not_reached ();
41 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
45 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
47 return mono_create_ftnptr (mono_domain_get (), addr);
51 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
57 mono_set_pending_exception (mono_get_exception_null_reference ());
61 res = mono_object_get_virtual_method (obj, method);
63 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
64 MonoGenericContext context = { NULL, NULL };
66 if (res->klass->generic_class)
67 context.class_inst = res->klass->generic_class->context.class_inst;
68 else if (res->klass->generic_container)
69 context.class_inst = res->klass->generic_container->context.class_inst;
70 context.method_inst = mono_method_get_context (method)->method_inst;
72 res = mono_class_inflate_generic_method_checked (res, &context, &error);
73 if (!mono_error_ok (&error)) {
74 mono_error_set_pending_exception (&error);
79 /* An rgctx wrapper is added by the trampolines no need to do it here */
81 return mono_ldftn (res);
85 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
87 return ldvirtfn_internal (obj, method, FALSE);
91 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
93 return ldvirtfn_internal (obj, method, TRUE);
97 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
100 mono_set_pending_exception (mono_get_exception_null_reference ());
103 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
104 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
109 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
112 mono_llmult (gint64 a, gint64 b)
118 mono_llmult_ovf_un (guint64 a, guint64 b)
121 guint32 ah = a >> 32;
123 guint32 bh = b >> 32;
126 // fixme: this is incredible slow
129 goto raise_exception;
131 res = (guint64)al * (guint64)bl;
133 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
136 goto raise_exception;
138 res += ((guint64)t1) << 32;
143 mono_set_pending_exception (mono_get_exception_overflow ());
148 mono_llmult_ovf (gint64 a, gint64 b)
155 Use Karatsuba algorithm where:
156 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
157 where Ah is the "high half" (most significant 32 bits) of a and
158 where Al is the "low half" (least significant 32 bits) of a and
159 where Bh is the "high half" of b and Bl is the "low half" and
160 where R is the Radix or "size of the half" (in our case 32 bits)
162 Note, for the product of two 64 bit numbers to fit into a 64
163 result, ah and/or bh must be 0. This will save us from doing
164 the AhBh term at all.
166 Also note that we refactor so that we don't overflow 64 bits with
167 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
173 /* need to work with absoulte values, so find out what the
174 resulting sign will be and convert any negative numbers
175 from two's complement
179 if (((guint32)ah == 0x80000000) && (al == 0)) {
180 /* This has no two's complement */
186 goto raise_exception;
189 /* flip the bits and add 1 */
200 if (((guint32)bh == 0x80000000) && (bl == 0)) {
201 /* This has no two's complement */
207 goto raise_exception;
210 /* flip the bits and add 1 */
220 /* we overflow for sure if both upper halves are greater
221 than zero because we would need to shift their
222 product 64 bits to the left and that will not fit
223 in a 64 bit result */
225 goto raise_exception;
226 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
227 goto raise_exception;
229 /* do the AlBl term first */
230 t1 = (gint64)al * (gint64)bl;
234 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
235 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
236 /* check for overflow */
238 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
239 goto raise_exception;
244 goto raise_exception;
252 mono_set_pending_exception (mono_get_exception_overflow ());
257 mono_lldiv (gint64 a, gint64 b)
259 #ifdef MONO_ARCH_NEED_DIV_CHECK
261 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
264 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
265 mono_set_pending_exception (mono_get_exception_arithmetic ());
273 mono_llrem (gint64 a, gint64 b)
275 #ifdef MONO_ARCH_NEED_DIV_CHECK
277 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
280 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
281 mono_set_pending_exception (mono_get_exception_arithmetic ());
289 mono_lldiv_un (guint64 a, guint64 b)
291 #ifdef MONO_ARCH_NEED_DIV_CHECK
293 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
301 mono_llrem_un (guint64 a, guint64 b)
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
305 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
314 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
317 mono_lshl (guint64 a, gint32 shamt)
321 res = a << (shamt & 0x7f);
323 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
329 mono_lshr_un (guint64 a, gint32 shamt)
333 res = a >> (shamt & 0x7f);
335 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
341 mono_lshr (gint64 a, gint32 shamt)
345 res = a >> (shamt & 0x7f);
347 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
354 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
357 mono_idiv (gint32 a, gint32 b)
359 #ifdef MONO_ARCH_NEED_DIV_CHECK
361 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
364 else if (b == -1 && a == (0x80000000)) {
365 mono_set_pending_exception (mono_get_exception_overflow ());
373 mono_idiv_un (guint32 a, guint32 b)
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
377 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
385 mono_irem (gint32 a, gint32 b)
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
389 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
392 else if (b == -1 && a == (0x80000000)) {
393 mono_set_pending_exception (mono_get_exception_overflow ());
401 mono_irem_un (guint32 a, guint32 b)
403 #ifdef MONO_ARCH_NEED_DIV_CHECK
405 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
414 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
417 mono_imul (gint32 a, gint32 b)
423 mono_imul_ovf (gint32 a, gint32 b)
427 res = (gint64)a * (gint64)b;
429 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
430 mono_set_pending_exception (mono_get_exception_overflow ());
438 mono_imul_ovf_un (guint32 a, guint32 b)
442 res = (guint64)a * (guint64)b;
445 mono_set_pending_exception (mono_get_exception_overflow ());
453 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
455 mono_fdiv (double a, double b)
461 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
464 mono_fsub (double a, double b)
470 mono_fadd (double a, double b)
476 mono_fmul (double a, double b)
488 mono_fconv_r4 (double a)
494 mono_conv_to_r8 (int a)
500 mono_conv_to_r4 (int a)
502 return (double)(float)a;
506 mono_fconv_i1 (double a)
512 mono_fconv_i2 (double a)
518 mono_fconv_i4 (double a)
524 mono_fconv_u1 (double a)
530 mono_fconv_u2 (double a)
536 mono_fcmp_eq (double a, double b)
542 mono_fcmp_ge (double a, double b)
548 mono_fcmp_gt (double a, double b)
554 mono_fcmp_le (double a, double b)
560 mono_fcmp_lt (double a, double b)
566 mono_fcmp_ne_un (double a, double b)
568 return isunordered (a, b) || a != b;
572 mono_fcmp_ge_un (double a, double b)
574 return isunordered (a, b) || a >= b;
578 mono_fcmp_gt_un (double a, double b)
580 return isunordered (a, b) || a > b;
584 mono_fcmp_le_un (double a, double b)
586 return isunordered (a, b) || a <= b;
590 mono_fcmp_lt_un (double a, double b)
592 return isunordered (a, b) || a < b;
596 mono_fceq (double a, double b)
602 mono_fcgt (double a, double b)
608 mono_fcgt_un (double a, double b)
610 return isunordered (a, b) || a > b;
614 mono_fclt (double a, double b)
620 mono_fclt_un (double a, double b)
622 return isunordered (a, b) || a < b;
626 mono_isfinite (double a)
631 g_assert_not_reached ();
637 mono_fload_r4 (float *ptr)
643 mono_fstore_r4 (double val, float *ptr)
648 /* returns the integer bitpattern that is passed in the regs or stack */
650 mono_fload_r4_arg (double val)
652 float v = (float)val;
653 return *(guint32*)&v;
659 mono_array_new_va (MonoMethod *cm, ...)
663 MonoDomain *domain = mono_domain_get ();
666 intptr_t *lower_bounds;
671 pcount = mono_method_signature (cm)->param_count;
672 rank = cm->klass->rank;
676 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
677 for (i = 0; i < pcount; ++i)
678 lengths [i] = d = va_arg(ap, int);
680 if (rank == pcount) {
681 /* Only lengths provided. */
682 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
683 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
684 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
689 g_assert (pcount == (rank * 2));
690 /* lower bounds are first. */
691 lower_bounds = (intptr_t*)lengths;
696 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
697 mono_error_raise_exception (&error); /* FIXME don't raise here */
702 /* Specialized version of mono_array_new_va () which avoids varargs */
704 mono_array_new_1 (MonoMethod *cm, guint32 length)
708 MonoDomain *domain = mono_domain_get ();
709 uintptr_t lengths [1];
710 intptr_t *lower_bounds;
714 pcount = mono_method_signature (cm)->param_count;
715 rank = cm->klass->rank;
717 lengths [0] = length;
719 g_assert (rank == pcount);
721 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
722 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
723 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
728 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
729 mono_error_raise_exception (&error); /* FIXME don't raise here */
735 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
739 MonoDomain *domain = mono_domain_get ();
740 uintptr_t lengths [2];
741 intptr_t *lower_bounds;
745 pcount = mono_method_signature (cm)->param_count;
746 rank = cm->klass->rank;
748 lengths [0] = length1;
749 lengths [1] = length2;
751 g_assert (rank == pcount);
753 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
754 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
755 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
760 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
761 mono_error_raise_exception (&error); /* FIXME don't raise here */
767 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
771 MonoDomain *domain = mono_domain_get ();
772 uintptr_t lengths [3];
773 intptr_t *lower_bounds;
777 pcount = mono_method_signature (cm)->param_count;
778 rank = cm->klass->rank;
780 lengths [0] = length1;
781 lengths [1] = length2;
782 lengths [2] = length3;
784 g_assert (rank == pcount);
786 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
787 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
788 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
793 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
794 mono_error_raise_exception (&error); /* FIXME don't raise here */
800 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
804 MonoDomain *domain = mono_domain_get ();
805 uintptr_t lengths [4];
806 intptr_t *lower_bounds;
810 pcount = mono_method_signature (cm)->param_count;
811 rank = cm->klass->rank;
813 lengths [0] = length1;
814 lengths [1] = length2;
815 lengths [2] = length3;
816 lengths [3] = length4;
818 g_assert (rank == pcount);
820 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
821 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
822 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
827 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
828 mono_error_raise_exception (&error); /* FIXME don't raise here */
834 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
839 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
841 mono_class_init (field->parent);
843 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
844 if (!vtable->initialized)
845 mono_runtime_class_init (vtable);
847 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
849 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
850 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
852 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
858 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
861 MonoClass *handle_class;
864 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
865 if (!mono_error_ok (&error)) {
866 mono_error_set_pending_exception (&error);
869 mono_class_init (handle_class);
875 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
877 MonoMethodSignature *sig = mono_method_signature (method);
878 MonoGenericContext *generic_context;
880 if (sig->is_inflated) {
881 generic_context = mono_method_get_context (method);
883 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
884 g_assert (generic_container);
885 generic_context = &generic_container->context;
888 return mono_ldtoken_wrapper (image, token, generic_context);
892 mono_fconv_u8 (double v)
898 mono_rconv_u8 (float v)
903 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
905 mono_fconv_i8 (double v)
912 mono_fconv_u4 (double v)
914 /* MS.NET behaves like this for some reason */
916 if (isinf (v) || isnan (v))
924 /* Solaris doesn't have trunc */
926 extern long double aintl (long double);
929 /* FIXME: This means we will never throw overflow exceptions */
932 #endif /* HAVE_TRUNC */
935 mono_fconv_ovf_i8 (double v)
941 if (isnan(v) || trunc (v) != res) {
942 mono_set_pending_exception (mono_get_exception_overflow ());
949 mono_fconv_ovf_u8 (double v)
954 * The soft-float implementation of some ARM devices have a buggy guin64 to double
955 * conversion that it looses precision even when the integer if fully representable
958 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
960 * To work around this issue we test for value boundaries instead.
962 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
963 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
964 mono_set_pending_exception (mono_get_exception_overflow ());
970 if (isnan(v) || trunc (v) != res) {
971 mono_set_pending_exception (mono_get_exception_overflow ());
978 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
980 mono_rconv_i8 (float v)
987 mono_rconv_ovf_i8 (float v)
993 if (isnan(v) || trunc (v) != res) {
994 mono_set_pending_exception (mono_get_exception_overflow ());
1001 mono_rconv_ovf_u8 (float v)
1006 if (isnan(v) || trunc (v) != res) {
1007 mono_set_pending_exception (mono_get_exception_overflow ());
1013 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1015 mono_lconv_to_r8 (gint64 a)
1021 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1023 mono_lconv_to_r4 (gint64 a)
1029 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1031 mono_conv_to_r8_un (guint32 a)
1037 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1039 mono_lconv_to_r8_un (guint64 a)
1045 #if defined(__native_client_codegen__) || defined(__native_client__)
1046 /* When we cross-compile to Native Client we can't directly embed calls */
1047 /* to the math library on the host. This will use the fmod on the target*/
1049 mono_fmod(double a, double b)
1056 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1058 MonoMethod *vmethod;
1060 MonoGenericContext *context = mono_method_get_context (method);
1062 mono_jit_stats.generic_virtual_invocations++;
1065 mono_set_pending_exception (mono_get_exception_null_reference ());
1068 vmethod = mono_object_get_virtual_method (obj, method);
1069 g_assert (!vmethod->klass->generic_container);
1070 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1071 g_assert (!context->method_inst || !context->method_inst->is_open);
1073 addr = mono_compile_method (vmethod);
1075 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1077 /* Since this is a virtual call, have to unbox vtypes */
1078 if (obj->vtable->klass->valuetype)
1079 *this_arg = mono_object_unbox (obj);
1087 mono_helper_ldstr (MonoImage *image, guint32 idx)
1089 return mono_ldstr (mono_domain_get (), image, idx);
1093 mono_helper_ldstr_mscorlib (guint32 idx)
1095 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1099 mono_helper_newobj_mscorlib (guint32 idx)
1102 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1104 if (!mono_error_ok (&error)) {
1105 mono_error_set_pending_exception (&error);
1109 return mono_object_new (mono_domain_get (), klass);
1113 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1114 * in generated code. So instead we emit a call to this function and place a gdb
1123 mono_create_corlib_exception_0 (guint32 token)
1125 return mono_exception_from_token (mono_defaults.corlib, token);
1129 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1131 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1135 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1137 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1141 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1143 MonoJitTlsData *jit_tls = NULL;
1146 if (mini_get_debug_options ()->better_cast_details) {
1147 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1148 jit_tls->class_cast_from = NULL;
1154 oklass = obj->vtable->klass;
1155 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1157 if (mono_object_isinst (obj, klass))
1160 if (mini_get_debug_options ()->better_cast_details) {
1161 jit_tls->class_cast_from = oklass;
1162 jit_tls->class_cast_to = klass;
1165 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1166 "System", "InvalidCastException"));
1172 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1174 MonoJitTlsData *jit_tls = NULL;
1175 gpointer cached_vtable, obj_vtable;
1177 if (mini_get_debug_options ()->better_cast_details) {
1178 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1179 jit_tls->class_cast_from = NULL;
1185 cached_vtable = *cache;
1186 obj_vtable = obj->vtable;
1188 if (cached_vtable == obj_vtable)
1191 if (mono_object_isinst (obj, klass)) {
1192 *cache = obj_vtable;
1196 if (mini_get_debug_options ()->better_cast_details) {
1197 jit_tls->class_cast_from = obj->vtable->klass;
1198 jit_tls->class_cast_to = klass;
1201 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1202 "System", "InvalidCastException"));
1208 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1210 size_t cached_vtable, obj_vtable;
1215 cached_vtable = (size_t)*cache;
1216 obj_vtable = (size_t)obj->vtable;
1218 if ((cached_vtable & ~0x1) == obj_vtable) {
1219 return (cached_vtable & 0x1) ? NULL : obj;
1222 if (mono_object_isinst (obj, klass)) {
1223 *cache = (gpointer)obj_vtable;
1227 *cache = (gpointer)(obj_vtable | 0x1);
1233 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1235 MonoMarshalSpec **mspecs;
1236 MonoMethodPInvoke piinfo;
1239 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1240 memset (&piinfo, 0, sizeof (piinfo));
1242 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1244 return mono_compile_method (m);
1248 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1251 int vt_slot, iface_offset;
1253 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1254 MonoObject *this_obj;
1256 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1257 this_obj = *(MonoObject**)mp;
1258 g_assert (this_obj);
1260 klass = this_obj->vtable->klass;
1263 if (mono_method_signature (cmethod)->pinvoke) {
1264 /* Object.GetType () */
1265 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1267 /* Lookup the virtual method */
1268 mono_class_setup_vtable (klass);
1269 g_assert (klass->vtable);
1270 vt_slot = mono_method_get_vtable_slot (cmethod);
1271 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1272 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1273 g_assert (iface_offset != -1);
1274 vt_slot += iface_offset;
1276 m = klass->vtable [vt_slot];
1277 if (cmethod->is_inflated)
1278 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1281 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1283 * Calling a non-vtype method with a vtype receiver, has to box.
1285 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1286 else if (klass->valuetype)
1288 * Calling a vtype method with a vtype receiver
1293 * Calling a non-vtype method
1295 *this_arg = *(gpointer*)mp;
1300 * mono_gsharedvt_constrained_call:
1302 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1303 * the arguments to the method in the format used by mono_runtime_invoke ().
1306 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1310 gpointer new_args [16];
1312 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1315 if (args && deref_arg) {
1316 new_args [0] = *(gpointer*)args [0];
1319 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1320 /* Object.GetType () */
1322 args [0] = this_arg;
1325 return mono_runtime_invoke (m, this_arg, args, NULL);
1329 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1331 if (klass->valuetype)
1332 mono_value_copy (dest, src, klass);
1334 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1338 mono_generic_class_init (MonoVTable *vtable)
1340 mono_runtime_class_init (vtable);
1344 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1346 return mono_class_fill_runtime_generic_context (vtable, index);
1350 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1352 return mono_method_fill_runtime_generic_context (mrgctx, index);
1356 * resolve_iface_call:
1358 * Return the executable code for the iface method IMT_METHOD called on THIS.
1359 * This function is called on a slowpath, so it doesn't need to be fast.
1360 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1364 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1367 gpointer *imt, *vtable_slot;
1368 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1369 gpointer addr, compiled_method, aot_addr;
1370 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1373 /* The caller will handle it */
1376 vt = this_obj->vtable;
1377 imt = (gpointer*)vt - MONO_IMT_SIZE;
1379 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1381 // FIXME: This can throw exceptions
1382 addr = compiled_method = mono_compile_method (impl_method);
1385 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1386 generic_virtual = imt_method;
1388 if (generic_virtual || variant_iface) {
1389 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1390 need_unbox_tramp = TRUE;
1392 if (impl_method->klass->valuetype)
1393 need_unbox_tramp = TRUE;
1396 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1398 if (generic_virtual || variant_iface) {
1399 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1401 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1410 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1412 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1416 is_generic_method_definition (MonoMethod *m)
1418 MonoGenericContext *context;
1421 if (!m->is_inflated)
1424 context = mono_method_get_context (m);
1425 if (!context->method_inst)
1427 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1435 * Return the executable code for calling vt->vtable [slot].
1436 * This function is called on a slowpath, so it doesn't need to be fast.
1437 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1441 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1443 MonoMethod *m, *generic_virtual = NULL;
1444 gpointer addr, compiled_method;
1445 gboolean need_unbox_tramp = FALSE;
1447 /* Same as in common_call_trampoline () */
1449 /* Avoid loading metadata or creating a generic vtable if possible */
1450 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1451 if (addr && !vt->klass->valuetype)
1452 return mono_create_ftnptr (mono_domain_get (), addr);
1454 m = mono_class_get_vtable_entry (vt->klass, slot);
1456 if (is_generic_method_definition (m)) {
1458 MonoGenericContext context = { NULL, NULL };
1459 MonoMethod *declaring;
1462 declaring = mono_method_get_declaring_generic_method (m);
1466 if (m->klass->generic_class)
1467 context.class_inst = m->klass->generic_class->context.class_inst;
1469 g_assert (!m->klass->generic_container);
1471 generic_virtual = imt_method;
1472 g_assert (generic_virtual);
1473 g_assert (generic_virtual->is_inflated);
1474 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1476 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1477 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1480 if (generic_virtual) {
1481 if (vt->klass->valuetype)
1482 need_unbox_tramp = TRUE;
1484 if (m->klass->valuetype)
1485 need_unbox_tramp = TRUE;
1488 // FIXME: This can throw exceptions
1489 addr = compiled_method = mono_compile_method (m);
1492 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1494 if (!gsharedvt && generic_virtual) {
1495 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1496 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1498 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1499 vt, vt->vtable + slot,
1500 generic_virtual, ftndesc);
1507 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1509 g_assert (this_obj);
1511 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1515 * mono_resolve_generic_virtual_call:
1517 * Resolve a generic virtual call.
1518 * This function is called on a slowpath, so it doesn't need to be fast.
1521 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1524 gpointer addr, compiled_method;
1525 gboolean need_unbox_tramp = FALSE;
1527 MonoGenericContext context = { NULL, NULL };
1528 MonoMethod *declaring;
1529 gpointer arg = NULL;
1531 m = mono_class_get_vtable_entry (vt->klass, slot);
1533 g_assert (is_generic_method_definition (m));
1536 declaring = mono_method_get_declaring_generic_method (m);
1540 if (m->klass->generic_class)
1541 context.class_inst = m->klass->generic_class->context.class_inst;
1543 g_assert (!m->klass->generic_container);
1545 g_assert (generic_virtual->is_inflated);
1546 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1548 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1549 g_assert (mono_error_ok (&error));
1551 if (vt->klass->valuetype)
1552 need_unbox_tramp = TRUE;
1554 // FIXME: This can throw exceptions
1555 addr = compiled_method = mono_compile_method (m);
1558 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1561 * This wastes memory but the memory usage is bounded since
1562 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1563 * this vtable slot so we are not called any more for this instantiation.
1565 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1567 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1568 vt, vt->vtable + slot,
1569 generic_virtual, ftndesc);
1574 * mono_resolve_generic_virtual_call:
1576 * Resolve a generic virtual/variant iface call on interfaces.
1577 * This function is called on a slowpath, so it doesn't need to be fast.
1580 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1582 MonoMethod *m, *variant_iface;
1583 gpointer addr, aot_addr, compiled_method;
1584 gboolean need_unbox_tramp = FALSE;
1585 gboolean need_rgctx_tramp;
1586 gpointer arg = NULL;
1589 imt = (gpointer*)vt - MONO_IMT_SIZE;
1591 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1593 if (vt->klass->valuetype)
1594 need_unbox_tramp = TRUE;
1596 // FIXME: This can throw exceptions
1597 addr = compiled_method = mono_compile_method (m);
1600 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1603 * This wastes memory but the memory usage is bounded since
1604 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1605 * this vtable slot so we are not called any more for this instantiation.
1607 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1609 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1611 variant_iface ? variant_iface : generic_virtual, ftndesc);
1616 * mono_init_vtable_slot:
1618 * Initialize slot SLOT of VTABLE.
1619 * Return the contents of the vtable slot.
1622 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1624 gpointer arg = NULL;
1628 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1629 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1632 mono_memory_barrier ();
1634 vtable->vtable [slot] = ftnptr;
1640 * mono_llvmonly_init_delegate:
1642 * Initialize a MonoDelegate object.
1643 * Similar to mono_delegate_ctor ().
1646 mono_llvmonly_init_delegate (MonoDelegate *del)
1648 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1651 * We store a MonoFtnDesc in del->method_code.
1652 * It would be better to store an ftndesc in del->method_ptr too,
1653 * but we don't have a a structure which could own its memory.
1655 if (G_UNLIKELY (!ftndesc)) {
1656 gpointer addr = mono_compile_method (del->method);
1657 gpointer arg = mini_get_delegate_arg (del->method, addr);
1659 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1660 mono_memory_barrier ();
1661 *del->method_code = (gpointer)ftndesc;
1663 del->method_ptr = ftndesc->addr;
1664 del->extra_arg = ftndesc->arg;
1668 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1672 method = mono_object_get_virtual_method (target, method);
1674 del->method = method;
1675 del->method_ptr = mono_compile_method (method);
1676 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1680 mono_get_assembly_object (MonoImage *image)
1682 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1686 mono_get_method_object (MonoMethod *method)
1688 return (MonoObject*)mono_method_get_object (mono_domain_get (), method, method->klass);
1692 mono_ckfinite (double d)
1694 if (isinf (d) || isnan (d))
1695 mono_set_pending_exception (mono_get_exception_arithmetic ());
1700 mono_llvmonly_set_calling_assembly (MonoImage *image)
1702 MonoJitTlsData *jit_tls = NULL;
1704 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1706 jit_tls->calling_image = image;
1710 mono_llvmonly_get_calling_assembly (void)
1712 MonoJitTlsData *jit_tls = NULL;
1714 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1716 if (!jit_tls->calling_image)
1717 mono_raise_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
1718 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);