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)
26 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
28 return mono_create_ftnptr (mono_domain_get (), addr);
32 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
38 mono_set_pending_exception (mono_get_exception_null_reference ());
42 res = mono_object_get_virtual_method (obj, method);
44 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
45 MonoGenericContext context = { NULL, NULL };
47 if (res->klass->generic_class)
48 context.class_inst = res->klass->generic_class->context.class_inst;
49 else if (res->klass->generic_container)
50 context.class_inst = res->klass->generic_container->context.class_inst;
51 context.method_inst = mono_method_get_context (method)->method_inst;
53 res = mono_class_inflate_generic_method_checked (res, &context, &error);
54 if (!mono_error_ok (&error)) {
55 mono_error_set_pending_exception (&error);
60 /* An rgctx wrapper is added by the trampolines no need to do it here */
62 return mono_ldftn (res);
66 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
68 return ldvirtfn_internal (obj, method, FALSE);
72 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
74 return ldvirtfn_internal (obj, method, TRUE);
78 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
81 mono_set_pending_exception (mono_get_exception_null_reference ());
84 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
85 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
90 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
93 mono_llmult (gint64 a, gint64 b)
99 mono_llmult_ovf_un (guint64 a, guint64 b)
102 guint32 ah = a >> 32;
104 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_set_pending_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
154 /* need to work with absoulte values, so find out what the
155 resulting sign will be and convert any negative numbers
156 from two's complement
160 if (((guint32)ah == 0x80000000) && (al == 0)) {
161 /* This has no two's complement */
167 goto raise_exception;
170 /* flip the bits and add 1 */
181 if (((guint32)bh == 0x80000000) && (bl == 0)) {
182 /* This has no two's complement */
188 goto raise_exception;
191 /* flip the bits and add 1 */
201 /* we overflow for sure if both upper halves are greater
202 than zero because we would need to shift their
203 product 64 bits to the left and that will not fit
204 in a 64 bit result */
206 goto raise_exception;
207 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
208 goto raise_exception;
210 /* do the AlBl term first */
211 t1 = (gint64)al * (gint64)bl;
215 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
216 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
217 /* check for overflow */
219 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
220 goto raise_exception;
225 goto raise_exception;
233 mono_set_pending_exception (mono_get_exception_overflow ());
238 mono_lldiv (gint64 a, gint64 b)
240 #ifdef MONO_ARCH_NEED_DIV_CHECK
242 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
245 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
246 mono_set_pending_exception (mono_get_exception_arithmetic ());
254 mono_llrem (gint64 a, gint64 b)
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
258 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
261 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
262 mono_set_pending_exception (mono_get_exception_arithmetic ());
270 mono_lldiv_un (guint64 a, guint64 b)
272 #ifdef MONO_ARCH_NEED_DIV_CHECK
274 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
282 mono_llrem_un (guint64 a, guint64 b)
284 #ifdef MONO_ARCH_NEED_DIV_CHECK
286 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
295 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
298 mono_lshl (guint64 a, gint32 shamt)
302 res = a << (shamt & 0x7f);
304 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
310 mono_lshr_un (guint64 a, gint32 shamt)
314 res = a >> (shamt & 0x7f);
316 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
322 mono_lshr (gint64 a, gint32 shamt)
326 res = a >> (shamt & 0x7f);
328 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
335 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
338 mono_idiv (gint32 a, gint32 b)
340 #ifdef MONO_ARCH_NEED_DIV_CHECK
342 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
345 else if (b == -1 && a == (0x80000000)) {
346 mono_set_pending_exception (mono_get_exception_overflow ());
354 mono_idiv_un (guint32 a, guint32 b)
356 #ifdef MONO_ARCH_NEED_DIV_CHECK
358 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
366 mono_irem (gint32 a, gint32 b)
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
370 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
373 else if (b == -1 && a == (0x80000000)) {
374 mono_set_pending_exception (mono_get_exception_overflow ());
382 mono_irem_un (guint32 a, guint32 b)
384 #ifdef MONO_ARCH_NEED_DIV_CHECK
386 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
395 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
398 mono_imul (gint32 a, gint32 b)
404 mono_imul_ovf (gint32 a, gint32 b)
408 res = (gint64)a * (gint64)b;
410 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
411 mono_set_pending_exception (mono_get_exception_overflow ());
419 mono_imul_ovf_un (guint32 a, guint32 b)
423 res = (guint64)a * (guint64)b;
426 mono_set_pending_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)
442 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
445 mono_fsub (double a, double b)
451 mono_fadd (double a, double b)
457 mono_fmul (double a, double b)
469 mono_fconv_r4 (double a)
475 mono_conv_to_r8 (int a)
481 mono_conv_to_r4 (int a)
483 return (double)(float)a;
487 mono_fconv_i1 (double a)
493 mono_fconv_i2 (double a)
499 mono_fconv_i4 (double a)
505 mono_fconv_u1 (double a)
511 mono_fconv_u2 (double a)
517 mono_fcmp_eq (double a, double b)
523 mono_fcmp_ge (double a, double b)
529 mono_fcmp_gt (double a, double b)
535 mono_fcmp_le (double a, double b)
541 mono_fcmp_lt (double a, double b)
547 mono_fcmp_ne_un (double a, double b)
549 return isunordered (a, b) || a != b;
553 mono_fcmp_ge_un (double a, double b)
555 return isunordered (a, b) || a >= b;
559 mono_fcmp_gt_un (double a, double b)
561 return isunordered (a, b) || a > b;
565 mono_fcmp_le_un (double a, double b)
567 return isunordered (a, b) || a <= b;
571 mono_fcmp_lt_un (double a, double b)
573 return isunordered (a, b) || a < b;
577 mono_fceq (double a, double b)
583 mono_fcgt (double a, double b)
589 mono_fcgt_un (double a, double b)
591 return isunordered (a, b) || a > b;
595 mono_fclt (double a, double b)
601 mono_fclt_un (double a, double b)
603 return isunordered (a, b) || a < b;
607 mono_isfinite (double a)
612 g_assert_not_reached ();
618 mono_fload_r4 (float *ptr)
624 mono_fstore_r4 (double val, float *ptr)
629 /* returns the integer bitpattern that is passed in the regs or stack */
631 mono_fload_r4_arg (double val)
633 float v = (float)val;
634 return *(guint32*)&v;
640 mono_array_new_va (MonoMethod *cm, ...)
642 MonoDomain *domain = mono_domain_get ();
645 intptr_t *lower_bounds;
650 pcount = mono_method_signature (cm)->param_count;
651 rank = cm->klass->rank;
655 lengths = alloca (sizeof (uintptr_t) * pcount);
656 for (i = 0; i < pcount; ++i)
657 lengths [i] = d = va_arg(ap, int);
659 if (rank == pcount) {
660 /* Only lengths provided. */
661 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
662 lower_bounds = alloca (sizeof (intptr_t) * rank);
663 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
668 g_assert (pcount == (rank * 2));
669 /* lower bounds are first. */
670 lower_bounds = (intptr_t*)lengths;
675 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
678 /* Specialized version of mono_array_new_va () which avoids varargs */
680 mono_array_new_1 (MonoMethod *cm, guint32 length)
682 MonoDomain *domain = mono_domain_get ();
683 uintptr_t lengths [1];
684 intptr_t *lower_bounds;
688 pcount = mono_method_signature (cm)->param_count;
689 rank = cm->klass->rank;
691 lengths [0] = length;
693 g_assert (rank == pcount);
695 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
696 lower_bounds = alloca (sizeof (intptr_t) * rank);
697 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
702 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
706 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
708 MonoDomain *domain = mono_domain_get ();
709 uintptr_t lengths [2];
710 intptr_t *lower_bounds;
714 pcount = mono_method_signature (cm)->param_count;
715 rank = cm->klass->rank;
717 lengths [0] = length1;
718 lengths [1] = length2;
720 g_assert (rank == pcount);
722 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
723 lower_bounds = alloca (sizeof (intptr_t) * rank);
724 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
729 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
733 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
735 MonoDomain *domain = mono_domain_get ();
736 uintptr_t lengths [3];
737 intptr_t *lower_bounds;
741 pcount = mono_method_signature (cm)->param_count;
742 rank = cm->klass->rank;
744 lengths [0] = length1;
745 lengths [1] = length2;
746 lengths [2] = length3;
748 g_assert (rank == pcount);
750 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
751 lower_bounds = alloca (sizeof (intptr_t) * rank);
752 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
757 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
761 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
763 MonoDomain *domain = mono_domain_get ();
764 uintptr_t lengths [4];
765 intptr_t *lower_bounds;
769 pcount = mono_method_signature (cm)->param_count;
770 rank = cm->klass->rank;
772 lengths [0] = length1;
773 lengths [1] = length2;
774 lengths [2] = length3;
775 lengths [3] = length4;
777 g_assert (rank == pcount);
779 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
780 lower_bounds = alloca (sizeof (intptr_t) * rank);
781 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
786 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
790 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
795 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
797 mono_class_init (field->parent);
799 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
800 if (!vtable->initialized)
801 mono_runtime_class_init (vtable);
803 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
805 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
806 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
808 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
814 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
817 MonoClass *handle_class;
820 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
821 if (!mono_error_ok (&error)) {
822 mono_error_set_pending_exception (&error);
825 mono_class_init (handle_class);
831 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
833 MonoMethodSignature *sig = mono_method_signature (method);
834 MonoGenericContext *generic_context;
836 if (sig->is_inflated) {
837 generic_context = mono_method_get_context (method);
839 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
840 g_assert (generic_container);
841 generic_context = &generic_container->context;
844 return mono_ldtoken_wrapper (image, token, generic_context);
848 mono_fconv_u8 (double v)
853 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
855 mono_fconv_i8 (double v)
862 mono_fconv_u4 (double v)
864 /* MS.NET behaves like this for some reason */
866 if (isinf (v) || isnan (v))
874 /* Solaris doesn't have trunc */
876 extern long double aintl (long double);
879 /* FIXME: This means we will never throw overflow exceptions */
882 #endif /* HAVE_TRUNC */
885 mono_fconv_ovf_i8 (double v)
891 if (isnan(v) || trunc (v) != res) {
892 mono_set_pending_exception (mono_get_exception_overflow ());
899 mono_fconv_ovf_u8 (double v)
904 * The soft-float implementation of some ARM devices have a buggy guin64 to double
905 * conversion that it looses precision even when the integer if fully representable
908 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
910 * To work around this issue we test for value boundaries instead.
912 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
913 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
914 mono_set_pending_exception (mono_get_exception_overflow ());
920 if (isnan(v) || trunc (v) != res) {
921 mono_set_pending_exception (mono_get_exception_overflow ());
928 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
930 mono_rconv_i8 (float v)
937 mono_rconv_ovf_i8 (float v)
943 if (isnan(v) || trunc (v) != res) {
944 mono_set_pending_exception (mono_get_exception_overflow ());
951 mono_rconv_ovf_u8 (float v)
956 if (isnan(v) || trunc (v) != res) {
957 mono_set_pending_exception (mono_get_exception_overflow ());
963 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
965 mono_lconv_to_r8 (gint64 a)
971 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
973 mono_lconv_to_r4 (gint64 a)
979 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
981 mono_conv_to_r8_un (guint32 a)
987 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
989 mono_lconv_to_r8_un (guint64 a)
995 #if defined(__native_client_codegen__) || defined(__native_client__)
996 /* When we cross-compile to Native Client we can't directly embed calls */
997 /* to the math library on the host. This will use the fmod on the target*/
999 mono_fmod(double a, double b)
1006 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1008 MonoMethod *vmethod;
1010 MonoGenericContext *context = mono_method_get_context (method);
1012 mono_jit_stats.generic_virtual_invocations++;
1015 mono_set_pending_exception (mono_get_exception_null_reference ());
1018 vmethod = mono_object_get_virtual_method (obj, method);
1019 g_assert (!vmethod->klass->generic_container);
1020 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1021 g_assert (!context->method_inst || !context->method_inst->is_open);
1023 addr = mono_compile_method (vmethod);
1025 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1027 /* Since this is a virtual call, have to unbox vtypes */
1028 if (obj->vtable->klass->valuetype)
1029 *this_arg = mono_object_unbox (obj);
1037 mono_helper_ldstr (MonoImage *image, guint32 idx)
1039 return mono_ldstr (mono_domain_get (), image, idx);
1043 mono_helper_ldstr_mscorlib (guint32 idx)
1045 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1049 mono_helper_newobj_mscorlib (guint32 idx)
1052 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1054 if (!mono_error_ok (&error)) {
1055 mono_error_set_pending_exception (&error);
1059 return mono_object_new (mono_domain_get (), klass);
1063 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1064 * in generated code. So instead we emit a call to this function and place a gdb
1073 mono_create_corlib_exception_0 (guint32 token)
1075 return mono_exception_from_token (mono_defaults.corlib, token);
1079 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1081 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1085 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1087 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1091 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1093 MonoJitTlsData *jit_tls = NULL;
1096 if (mini_get_debug_options ()->better_cast_details) {
1097 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1098 jit_tls->class_cast_from = NULL;
1104 oklass = obj->vtable->klass;
1105 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1107 if (mono_object_isinst (obj, klass))
1110 if (mini_get_debug_options ()->better_cast_details) {
1111 jit_tls->class_cast_from = oklass;
1112 jit_tls->class_cast_to = klass;
1115 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1116 "System", "InvalidCastException"));
1122 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1124 MonoJitTlsData *jit_tls = NULL;
1125 gpointer cached_vtable, obj_vtable;
1127 if (mini_get_debug_options ()->better_cast_details) {
1128 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1129 jit_tls->class_cast_from = NULL;
1135 cached_vtable = *cache;
1136 obj_vtable = obj->vtable;
1138 if (cached_vtable == obj_vtable)
1141 if (mono_object_isinst (obj, klass)) {
1142 *cache = obj_vtable;
1146 if (mini_get_debug_options ()->better_cast_details) {
1147 jit_tls->class_cast_from = obj->vtable->klass;
1148 jit_tls->class_cast_to = klass;
1151 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1152 "System", "InvalidCastException"));
1158 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1160 size_t cached_vtable, obj_vtable;
1165 cached_vtable = (size_t)*cache;
1166 obj_vtable = (size_t)obj->vtable;
1168 if ((cached_vtable & ~0x1) == obj_vtable) {
1169 return (cached_vtable & 0x1) ? NULL : obj;
1172 if (mono_object_isinst (obj, klass)) {
1173 *cache = (gpointer)obj_vtable;
1177 *cache = (gpointer)(obj_vtable | 0x1);
1183 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1185 MonoMarshalSpec **mspecs;
1186 MonoMethodPInvoke piinfo;
1189 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1190 memset (&piinfo, 0, sizeof (piinfo));
1192 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1194 return mono_compile_method (m);
1198 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1203 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1204 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1208 if (mono_method_signature (cmethod)->pinvoke) {
1209 /* Object.GetType () */
1210 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1212 /* Lookup the virtual method */
1213 mono_class_setup_vtable (klass);
1214 g_assert (klass->vtable);
1215 vt_slot = mono_method_get_vtable_slot (cmethod);
1216 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1219 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1220 g_assert (iface_offset != -1);
1221 vt_slot += iface_offset;
1223 m = klass->vtable [vt_slot];
1224 if (cmethod->is_inflated)
1225 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1227 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1229 * Calling a non-vtype method with a vtype receiver, has to box.
1231 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1232 else if (klass->valuetype)
1234 * Calling a vtype method with a vtype receiver
1239 * Calling a non-vtype method
1241 *this_arg = *(gpointer*)mp;
1246 * mono_gsharedvt_constrained_call:
1248 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1249 * the arguments to the method in the format used by mono_runtime_invoke ().
1252 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1256 gpointer new_args [16];
1258 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1261 if (args && deref_arg) {
1262 new_args [0] = *(gpointer*)args [0];
1265 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1266 /* Object.GetType () */
1268 args [0] = this_arg;
1271 return mono_runtime_invoke (m, this_arg, args, NULL);
1275 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1277 if (klass->valuetype)
1278 mono_value_copy (dest, src, klass);
1280 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1284 mono_generic_class_init (MonoVTable *vtable)
1286 mono_runtime_class_init (vtable);
1290 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1292 return mono_class_fill_runtime_generic_context (vtable, index);
1296 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1298 return mono_method_fill_runtime_generic_context (mrgctx, index);