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, ...)
661 MonoDomain *domain = mono_domain_get ();
664 intptr_t *lower_bounds;
669 pcount = mono_method_signature (cm)->param_count;
670 rank = cm->klass->rank;
674 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
675 for (i = 0; i < pcount; ++i)
676 lengths [i] = d = va_arg(ap, int);
678 if (rank == pcount) {
679 /* Only lengths provided. */
680 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
681 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
682 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
687 g_assert (pcount == (rank * 2));
688 /* lower bounds are first. */
689 lower_bounds = (intptr_t*)lengths;
694 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
697 /* Specialized version of mono_array_new_va () which avoids varargs */
699 mono_array_new_1 (MonoMethod *cm, guint32 length)
701 MonoDomain *domain = mono_domain_get ();
702 uintptr_t lengths [1];
703 intptr_t *lower_bounds;
707 pcount = mono_method_signature (cm)->param_count;
708 rank = cm->klass->rank;
710 lengths [0] = length;
712 g_assert (rank == pcount);
714 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
715 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
716 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
721 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
725 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
727 MonoDomain *domain = mono_domain_get ();
728 uintptr_t lengths [2];
729 intptr_t *lower_bounds;
733 pcount = mono_method_signature (cm)->param_count;
734 rank = cm->klass->rank;
736 lengths [0] = length1;
737 lengths [1] = length2;
739 g_assert (rank == pcount);
741 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
742 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
743 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
748 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
752 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
754 MonoDomain *domain = mono_domain_get ();
755 uintptr_t lengths [3];
756 intptr_t *lower_bounds;
760 pcount = mono_method_signature (cm)->param_count;
761 rank = cm->klass->rank;
763 lengths [0] = length1;
764 lengths [1] = length2;
765 lengths [2] = length3;
767 g_assert (rank == pcount);
769 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
770 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
771 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
776 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
780 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
782 MonoDomain *domain = mono_domain_get ();
783 uintptr_t lengths [4];
784 intptr_t *lower_bounds;
788 pcount = mono_method_signature (cm)->param_count;
789 rank = cm->klass->rank;
791 lengths [0] = length1;
792 lengths [1] = length2;
793 lengths [2] = length3;
794 lengths [3] = length4;
796 g_assert (rank == pcount);
798 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
799 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
800 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
805 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
809 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
814 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
816 mono_class_init (field->parent);
818 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
819 if (!vtable->initialized)
820 mono_runtime_class_init (vtable);
822 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
824 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
825 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
827 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
833 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
836 MonoClass *handle_class;
839 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
840 if (!mono_error_ok (&error)) {
841 mono_error_set_pending_exception (&error);
844 mono_class_init (handle_class);
850 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
852 MonoMethodSignature *sig = mono_method_signature (method);
853 MonoGenericContext *generic_context;
855 if (sig->is_inflated) {
856 generic_context = mono_method_get_context (method);
858 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
859 g_assert (generic_container);
860 generic_context = &generic_container->context;
863 return mono_ldtoken_wrapper (image, token, generic_context);
867 mono_fconv_u8 (double v)
873 mono_rconv_u8 (float v)
878 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
880 mono_fconv_i8 (double v)
887 mono_fconv_u4 (double v)
889 /* MS.NET behaves like this for some reason */
891 if (isinf (v) || isnan (v))
899 /* Solaris doesn't have trunc */
901 extern long double aintl (long double);
904 /* FIXME: This means we will never throw overflow exceptions */
907 #endif /* HAVE_TRUNC */
910 mono_fconv_ovf_i8 (double v)
916 if (isnan(v) || trunc (v) != res) {
917 mono_set_pending_exception (mono_get_exception_overflow ());
924 mono_fconv_ovf_u8 (double v)
929 * The soft-float implementation of some ARM devices have a buggy guin64 to double
930 * conversion that it looses precision even when the integer if fully representable
933 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
935 * To work around this issue we test for value boundaries instead.
937 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
938 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
939 mono_set_pending_exception (mono_get_exception_overflow ());
945 if (isnan(v) || trunc (v) != res) {
946 mono_set_pending_exception (mono_get_exception_overflow ());
953 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
955 mono_rconv_i8 (float v)
962 mono_rconv_ovf_i8 (float v)
968 if (isnan(v) || trunc (v) != res) {
969 mono_set_pending_exception (mono_get_exception_overflow ());
976 mono_rconv_ovf_u8 (float v)
981 if (isnan(v) || trunc (v) != res) {
982 mono_set_pending_exception (mono_get_exception_overflow ());
988 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
990 mono_lconv_to_r8 (gint64 a)
996 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
998 mono_lconv_to_r4 (gint64 a)
1004 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1006 mono_conv_to_r8_un (guint32 a)
1012 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1014 mono_lconv_to_r8_un (guint64 a)
1020 #if defined(__native_client_codegen__) || defined(__native_client__)
1021 /* When we cross-compile to Native Client we can't directly embed calls */
1022 /* to the math library on the host. This will use the fmod on the target*/
1024 mono_fmod(double a, double b)
1031 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1033 MonoMethod *vmethod;
1035 MonoGenericContext *context = mono_method_get_context (method);
1037 mono_jit_stats.generic_virtual_invocations++;
1040 mono_set_pending_exception (mono_get_exception_null_reference ());
1043 vmethod = mono_object_get_virtual_method (obj, method);
1044 g_assert (!vmethod->klass->generic_container);
1045 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1046 g_assert (!context->method_inst || !context->method_inst->is_open);
1048 addr = mono_compile_method (vmethod);
1050 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1052 /* Since this is a virtual call, have to unbox vtypes */
1053 if (obj->vtable->klass->valuetype)
1054 *this_arg = mono_object_unbox (obj);
1062 mono_helper_ldstr (MonoImage *image, guint32 idx)
1064 return mono_ldstr (mono_domain_get (), image, idx);
1068 mono_helper_ldstr_mscorlib (guint32 idx)
1070 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1074 mono_helper_newobj_mscorlib (guint32 idx)
1077 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1079 if (!mono_error_ok (&error)) {
1080 mono_error_set_pending_exception (&error);
1084 return mono_object_new (mono_domain_get (), klass);
1088 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1089 * in generated code. So instead we emit a call to this function and place a gdb
1098 mono_create_corlib_exception_0 (guint32 token)
1100 return mono_exception_from_token (mono_defaults.corlib, token);
1104 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1106 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1110 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1112 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1116 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1118 MonoJitTlsData *jit_tls = NULL;
1121 if (mini_get_debug_options ()->better_cast_details) {
1122 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1123 jit_tls->class_cast_from = NULL;
1129 oklass = obj->vtable->klass;
1130 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1132 if (mono_object_isinst (obj, klass))
1135 if (mini_get_debug_options ()->better_cast_details) {
1136 jit_tls->class_cast_from = oklass;
1137 jit_tls->class_cast_to = klass;
1140 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1141 "System", "InvalidCastException"));
1147 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1149 MonoJitTlsData *jit_tls = NULL;
1150 gpointer cached_vtable, obj_vtable;
1152 if (mini_get_debug_options ()->better_cast_details) {
1153 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1154 jit_tls->class_cast_from = NULL;
1160 cached_vtable = *cache;
1161 obj_vtable = obj->vtable;
1163 if (cached_vtable == obj_vtable)
1166 if (mono_object_isinst (obj, klass)) {
1167 *cache = obj_vtable;
1171 if (mini_get_debug_options ()->better_cast_details) {
1172 jit_tls->class_cast_from = obj->vtable->klass;
1173 jit_tls->class_cast_to = klass;
1176 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1177 "System", "InvalidCastException"));
1183 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1185 size_t cached_vtable, obj_vtable;
1190 cached_vtable = (size_t)*cache;
1191 obj_vtable = (size_t)obj->vtable;
1193 if ((cached_vtable & ~0x1) == obj_vtable) {
1194 return (cached_vtable & 0x1) ? NULL : obj;
1197 if (mono_object_isinst (obj, klass)) {
1198 *cache = (gpointer)obj_vtable;
1202 *cache = (gpointer)(obj_vtable | 0x1);
1208 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1210 MonoMarshalSpec **mspecs;
1211 MonoMethodPInvoke piinfo;
1214 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1215 memset (&piinfo, 0, sizeof (piinfo));
1217 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1219 return mono_compile_method (m);
1223 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1226 int vt_slot, iface_offset;
1228 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1229 MonoObject *this_obj;
1231 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1232 this_obj = *(MonoObject**)mp;
1233 g_assert (this_obj);
1235 klass = this_obj->vtable->klass;
1238 if (mono_method_signature (cmethod)->pinvoke) {
1239 /* Object.GetType () */
1240 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1242 /* Lookup the virtual method */
1243 mono_class_setup_vtable (klass);
1244 g_assert (klass->vtable);
1245 vt_slot = mono_method_get_vtable_slot (cmethod);
1246 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1247 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1248 g_assert (iface_offset != -1);
1249 vt_slot += iface_offset;
1251 m = klass->vtable [vt_slot];
1252 if (cmethod->is_inflated)
1253 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1256 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1258 * Calling a non-vtype method with a vtype receiver, has to box.
1260 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1261 else if (klass->valuetype)
1263 * Calling a vtype method with a vtype receiver
1268 * Calling a non-vtype method
1270 *this_arg = *(gpointer*)mp;
1275 * mono_gsharedvt_constrained_call:
1277 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1278 * the arguments to the method in the format used by mono_runtime_invoke ().
1281 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1285 gpointer new_args [16];
1287 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1290 if (args && deref_arg) {
1291 new_args [0] = *(gpointer*)args [0];
1294 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1295 /* Object.GetType () */
1297 args [0] = this_arg;
1300 return mono_runtime_invoke (m, this_arg, args, NULL);
1304 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1306 if (klass->valuetype)
1307 mono_value_copy (dest, src, klass);
1309 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1313 mono_generic_class_init (MonoVTable *vtable)
1315 mono_runtime_class_init (vtable);
1319 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1321 return mono_class_fill_runtime_generic_context (vtable, index);
1325 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1327 return mono_method_fill_runtime_generic_context (mrgctx, index);
1331 * resolve_iface_call:
1333 * Return the executable code for the iface method IMT_METHOD called on THIS.
1334 * This function is called on a slowpath, so it doesn't need to be fast.
1335 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1339 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1342 gpointer *imt, *vtable_slot;
1343 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1344 gpointer addr, compiled_method, aot_addr;
1345 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1348 /* The caller will handle it */
1351 vt = this_obj->vtable;
1352 imt = (gpointer*)vt - MONO_IMT_SIZE;
1354 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1356 // FIXME: This can throw exceptions
1357 addr = compiled_method = mono_compile_method (impl_method);
1360 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1361 generic_virtual = imt_method;
1363 if (generic_virtual || variant_iface) {
1364 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1365 need_unbox_tramp = TRUE;
1367 if (impl_method->klass->valuetype)
1368 need_unbox_tramp = TRUE;
1371 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1373 if (generic_virtual || variant_iface) {
1374 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1376 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1385 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1387 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1391 is_generic_method_definition (MonoMethod *m)
1393 MonoGenericContext *context;
1396 if (!m->is_inflated)
1399 context = mono_method_get_context (m);
1400 if (!context->method_inst)
1402 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1410 * Return the executable code for calling vt->vtable [slot].
1411 * This function is called on a slowpath, so it doesn't need to be fast.
1412 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1416 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1418 MonoMethod *m, *generic_virtual = NULL;
1419 gpointer addr, compiled_method;
1420 gboolean need_unbox_tramp = FALSE;
1422 /* Same as in common_call_trampoline () */
1424 /* Avoid loading metadata or creating a generic vtable if possible */
1425 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1426 if (addr && !vt->klass->valuetype)
1427 return mono_create_ftnptr (mono_domain_get (), addr);
1429 m = mono_class_get_vtable_entry (vt->klass, slot);
1431 if (is_generic_method_definition (m)) {
1433 MonoGenericContext context = { NULL, NULL };
1434 MonoMethod *declaring;
1437 declaring = mono_method_get_declaring_generic_method (m);
1441 if (m->klass->generic_class)
1442 context.class_inst = m->klass->generic_class->context.class_inst;
1444 g_assert (!m->klass->generic_container);
1446 generic_virtual = imt_method;
1447 g_assert (generic_virtual);
1448 g_assert (generic_virtual->is_inflated);
1449 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1451 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1452 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1455 if (generic_virtual) {
1456 if (vt->klass->valuetype)
1457 need_unbox_tramp = TRUE;
1459 if (m->klass->valuetype)
1460 need_unbox_tramp = TRUE;
1463 // FIXME: This can throw exceptions
1464 addr = compiled_method = mono_compile_method (m);
1467 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, out_arg);
1471 * The caller uses the gsharedvt calling convention, have to add an out wrapper.
1475 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (imt_method), NULL, -1, FALSE);
1476 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, *out_arg);
1479 *out_arg = out_wrapper_arg;
1482 if (!gsharedvt && generic_virtual) {
1483 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1484 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1486 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1487 vt, vt->vtable + slot,
1488 generic_virtual, ftndesc);
1495 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1497 g_assert (this_obj);
1499 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1503 * mono_resolve_generic_virtual_call:
1505 * Resolve a generic virtual call.
1506 * This function is called on a slowpath, so it doesn't need to be fast.
1509 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1512 gpointer addr, compiled_method;
1513 gboolean need_unbox_tramp = FALSE;
1515 MonoGenericContext context = { NULL, NULL };
1516 MonoMethod *declaring;
1517 gpointer arg = NULL;
1519 m = mono_class_get_vtable_entry (vt->klass, slot);
1521 g_assert (is_generic_method_definition (m));
1524 declaring = mono_method_get_declaring_generic_method (m);
1528 if (m->klass->generic_class)
1529 context.class_inst = m->klass->generic_class->context.class_inst;
1531 g_assert (!m->klass->generic_container);
1533 g_assert (generic_virtual->is_inflated);
1534 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1536 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1537 g_assert (mono_error_ok (&error));
1539 if (vt->klass->valuetype)
1540 need_unbox_tramp = TRUE;
1542 // FIXME: This can throw exceptions
1543 addr = compiled_method = mono_compile_method (m);
1546 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1549 * This wastes memory but the memory usage is bounded since
1550 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1551 * this vtable slot so we are not called any more for this instantiation.
1553 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1555 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1556 vt, vt->vtable + slot,
1557 generic_virtual, ftndesc);
1562 * mono_resolve_generic_virtual_call:
1564 * Resolve a generic virtual call on interfaces.
1565 * This function is called on a slowpath, so it doesn't need to be fast.
1568 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1570 MonoMethod *m, *variant_iface;
1571 gpointer addr, aot_addr, compiled_method;
1572 gboolean need_unbox_tramp = FALSE;
1573 gboolean need_rgctx_tramp;
1574 gpointer arg = NULL;
1577 imt = (gpointer*)vt - MONO_IMT_SIZE;
1579 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1580 g_assert (!variant_iface);
1582 if (vt->klass->valuetype)
1583 need_unbox_tramp = TRUE;
1585 // FIXME: This can throw exceptions
1586 addr = compiled_method = mono_compile_method (m);
1589 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1592 * This wastes memory but the memory usage is bounded since
1593 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1594 * this vtable slot so we are not called any more for this instantiation.
1596 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1598 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1600 generic_virtual, ftndesc);
1605 * mono_init_vtable_slot:
1607 * Initialize slot SLOT of VTABLE.
1608 * Return the contents of the vtable slot.
1611 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1613 gpointer arg = NULL;
1617 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1618 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1621 mono_memory_barrier ();
1623 vtable->vtable [slot] = ftnptr;
1629 * mono_init_delegate:
1631 * Initialize a MonoDelegate object.
1632 * Similar to mono_delegate_ctor ().
1635 mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1637 MONO_OBJECT_SETREF (del, target, target);
1638 del->method = method;
1639 del->method_ptr = mono_compile_method (method);
1641 del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
1643 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1644 del->rgctx = mini_method_get_rgctx (method);
1649 mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1653 method = mono_object_get_virtual_method (target, method);
1655 MONO_OBJECT_SETREF (del, target, target);
1656 del->method = method;
1657 del->method_ptr = mono_compile_method (method);
1659 del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
1661 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1662 del->rgctx = mini_method_get_rgctx (method);
1667 mono_get_assembly_object (MonoImage *image)
1669 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1673 mono_ckfinite (double d)
1675 if (isinf (d) || isnan (d))
1676 mono_set_pending_exception (mono_get_exception_arithmetic ());