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>
22 mono_ldftn (MonoMethod *method)
28 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
30 return mono_create_ftnptr (mono_domain_get (), addr);
34 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
42 mono_raise_exception (mono_get_exception_null_reference ());
44 res = mono_object_get_virtual_method (obj, method);
46 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
47 MonoGenericContext context = { NULL, NULL };
49 if (res->klass->generic_class)
50 context.class_inst = res->klass->generic_class->context.class_inst;
51 else if (res->klass->generic_container)
52 context.class_inst = res->klass->generic_container->context.class_inst;
53 context.method_inst = mono_method_get_context (method)->method_inst;
55 res = mono_class_inflate_generic_method_checked (res, &context, &error);
56 mono_error_raise_exception (&error);
59 /* An rgctx wrapper is added by the trampolines no need to do it here */
61 return mono_ldftn (res);
65 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
67 return ldvirtfn_internal (obj, method, FALSE);
71 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
73 return ldvirtfn_internal (obj, method, TRUE);
77 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
82 mono_raise_exception (mono_get_exception_null_reference ());
83 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
84 mono_raise_exception (mono_get_exception_array_type_mismatch ());
87 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
90 mono_llmult (gint64 a, gint64 b)
92 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
97 mono_llmult_ovf_un (guint64 a, guint64 b)
100 guint32 ah = a >> 32;
102 guint32 bh = b >> 32;
107 // fixme: this is incredible slow
110 goto raise_exception;
112 res = (guint64)al * (guint64)bl;
114 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
117 goto raise_exception;
119 res += ((guint64)t1) << 32;
124 mono_raise_exception (mono_get_exception_overflow ());
129 mono_llmult_ovf (gint64 a, gint64 b)
136 Use Karatsuba algorithm where:
137 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
138 where Ah is the "high half" (most significant 32 bits) of a and
139 where Al is the "low half" (least significant 32 bits) of a and
140 where Bh is the "high half" of b and Bl is the "low half" and
141 where R is the Radix or "size of the half" (in our case 32 bits)
143 Note, for the product of two 64 bit numbers to fit into a 64
144 result, ah and/or bh must be 0. This will save us from doing
145 the AhBh term at all.
147 Also note that we refactor so that we don't overflow 64 bits with
148 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
156 /* need to work with absoulte values, so find out what the
157 resulting sign will be and convert any negative numbers
158 from two's complement
162 if (((guint32)ah == 0x80000000) && (al == 0)) {
163 /* This has no two's complement */
169 goto raise_exception;
172 /* flip the bits and add 1 */
183 if (((guint32)bh == 0x80000000) && (bl == 0)) {
184 /* This has no two's complement */
190 goto raise_exception;
193 /* flip the bits and add 1 */
203 /* we overflow for sure if both upper halves are greater
204 than zero because we would need to shift their
205 product 64 bits to the left and that will not fit
206 in a 64 bit result */
208 goto raise_exception;
209 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
210 goto raise_exception;
212 /* do the AlBl term first */
213 t1 = (gint64)al * (gint64)bl;
217 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
218 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
219 /* check for overflow */
221 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
222 goto raise_exception;
227 goto raise_exception;
235 mono_raise_exception (mono_get_exception_overflow ());
240 mono_lldiv (gint64 a, gint64 b)
244 #ifdef MONO_ARCH_NEED_DIV_CHECK
246 mono_raise_exception (mono_get_exception_divide_by_zero ());
247 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
248 mono_raise_exception (mono_get_exception_arithmetic ());
254 mono_llrem (gint64 a, gint64 b)
258 #ifdef MONO_ARCH_NEED_DIV_CHECK
260 mono_raise_exception (mono_get_exception_divide_by_zero ());
261 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
262 mono_raise_exception (mono_get_exception_arithmetic ());
268 mono_lldiv_un (guint64 a, guint64 b)
272 #ifdef MONO_ARCH_NEED_DIV_CHECK
274 mono_raise_exception (mono_get_exception_divide_by_zero ());
280 mono_llrem_un (guint64 a, guint64 b)
284 #ifdef MONO_ARCH_NEED_DIV_CHECK
286 mono_raise_exception (mono_get_exception_divide_by_zero ());
293 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
296 mono_lshl (guint64 a, gint32 shamt)
300 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
303 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
309 mono_lshr_un (guint64 a, gint32 shamt)
313 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
316 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
322 mono_lshr (gint64 a, gint32 shamt)
326 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
329 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
336 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
339 mono_idiv (gint32 a, gint32 b)
343 #ifdef MONO_ARCH_NEED_DIV_CHECK
345 mono_raise_exception (mono_get_exception_divide_by_zero ());
346 else if (b == -1 && a == (0x80000000))
347 mono_raise_exception (mono_get_exception_overflow ());
353 mono_idiv_un (guint32 a, guint32 b)
357 #ifdef MONO_ARCH_NEED_DIV_CHECK
359 mono_raise_exception (mono_get_exception_divide_by_zero ());
365 mono_irem (gint32 a, gint32 b)
369 #ifdef MONO_ARCH_NEED_DIV_CHECK
371 mono_raise_exception (mono_get_exception_divide_by_zero ());
372 else if (b == -1 && a == (0x80000000))
373 mono_raise_exception (mono_get_exception_overflow ());
380 mono_irem_un (guint32 a, guint32 b)
384 #ifdef MONO_ARCH_NEED_DIV_CHECK
386 mono_raise_exception (mono_get_exception_divide_by_zero ());
393 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
396 mono_imul (gint32 a, gint32 b)
404 mono_imul_ovf (gint32 a, gint32 b)
410 res = (gint64)a * (gint64)b;
412 if ((res > 0x7fffffffL) || (res < -2147483648LL))
413 mono_raise_exception (mono_get_exception_overflow ());
419 mono_imul_ovf_un (guint32 a, guint32 b)
425 res = (guint64)a * (guint64)b;
428 mono_raise_exception (mono_get_exception_overflow ());
434 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
436 mono_fdiv (double a, double b)
444 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
447 mono_fsub (double a, double b)
453 mono_fadd (double a, double b)
459 mono_fmul (double a, double b)
471 mono_fconv_r4 (double a)
477 mono_conv_to_r8 (int a)
483 mono_conv_to_r4 (int a)
485 return (double)(float)a;
489 mono_fconv_i1 (double a)
495 mono_fconv_i2 (double a)
501 mono_fconv_i4 (double a)
507 mono_fconv_u1 (double a)
513 mono_fconv_u2 (double a)
519 mono_fcmp_eq (double a, double b)
525 mono_fcmp_ge (double a, double b)
531 mono_fcmp_gt (double a, double b)
537 mono_fcmp_le (double a, double b)
543 mono_fcmp_lt (double a, double b)
549 mono_fcmp_ne_un (double a, double b)
551 return isunordered (a, b) || a != b;
555 mono_fcmp_ge_un (double a, double b)
557 return isunordered (a, b) || a >= b;
561 mono_fcmp_gt_un (double a, double b)
563 return isunordered (a, b) || a > b;
567 mono_fcmp_le_un (double a, double b)
569 return isunordered (a, b) || a <= b;
573 mono_fcmp_lt_un (double a, double b)
575 return isunordered (a, b) || a < b;
579 mono_fceq (double a, double b)
585 mono_fcgt (double a, double b)
591 mono_fcgt_un (double a, double b)
593 return isunordered (a, b) || a > b;
597 mono_fclt (double a, double b)
603 mono_fclt_un (double a, double b)
605 return isunordered (a, b) || a < b;
609 mono_isfinite (double a)
614 g_assert_not_reached ();
620 mono_fload_r4 (float *ptr)
626 mono_fstore_r4 (double val, float *ptr)
631 /* returns the integer bitpattern that is passed in the regs or stack */
633 mono_fload_r4_arg (double val)
635 float v = (float)val;
636 return *(guint32*)&v;
642 mono_array_new_va (MonoMethod *cm, ...)
644 MonoDomain *domain = mono_domain_get ();
647 intptr_t *lower_bounds;
654 pcount = mono_method_signature (cm)->param_count;
655 rank = cm->klass->rank;
659 lengths = alloca (sizeof (uintptr_t) * pcount);
660 for (i = 0; i < pcount; ++i)
661 lengths [i] = d = va_arg(ap, int);
663 if (rank == pcount) {
664 /* Only lengths provided. */
665 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
666 lower_bounds = alloca (sizeof (intptr_t) * rank);
667 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
672 g_assert (pcount == (rank * 2));
673 /* lower bounds are first. */
674 lower_bounds = (intptr_t*)lengths;
679 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
682 /* Specialized version of mono_array_new_va () which avoids varargs */
684 mono_array_new_1 (MonoMethod *cm, guint32 length)
686 MonoDomain *domain = mono_domain_get ();
687 uintptr_t lengths [1];
688 intptr_t *lower_bounds;
694 pcount = mono_method_signature (cm)->param_count;
695 rank = cm->klass->rank;
697 lengths [0] = length;
699 g_assert (rank == pcount);
701 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
702 lower_bounds = alloca (sizeof (intptr_t) * rank);
703 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
708 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
712 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
714 MonoDomain *domain = mono_domain_get ();
715 uintptr_t lengths [2];
716 intptr_t *lower_bounds;
722 pcount = mono_method_signature (cm)->param_count;
723 rank = cm->klass->rank;
725 lengths [0] = length1;
726 lengths [1] = length2;
728 g_assert (rank == pcount);
730 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
731 lower_bounds = alloca (sizeof (intptr_t) * rank);
732 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
737 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
741 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
743 MonoDomain *domain = mono_domain_get ();
744 uintptr_t lengths [3];
745 intptr_t *lower_bounds;
751 pcount = mono_method_signature (cm)->param_count;
752 rank = cm->klass->rank;
754 lengths [0] = length1;
755 lengths [1] = length2;
756 lengths [2] = length3;
758 g_assert (rank == pcount);
760 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
761 lower_bounds = alloca (sizeof (intptr_t) * rank);
762 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
767 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
771 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
773 MonoDomain *domain = mono_domain_get ();
774 uintptr_t lengths [4];
775 intptr_t *lower_bounds;
781 pcount = mono_method_signature (cm)->param_count;
782 rank = cm->klass->rank;
784 lengths [0] = length1;
785 lengths [1] = length2;
786 lengths [2] = length3;
787 lengths [3] = length4;
789 g_assert (rank == pcount);
791 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
792 lower_bounds = alloca (sizeof (intptr_t) * rank);
793 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
798 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
802 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
809 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
811 mono_class_init (field->parent);
813 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
814 if (!vtable->initialized)
815 mono_runtime_class_init (vtable);
817 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
819 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
820 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
822 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
828 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
831 MonoClass *handle_class;
835 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
836 mono_error_raise_exception (&error);
837 mono_class_init (handle_class);
843 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
845 MonoMethodSignature *sig = mono_method_signature (method);
846 MonoGenericContext *generic_context;
848 if (sig->is_inflated) {
849 generic_context = mono_method_get_context (method);
851 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
852 g_assert (generic_container);
853 generic_context = &generic_container->context;
856 return mono_ldtoken_wrapper (image, token, generic_context);
860 mono_fconv_u8 (double v)
865 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
867 mono_fconv_i8 (double v)
869 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
875 mono_fconv_u4 (double v)
877 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
879 /* MS.NET behaves like this for some reason */
881 if (isinf (v) || isnan (v))
889 /* Solaris doesn't have trunc */
891 extern long double aintl (long double);
894 /* FIXME: This means we will never throw overflow exceptions */
897 #endif /* HAVE_TRUNC */
900 mono_fconv_ovf_i8 (double v)
908 if (isnan(v) || trunc (v) != res) {
909 mono_raise_exception (mono_get_exception_overflow ());
915 mono_fconv_ovf_u8 (double v)
921 * The soft-float implementation of some ARM devices have a buggy guin64 to double
922 * conversion that it looses precision even when the integer if fully representable
925 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
927 * To work around this issue we test for value boundaries instead.
929 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
930 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
931 mono_raise_exception (mono_get_exception_overflow ());
936 if (isnan(v) || trunc (v) != res) {
937 mono_raise_exception (mono_get_exception_overflow ());
943 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
945 mono_rconv_i8 (float v)
952 mono_rconv_ovf_i8 (float v)
958 if (isnan(v) || trunc (v) != res) {
959 mono_raise_exception (mono_get_exception_overflow ());
965 mono_rconv_ovf_u8 (float v)
970 if (isnan(v) || trunc (v) != res) {
971 mono_raise_exception (mono_get_exception_overflow ());
976 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
978 mono_lconv_to_r8 (gint64 a)
984 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
986 mono_lconv_to_r4 (gint64 a)
992 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
994 mono_conv_to_r8_un (guint32 a)
1000 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1002 mono_lconv_to_r8_un (guint64 a)
1008 #if defined(__native_client_codegen__) || defined(__native_client__)
1009 /* When we cross-compile to Native Client we can't directly embed calls */
1010 /* to the math library on the host. This will use the fmod on the target*/
1012 mono_fmod(double a, double b)
1019 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1021 MonoMethod *vmethod;
1023 MonoGenericContext *context = mono_method_get_context (method);
1025 mono_jit_stats.generic_virtual_invocations++;
1028 mono_raise_exception (mono_get_exception_null_reference ());
1029 vmethod = mono_object_get_virtual_method (obj, method);
1030 g_assert (!vmethod->klass->generic_container);
1031 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1032 g_assert (!context->method_inst || !context->method_inst->is_open);
1034 addr = mono_compile_method (vmethod);
1036 addr = mini_add_method_trampoline (NULL, vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1038 /* Since this is a virtual call, have to unbox vtypes */
1039 if (obj->vtable->klass->valuetype)
1040 *this_arg = mono_object_unbox (obj);
1048 mono_helper_ldstr (MonoImage *image, guint32 idx)
1050 return mono_ldstr (mono_domain_get (), image, idx);
1054 mono_helper_ldstr_mscorlib (guint32 idx)
1056 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1060 mono_helper_newobj_mscorlib (guint32 idx)
1063 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1064 mono_error_raise_exception (&error);
1066 return mono_object_new (mono_domain_get (), klass);
1070 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1071 * in generated code. So instead we emit a call to this function and place a gdb
1080 mono_create_corlib_exception_0 (guint32 token)
1082 return mono_exception_from_token (mono_defaults.corlib, token);
1086 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1088 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1092 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1094 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1098 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1100 MonoJitTlsData *jit_tls = NULL;
1103 if (mini_get_debug_options ()->better_cast_details) {
1104 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1105 jit_tls->class_cast_from = NULL;
1111 oklass = obj->vtable->klass;
1112 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1114 if (mono_object_isinst (obj, klass))
1117 if (mini_get_debug_options ()->better_cast_details) {
1118 jit_tls->class_cast_from = oklass;
1119 jit_tls->class_cast_to = klass;
1122 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1123 "System", "InvalidCastException"));
1129 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1131 MonoJitTlsData *jit_tls = NULL;
1132 gpointer cached_vtable, obj_vtable;
1134 if (mini_get_debug_options ()->better_cast_details) {
1135 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1136 jit_tls->class_cast_from = NULL;
1142 cached_vtable = *cache;
1143 obj_vtable = obj->vtable;
1145 if (cached_vtable == obj_vtable)
1148 if (mono_object_isinst (obj, klass)) {
1149 *cache = obj_vtable;
1153 if (mini_get_debug_options ()->better_cast_details) {
1154 jit_tls->class_cast_from = obj->vtable->klass;
1155 jit_tls->class_cast_to = klass;
1158 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1159 "System", "InvalidCastException"));
1165 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1167 size_t cached_vtable, obj_vtable;
1172 cached_vtable = (size_t)*cache;
1173 obj_vtable = (size_t)obj->vtable;
1175 if ((cached_vtable & ~0x1) == obj_vtable) {
1176 return (cached_vtable & 0x1) ? NULL : obj;
1179 if (mono_object_isinst (obj, klass)) {
1180 *cache = (gpointer)obj_vtable;
1184 *cache = (gpointer)(obj_vtable | 0x1);
1190 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1192 MonoMarshalSpec **mspecs;
1193 MonoMethodPInvoke piinfo;
1196 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1197 memset (&piinfo, 0, sizeof (piinfo));
1199 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1201 return mono_compile_method (m);
1205 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1210 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
1211 mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
1213 if (mono_method_signature (cmethod)->pinvoke) {
1214 /* Object.GetType () */
1215 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1217 /* Lookup the virtual method */
1218 mono_class_setup_vtable (klass);
1219 g_assert (klass->vtable);
1220 vt_slot = mono_method_get_vtable_slot (cmethod);
1221 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1224 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1225 g_assert (iface_offset != -1);
1226 vt_slot += iface_offset;
1228 m = klass->vtable [vt_slot];
1229 if (cmethod->is_inflated)
1230 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1232 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1234 * Calling a non-vtype method with a vtype receiver, has to box.
1236 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1237 else if (klass->valuetype)
1239 * Calling a vtype method with a vtype receiver
1244 * Calling a non-vtype method
1246 *this_arg = *(gpointer*)mp;
1251 * mono_gsharedvt_constrained_call:
1253 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1254 * the arguments to the method in the format used by mono_runtime_invoke ().
1257 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1261 gpointer new_args [16];
1263 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1264 if (args && deref_arg) {
1265 new_args [0] = *(gpointer*)args [0];
1268 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1269 /* Object.GetType () */
1271 args [0] = this_arg;
1274 return mono_runtime_invoke (m, this_arg, args, NULL);
1278 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1280 if (klass->valuetype)
1281 mono_value_copy (dest, src, klass);
1283 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);