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 mono_error_raise_exception (&error);
57 /* An rgctx wrapper is added by the trampolines no need to do it here */
59 return mono_ldftn (res);
63 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
65 return ldvirtfn_internal (obj, method, FALSE);
69 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
71 return ldvirtfn_internal (obj, method, TRUE);
75 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
78 mono_set_pending_exception (mono_get_exception_null_reference ());
81 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
82 mono_set_pending_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)
96 mono_llmult_ovf_un (guint64 a, guint64 b)
101 guint32 bh = b >> 32;
104 // fixme: this is incredible slow
107 goto raise_exception;
109 res = (guint64)al * (guint64)bl;
111 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
114 goto raise_exception;
116 res += ((guint64)t1) << 32;
121 mono_set_pending_exception (mono_get_exception_overflow ());
126 mono_llmult_ovf (gint64 a, gint64 b)
133 Use Karatsuba algorithm where:
134 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
135 where Ah is the "high half" (most significant 32 bits) of a and
136 where Al is the "low half" (least significant 32 bits) of a and
137 where Bh is the "high half" of b and Bl is the "low half" and
138 where R is the Radix or "size of the half" (in our case 32 bits)
140 Note, for the product of two 64 bit numbers to fit into a 64
141 result, ah and/or bh must be 0. This will save us from doing
142 the AhBh term at all.
144 Also note that we refactor so that we don't overflow 64 bits with
145 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
151 /* need to work with absoulte values, so find out what the
152 resulting sign will be and convert any negative numbers
153 from two's complement
157 if (((guint32)ah == 0x80000000) && (al == 0)) {
158 /* This has no two's complement */
164 goto raise_exception;
167 /* flip the bits and add 1 */
178 if (((guint32)bh == 0x80000000) && (bl == 0)) {
179 /* This has no two's complement */
185 goto raise_exception;
188 /* flip the bits and add 1 */
198 /* we overflow for sure if both upper halves are greater
199 than zero because we would need to shift their
200 product 64 bits to the left and that will not fit
201 in a 64 bit result */
203 goto raise_exception;
204 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
205 goto raise_exception;
207 /* do the AlBl term first */
208 t1 = (gint64)al * (gint64)bl;
212 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
213 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
214 /* check for overflow */
216 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
217 goto raise_exception;
222 goto raise_exception;
230 mono_set_pending_exception (mono_get_exception_overflow ());
235 mono_lldiv (gint64 a, gint64 b)
237 #ifdef MONO_ARCH_NEED_DIV_CHECK
239 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
242 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
243 mono_set_pending_exception (mono_get_exception_arithmetic ());
251 mono_llrem (gint64 a, gint64 b)
253 #ifdef MONO_ARCH_NEED_DIV_CHECK
255 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
258 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
259 mono_set_pending_exception (mono_get_exception_arithmetic ());
267 mono_lldiv_un (guint64 a, guint64 b)
269 #ifdef MONO_ARCH_NEED_DIV_CHECK
271 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
279 mono_llrem_un (guint64 a, guint64 b)
281 #ifdef MONO_ARCH_NEED_DIV_CHECK
283 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
292 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
295 mono_lshl (guint64 a, gint32 shamt)
301 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
307 mono_lshr_un (guint64 a, gint32 shamt)
313 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
319 mono_lshr (gint64 a, gint32 shamt)
325 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
332 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
335 mono_idiv (gint32 a, gint32 b)
337 #ifdef MONO_ARCH_NEED_DIV_CHECK
339 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
342 else if (b == -1 && a == (0x80000000)) {
343 mono_set_pending_exception (mono_get_exception_overflow ());
351 mono_idiv_un (guint32 a, guint32 b)
353 #ifdef MONO_ARCH_NEED_DIV_CHECK
355 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
363 mono_irem (gint32 a, gint32 b)
365 #ifdef MONO_ARCH_NEED_DIV_CHECK
367 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
370 else if (b == -1 && a == (0x80000000)) {
371 mono_set_pending_exception (mono_get_exception_overflow ());
379 mono_irem_un (guint32 a, guint32 b)
381 #ifdef MONO_ARCH_NEED_DIV_CHECK
383 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
392 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
395 mono_imul (gint32 a, gint32 b)
401 mono_imul_ovf (gint32 a, gint32 b)
405 res = (gint64)a * (gint64)b;
407 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
408 mono_set_pending_exception (mono_get_exception_overflow ());
416 mono_imul_ovf_un (guint32 a, guint32 b)
420 res = (guint64)a * (guint64)b;
423 mono_set_pending_exception (mono_get_exception_overflow ());
431 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
433 mono_fdiv (double a, double b)
439 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
442 mono_fsub (double a, double b)
448 mono_fadd (double a, double b)
454 mono_fmul (double a, double b)
466 mono_fconv_r4 (double a)
472 mono_conv_to_r8 (int a)
478 mono_conv_to_r4 (int a)
480 return (double)(float)a;
484 mono_fconv_i1 (double a)
490 mono_fconv_i2 (double a)
496 mono_fconv_i4 (double a)
502 mono_fconv_u1 (double a)
508 mono_fconv_u2 (double a)
514 mono_fcmp_eq (double a, double b)
520 mono_fcmp_ge (double a, double b)
526 mono_fcmp_gt (double a, double b)
532 mono_fcmp_le (double a, double b)
538 mono_fcmp_lt (double a, double b)
544 mono_fcmp_ne_un (double a, double b)
546 return isunordered (a, b) || a != b;
550 mono_fcmp_ge_un (double a, double b)
552 return isunordered (a, b) || a >= b;
556 mono_fcmp_gt_un (double a, double b)
558 return isunordered (a, b) || a > b;
562 mono_fcmp_le_un (double a, double b)
564 return isunordered (a, b) || a <= b;
568 mono_fcmp_lt_un (double a, double b)
570 return isunordered (a, b) || a < b;
574 mono_fceq (double a, double b)
580 mono_fcgt (double a, double b)
586 mono_fcgt_un (double a, double b)
588 return isunordered (a, b) || a > b;
592 mono_fclt (double a, double b)
598 mono_fclt_un (double a, double b)
600 return isunordered (a, b) || a < b;
604 mono_isfinite (double a)
609 g_assert_not_reached ();
615 mono_fload_r4 (float *ptr)
621 mono_fstore_r4 (double val, float *ptr)
626 /* returns the integer bitpattern that is passed in the regs or stack */
628 mono_fload_r4_arg (double val)
630 float v = (float)val;
631 return *(guint32*)&v;
637 mono_array_new_va (MonoMethod *cm, ...)
639 MonoDomain *domain = mono_domain_get ();
642 intptr_t *lower_bounds;
647 pcount = mono_method_signature (cm)->param_count;
648 rank = cm->klass->rank;
652 lengths = alloca (sizeof (uintptr_t) * pcount);
653 for (i = 0; i < pcount; ++i)
654 lengths [i] = d = va_arg(ap, int);
656 if (rank == pcount) {
657 /* Only lengths provided. */
658 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
659 lower_bounds = alloca (sizeof (intptr_t) * rank);
660 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
665 g_assert (pcount == (rank * 2));
666 /* lower bounds are first. */
667 lower_bounds = (intptr_t*)lengths;
672 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
675 /* Specialized version of mono_array_new_va () which avoids varargs */
677 mono_array_new_1 (MonoMethod *cm, guint32 length)
679 MonoDomain *domain = mono_domain_get ();
680 uintptr_t lengths [1];
681 intptr_t *lower_bounds;
685 pcount = mono_method_signature (cm)->param_count;
686 rank = cm->klass->rank;
688 lengths [0] = length;
690 g_assert (rank == pcount);
692 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
693 lower_bounds = alloca (sizeof (intptr_t) * rank);
694 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
699 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
703 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
705 MonoDomain *domain = mono_domain_get ();
706 uintptr_t lengths [2];
707 intptr_t *lower_bounds;
711 pcount = mono_method_signature (cm)->param_count;
712 rank = cm->klass->rank;
714 lengths [0] = length1;
715 lengths [1] = length2;
717 g_assert (rank == pcount);
719 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
720 lower_bounds = alloca (sizeof (intptr_t) * rank);
721 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
726 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
730 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
732 MonoDomain *domain = mono_domain_get ();
733 uintptr_t lengths [3];
734 intptr_t *lower_bounds;
738 pcount = mono_method_signature (cm)->param_count;
739 rank = cm->klass->rank;
741 lengths [0] = length1;
742 lengths [1] = length2;
743 lengths [2] = length3;
745 g_assert (rank == pcount);
747 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
748 lower_bounds = alloca (sizeof (intptr_t) * rank);
749 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
754 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
758 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
760 MonoDomain *domain = mono_domain_get ();
761 uintptr_t lengths [4];
762 intptr_t *lower_bounds;
766 pcount = mono_method_signature (cm)->param_count;
767 rank = cm->klass->rank;
769 lengths [0] = length1;
770 lengths [1] = length2;
771 lengths [2] = length3;
772 lengths [3] = length4;
774 g_assert (rank == pcount);
776 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
777 lower_bounds = alloca (sizeof (intptr_t) * rank);
778 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
783 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
787 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
792 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
794 mono_class_init (field->parent);
796 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
797 if (!vtable->initialized)
798 mono_runtime_class_init (vtable);
800 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
802 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
803 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
805 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
811 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
814 MonoClass *handle_class;
817 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
818 mono_error_raise_exception (&error);
819 mono_class_init (handle_class);
825 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
827 MonoMethodSignature *sig = mono_method_signature (method);
828 MonoGenericContext *generic_context;
830 if (sig->is_inflated) {
831 generic_context = mono_method_get_context (method);
833 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
834 g_assert (generic_container);
835 generic_context = &generic_container->context;
838 return mono_ldtoken_wrapper (image, token, generic_context);
842 mono_fconv_u8 (double v)
847 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
849 mono_fconv_i8 (double v)
856 mono_fconv_u4 (double v)
858 /* MS.NET behaves like this for some reason */
860 if (isinf (v) || isnan (v))
868 /* Solaris doesn't have trunc */
870 extern long double aintl (long double);
873 /* FIXME: This means we will never throw overflow exceptions */
876 #endif /* HAVE_TRUNC */
879 mono_fconv_ovf_i8 (double v)
885 if (isnan(v) || trunc (v) != res) {
886 mono_set_pending_exception (mono_get_exception_overflow ());
893 mono_fconv_ovf_u8 (double v)
898 * The soft-float implementation of some ARM devices have a buggy guin64 to double
899 * conversion that it looses precision even when the integer if fully representable
902 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
904 * To work around this issue we test for value boundaries instead.
906 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
907 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
908 mono_set_pending_exception (mono_get_exception_overflow ());
914 if (isnan(v) || trunc (v) != res) {
915 mono_set_pending_exception (mono_get_exception_overflow ());
922 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
924 mono_rconv_i8 (float v)
931 mono_rconv_ovf_i8 (float v)
937 if (isnan(v) || trunc (v) != res) {
938 mono_set_pending_exception (mono_get_exception_overflow ());
945 mono_rconv_ovf_u8 (float v)
950 if (isnan(v) || trunc (v) != res) {
951 mono_set_pending_exception (mono_get_exception_overflow ());
957 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
959 mono_lconv_to_r8 (gint64 a)
965 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
967 mono_lconv_to_r4 (gint64 a)
973 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
975 mono_conv_to_r8_un (guint32 a)
981 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
983 mono_lconv_to_r8_un (guint64 a)
989 #if defined(__native_client_codegen__) || defined(__native_client__)
990 /* When we cross-compile to Native Client we can't directly embed calls */
991 /* to the math library on the host. This will use the fmod on the target*/
993 mono_fmod(double a, double b)
1000 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1002 MonoMethod *vmethod;
1004 MonoGenericContext *context = mono_method_get_context (method);
1006 mono_jit_stats.generic_virtual_invocations++;
1009 mono_set_pending_exception (mono_get_exception_null_reference ());
1012 vmethod = mono_object_get_virtual_method (obj, method);
1013 g_assert (!vmethod->klass->generic_container);
1014 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1015 g_assert (!context->method_inst || !context->method_inst->is_open);
1017 addr = mono_compile_method (vmethod);
1019 addr = mini_add_method_trampoline (NULL, vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1021 /* Since this is a virtual call, have to unbox vtypes */
1022 if (obj->vtable->klass->valuetype)
1023 *this_arg = mono_object_unbox (obj);
1031 mono_helper_ldstr (MonoImage *image, guint32 idx)
1033 return mono_ldstr (mono_domain_get (), image, idx);
1037 mono_helper_ldstr_mscorlib (guint32 idx)
1039 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1043 mono_helper_newobj_mscorlib (guint32 idx)
1046 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1047 mono_error_raise_exception (&error);
1049 return mono_object_new (mono_domain_get (), klass);
1053 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1054 * in generated code. So instead we emit a call to this function and place a gdb
1063 mono_create_corlib_exception_0 (guint32 token)
1065 return mono_exception_from_token (mono_defaults.corlib, token);
1069 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1071 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1075 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1077 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1081 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1083 MonoJitTlsData *jit_tls = NULL;
1086 if (mini_get_debug_options ()->better_cast_details) {
1087 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1088 jit_tls->class_cast_from = NULL;
1094 oklass = obj->vtable->klass;
1095 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1097 if (mono_object_isinst (obj, klass))
1100 if (mini_get_debug_options ()->better_cast_details) {
1101 jit_tls->class_cast_from = oklass;
1102 jit_tls->class_cast_to = klass;
1105 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1106 "System", "InvalidCastException"));
1112 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1114 MonoJitTlsData *jit_tls = NULL;
1115 gpointer cached_vtable, obj_vtable;
1117 if (mini_get_debug_options ()->better_cast_details) {
1118 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1119 jit_tls->class_cast_from = NULL;
1125 cached_vtable = *cache;
1126 obj_vtable = obj->vtable;
1128 if (cached_vtable == obj_vtable)
1131 if (mono_object_isinst (obj, klass)) {
1132 *cache = obj_vtable;
1136 if (mini_get_debug_options ()->better_cast_details) {
1137 jit_tls->class_cast_from = obj->vtable->klass;
1138 jit_tls->class_cast_to = klass;
1141 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1142 "System", "InvalidCastException"));
1148 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1150 size_t cached_vtable, obj_vtable;
1155 cached_vtable = (size_t)*cache;
1156 obj_vtable = (size_t)obj->vtable;
1158 if ((cached_vtable & ~0x1) == obj_vtable) {
1159 return (cached_vtable & 0x1) ? NULL : obj;
1162 if (mono_object_isinst (obj, klass)) {
1163 *cache = (gpointer)obj_vtable;
1167 *cache = (gpointer)(obj_vtable | 0x1);
1173 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1175 MonoMarshalSpec **mspecs;
1176 MonoMethodPInvoke piinfo;
1179 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1180 memset (&piinfo, 0, sizeof (piinfo));
1182 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1184 return mono_compile_method (m);
1188 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1193 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1194 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1198 if (mono_method_signature (cmethod)->pinvoke) {
1199 /* Object.GetType () */
1200 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1202 /* Lookup the virtual method */
1203 mono_class_setup_vtable (klass);
1204 g_assert (klass->vtable);
1205 vt_slot = mono_method_get_vtable_slot (cmethod);
1206 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1209 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1210 g_assert (iface_offset != -1);
1211 vt_slot += iface_offset;
1213 m = klass->vtable [vt_slot];
1214 if (cmethod->is_inflated)
1215 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1217 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1219 * Calling a non-vtype method with a vtype receiver, has to box.
1221 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1222 else if (klass->valuetype)
1224 * Calling a vtype method with a vtype receiver
1229 * Calling a non-vtype method
1231 *this_arg = *(gpointer*)mp;
1236 * mono_gsharedvt_constrained_call:
1238 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1239 * the arguments to the method in the format used by mono_runtime_invoke ().
1242 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1246 gpointer new_args [16];
1248 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1249 if (args && deref_arg) {
1250 new_args [0] = *(gpointer*)args [0];
1253 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1254 /* Object.GetType () */
1256 args [0] = this_arg;
1259 return mono_runtime_invoke (m, this_arg, args, NULL);
1263 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1265 if (klass->valuetype)
1266 mono_value_copy (dest, src, klass);
1268 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);