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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 * mono_resolve_iface_call:
1333 * Return the executable code for the iface method IMT_METHOD called on THIS.
1336 mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
1339 gpointer *imt, *vtable_slot;
1340 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1341 gpointer addr, compiled_method, aot_addr;
1342 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1344 // FIXME: Optimize this
1347 /* The caller will handle it */
1350 vt = this_obj->vtable;
1351 imt = (gpointer*)vt - MONO_IMT_SIZE;
1353 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1355 // FIXME: This can throw exceptions
1356 addr = compiled_method = mono_compile_method (impl_method);
1359 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
1360 generic_virtual = imt_method;
1361 need_rgctx_tramp = TRUE;
1364 if (generic_virtual || variant_iface) {
1365 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1366 need_unbox_tramp = TRUE;
1368 if (impl_method->klass->valuetype)
1369 need_unbox_tramp = TRUE;
1372 addr = mini_add_method_trampoline (impl_method, addr, need_rgctx_tramp, need_unbox_tramp);
1374 if (generic_virtual || variant_iface) {
1375 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1377 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1382 *vtable_slot = addr;
1384 if (need_rgctx_tramp && out_rgctx_arg) {
1385 MonoMethod *m = impl_method;
1389 * The exact compiled method might not be shared so it doesn't have an rgctx arg.
1391 ji = mini_jit_info_table_find (mono_domain_get (), compiled_method, NULL);
1392 if (!ji || (ji && ji->has_generic_jit_info)) {
1393 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && m->klass->rank && strstr (m->name, "System.Collections.Generic"))
1394 m = mono_aot_get_array_helper_from_wrapper (m);
1395 *out_rgctx_arg = mini_method_get_rgctx (m);
1403 is_generic_method_definition (MonoMethod *m)
1405 MonoGenericContext *context;
1408 if (!m->is_inflated)
1411 context = mono_method_get_context (m);
1412 if (!context->method_inst)
1414 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1420 * mono_resolve_vcall:
1422 * Return the executable code for calling this_obj->vtable [slot].
1425 mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method)
1428 MonoMethod *m, *generic_virtual = NULL;
1429 gpointer *vtable_slot;
1431 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1433 // FIXME: Optimize this
1436 /* The caller will handle it */
1439 vt = this_obj->vtable;
1441 vtable_slot = &(vt->vtable [slot]);
1443 /* Same as in common_call_trampoline () */
1445 /* Avoid loading metadata or creating a generic vtable if possible */
1446 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1447 if (addr && !vt->klass->valuetype) {
1448 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
1449 *vtable_slot = addr;
1451 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 */
1478 /* FIXME: only do this if the method is sharable */
1480 //g_assert_not_reached ();
1481 //need_rgctx_tramp = TRUE;
1484 if (generic_virtual) {
1485 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1486 need_unbox_tramp = TRUE;
1488 if (m->klass->valuetype)
1489 need_unbox_tramp = TRUE;
1492 // FIXME: This can throw exceptions
1493 addr = mono_compile_method (m);
1496 addr = mini_add_method_trampoline (m, addr, need_rgctx_tramp, need_unbox_tramp);
1498 *vtable_slot = addr;
1504 * mono_init_delegate:
1506 * Initialize a MonoDelegate object.
1507 * Similar to mono_delegate_ctor ().
1510 mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1512 MONO_OBJECT_SETREF (del, target, target);
1513 del->method = method;
1514 del->method_ptr = mono_compile_method (method);
1515 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1516 del->rgctx = mini_method_get_rgctx (method);
1520 mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1524 method = mono_object_get_virtual_method (target, method);
1526 MONO_OBJECT_SETREF (del, target, target);
1527 del->method = method;
1528 del->method_ptr = mono_compile_method (method);
1529 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1530 del->rgctx = mini_method_get_rgctx (method);
1534 mono_get_assembly_object (MonoImage *image)
1536 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1540 mono_ckfinite (double d)
1542 if (isinf (d) || isnan (d))
1543 mono_set_pending_exception (mono_get_exception_arithmetic ());