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_raise_exception (mono_get_exception_null_reference ());
40 res = mono_object_get_virtual_method (obj, method);
42 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
43 MonoGenericContext context = { NULL, NULL };
45 if (res->klass->generic_class)
46 context.class_inst = res->klass->generic_class->context.class_inst;
47 else if (res->klass->generic_container)
48 context.class_inst = res->klass->generic_container->context.class_inst;
49 context.method_inst = mono_method_get_context (method)->method_inst;
51 res = mono_class_inflate_generic_method_checked (res, &context, &error);
52 mono_error_raise_exception (&error);
55 /* An rgctx wrapper is added by the trampolines no need to do it here */
57 return mono_ldftn (res);
61 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
63 return ldvirtfn_internal (obj, method, FALSE);
67 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
69 return ldvirtfn_internal (obj, method, TRUE);
73 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
76 mono_raise_exception (mono_get_exception_null_reference ());
77 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
78 mono_raise_exception (mono_get_exception_array_type_mismatch ());
81 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
84 mono_llmult (gint64 a, gint64 b)
90 mono_llmult_ovf_un (guint64 a, guint64 b)
98 // fixme: this is incredible slow
101 goto raise_exception;
103 res = (guint64)al * (guint64)bl;
105 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
108 goto raise_exception;
110 res += ((guint64)t1) << 32;
115 mono_raise_exception (mono_get_exception_overflow ());
120 mono_llmult_ovf (gint64 a, gint64 b)
127 Use Karatsuba algorithm where:
128 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
129 where Ah is the "high half" (most significant 32 bits) of a and
130 where Al is the "low half" (least significant 32 bits) of a and
131 where Bh is the "high half" of b and Bl is the "low half" and
132 where R is the Radix or "size of the half" (in our case 32 bits)
134 Note, for the product of two 64 bit numbers to fit into a 64
135 result, ah and/or bh must be 0. This will save us from doing
136 the AhBh term at all.
138 Also note that we refactor so that we don't overflow 64 bits with
139 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
145 /* need to work with absoulte values, so find out what the
146 resulting sign will be and convert any negative numbers
147 from two's complement
151 if (((guint32)ah == 0x80000000) && (al == 0)) {
152 /* This has no two's complement */
158 goto raise_exception;
161 /* flip the bits and add 1 */
172 if (((guint32)bh == 0x80000000) && (bl == 0)) {
173 /* This has no two's complement */
179 goto raise_exception;
182 /* flip the bits and add 1 */
192 /* we overflow for sure if both upper halves are greater
193 than zero because we would need to shift their
194 product 64 bits to the left and that will not fit
195 in a 64 bit result */
197 goto raise_exception;
198 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
199 goto raise_exception;
201 /* do the AlBl term first */
202 t1 = (gint64)al * (gint64)bl;
206 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
207 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
208 /* check for overflow */
210 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
211 goto raise_exception;
216 goto raise_exception;
224 mono_raise_exception (mono_get_exception_overflow ());
229 mono_lldiv (gint64 a, gint64 b)
231 #ifdef MONO_ARCH_NEED_DIV_CHECK
233 mono_raise_exception (mono_get_exception_divide_by_zero ());
234 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
235 mono_raise_exception (mono_get_exception_arithmetic ());
241 mono_llrem (gint64 a, gint64 b)
243 #ifdef MONO_ARCH_NEED_DIV_CHECK
245 mono_raise_exception (mono_get_exception_divide_by_zero ());
246 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
247 mono_raise_exception (mono_get_exception_arithmetic ());
253 mono_lldiv_un (guint64 a, guint64 b)
255 #ifdef MONO_ARCH_NEED_DIV_CHECK
257 mono_raise_exception (mono_get_exception_divide_by_zero ());
263 mono_llrem_un (guint64 a, guint64 b)
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
267 mono_raise_exception (mono_get_exception_divide_by_zero ());
274 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
277 mono_lshl (guint64 a, gint32 shamt)
283 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
289 mono_lshr_un (guint64 a, gint32 shamt)
295 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
301 mono_lshr (gint64 a, gint32 shamt)
307 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
314 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
317 mono_idiv (gint32 a, gint32 b)
319 #ifdef MONO_ARCH_NEED_DIV_CHECK
321 mono_raise_exception (mono_get_exception_divide_by_zero ());
322 else if (b == -1 && a == (0x80000000))
323 mono_raise_exception (mono_get_exception_overflow ());
329 mono_idiv_un (guint32 a, guint32 b)
331 #ifdef MONO_ARCH_NEED_DIV_CHECK
333 mono_raise_exception (mono_get_exception_divide_by_zero ());
339 mono_irem (gint32 a, gint32 b)
341 #ifdef MONO_ARCH_NEED_DIV_CHECK
343 mono_raise_exception (mono_get_exception_divide_by_zero ());
344 else if (b == -1 && a == (0x80000000))
345 mono_raise_exception (mono_get_exception_overflow ());
352 mono_irem_un (guint32 a, guint32 b)
354 #ifdef MONO_ARCH_NEED_DIV_CHECK
356 mono_raise_exception (mono_get_exception_divide_by_zero ());
363 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
366 mono_imul (gint32 a, gint32 b)
372 mono_imul_ovf (gint32 a, gint32 b)
376 res = (gint64)a * (gint64)b;
378 if ((res > 0x7fffffffL) || (res < -2147483648LL))
379 mono_raise_exception (mono_get_exception_overflow ());
385 mono_imul_ovf_un (guint32 a, guint32 b)
389 res = (guint64)a * (guint64)b;
392 mono_raise_exception (mono_get_exception_overflow ());
398 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
400 mono_fdiv (double a, double b)
406 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
409 mono_fsub (double a, double b)
415 mono_fadd (double a, double b)
421 mono_fmul (double a, double b)
433 mono_fconv_r4 (double a)
439 mono_conv_to_r8 (int a)
445 mono_conv_to_r4 (int a)
447 return (double)(float)a;
451 mono_fconv_i1 (double a)
457 mono_fconv_i2 (double a)
463 mono_fconv_i4 (double a)
469 mono_fconv_u1 (double a)
475 mono_fconv_u2 (double a)
481 mono_fcmp_eq (double a, double b)
487 mono_fcmp_ge (double a, double b)
493 mono_fcmp_gt (double a, double b)
499 mono_fcmp_le (double a, double b)
505 mono_fcmp_lt (double a, double b)
511 mono_fcmp_ne_un (double a, double b)
513 return isunordered (a, b) || a != b;
517 mono_fcmp_ge_un (double a, double b)
519 return isunordered (a, b) || a >= b;
523 mono_fcmp_gt_un (double a, double b)
525 return isunordered (a, b) || a > b;
529 mono_fcmp_le_un (double a, double b)
531 return isunordered (a, b) || a <= b;
535 mono_fcmp_lt_un (double a, double b)
537 return isunordered (a, b) || a < b;
541 mono_fceq (double a, double b)
547 mono_fcgt (double a, double b)
553 mono_fcgt_un (double a, double b)
555 return isunordered (a, b) || a > b;
559 mono_fclt (double a, double b)
565 mono_fclt_un (double a, double b)
567 return isunordered (a, b) || a < b;
571 mono_isfinite (double a)
576 g_assert_not_reached ();
582 mono_fload_r4 (float *ptr)
588 mono_fstore_r4 (double val, float *ptr)
593 /* returns the integer bitpattern that is passed in the regs or stack */
595 mono_fload_r4_arg (double val)
597 float v = (float)val;
598 return *(guint32*)&v;
604 mono_array_new_va (MonoMethod *cm, ...)
606 MonoDomain *domain = mono_domain_get ();
609 intptr_t *lower_bounds;
614 pcount = mono_method_signature (cm)->param_count;
615 rank = cm->klass->rank;
619 lengths = alloca (sizeof (uintptr_t) * pcount);
620 for (i = 0; i < pcount; ++i)
621 lengths [i] = d = va_arg(ap, int);
623 if (rank == pcount) {
624 /* Only lengths provided. */
625 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
626 lower_bounds = alloca (sizeof (intptr_t) * rank);
627 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
632 g_assert (pcount == (rank * 2));
633 /* lower bounds are first. */
634 lower_bounds = (intptr_t*)lengths;
639 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
642 /* Specialized version of mono_array_new_va () which avoids varargs */
644 mono_array_new_1 (MonoMethod *cm, guint32 length)
646 MonoDomain *domain = mono_domain_get ();
647 uintptr_t lengths [1];
648 intptr_t *lower_bounds;
652 pcount = mono_method_signature (cm)->param_count;
653 rank = cm->klass->rank;
655 lengths [0] = length;
657 g_assert (rank == pcount);
659 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
660 lower_bounds = alloca (sizeof (intptr_t) * rank);
661 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
666 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
670 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
672 MonoDomain *domain = mono_domain_get ();
673 uintptr_t lengths [2];
674 intptr_t *lower_bounds;
678 pcount = mono_method_signature (cm)->param_count;
679 rank = cm->klass->rank;
681 lengths [0] = length1;
682 lengths [1] = length2;
684 g_assert (rank == pcount);
686 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
687 lower_bounds = alloca (sizeof (intptr_t) * rank);
688 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
693 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
697 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
699 MonoDomain *domain = mono_domain_get ();
700 uintptr_t lengths [3];
701 intptr_t *lower_bounds;
705 pcount = mono_method_signature (cm)->param_count;
706 rank = cm->klass->rank;
708 lengths [0] = length1;
709 lengths [1] = length2;
710 lengths [2] = length3;
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_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
727 MonoDomain *domain = mono_domain_get ();
728 uintptr_t lengths [4];
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;
738 lengths [2] = length3;
739 lengths [3] = length4;
741 g_assert (rank == pcount);
743 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
744 lower_bounds = alloca (sizeof (intptr_t) * rank);
745 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
750 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
754 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
759 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
761 mono_class_init (field->parent);
763 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
764 if (!vtable->initialized)
765 mono_runtime_class_init (vtable);
767 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
769 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
770 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
772 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
778 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
781 MonoClass *handle_class;
784 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
785 mono_error_raise_exception (&error);
786 mono_class_init (handle_class);
792 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
794 MonoMethodSignature *sig = mono_method_signature (method);
795 MonoGenericContext *generic_context;
797 if (sig->is_inflated) {
798 generic_context = mono_method_get_context (method);
800 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
801 g_assert (generic_container);
802 generic_context = &generic_container->context;
805 return mono_ldtoken_wrapper (image, token, generic_context);
809 mono_fconv_u8 (double v)
814 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
816 mono_fconv_i8 (double v)
823 mono_fconv_u4 (double v)
825 /* MS.NET behaves like this for some reason */
827 if (isinf (v) || isnan (v))
835 /* Solaris doesn't have trunc */
837 extern long double aintl (long double);
840 /* FIXME: This means we will never throw overflow exceptions */
843 #endif /* HAVE_TRUNC */
846 mono_fconv_ovf_i8 (double v)
852 if (isnan(v) || trunc (v) != res) {
853 mono_raise_exception (mono_get_exception_overflow ());
859 mono_fconv_ovf_u8 (double v)
864 * The soft-float implementation of some ARM devices have a buggy guin64 to double
865 * conversion that it looses precision even when the integer if fully representable
868 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
870 * To work around this issue we test for value boundaries instead.
872 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
873 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
874 mono_raise_exception (mono_get_exception_overflow ());
879 if (isnan(v) || trunc (v) != res) {
880 mono_raise_exception (mono_get_exception_overflow ());
886 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
888 mono_rconv_i8 (float v)
895 mono_rconv_ovf_i8 (float v)
901 if (isnan(v) || trunc (v) != res) {
902 mono_raise_exception (mono_get_exception_overflow ());
908 mono_rconv_ovf_u8 (float v)
913 if (isnan(v) || trunc (v) != res) {
914 mono_raise_exception (mono_get_exception_overflow ());
919 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
921 mono_lconv_to_r8 (gint64 a)
927 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
929 mono_lconv_to_r4 (gint64 a)
935 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
937 mono_conv_to_r8_un (guint32 a)
943 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
945 mono_lconv_to_r8_un (guint64 a)
951 #if defined(__native_client_codegen__) || defined(__native_client__)
952 /* When we cross-compile to Native Client we can't directly embed calls */
953 /* to the math library on the host. This will use the fmod on the target*/
955 mono_fmod(double a, double b)
962 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
966 MonoGenericContext *context = mono_method_get_context (method);
968 mono_jit_stats.generic_virtual_invocations++;
971 mono_raise_exception (mono_get_exception_null_reference ());
972 vmethod = mono_object_get_virtual_method (obj, method);
973 g_assert (!vmethod->klass->generic_container);
974 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
975 g_assert (!context->method_inst || !context->method_inst->is_open);
977 addr = mono_compile_method (vmethod);
979 addr = mini_add_method_trampoline (NULL, vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
981 /* Since this is a virtual call, have to unbox vtypes */
982 if (obj->vtable->klass->valuetype)
983 *this_arg = mono_object_unbox (obj);
991 mono_helper_ldstr (MonoImage *image, guint32 idx)
993 return mono_ldstr (mono_domain_get (), image, idx);
997 mono_helper_ldstr_mscorlib (guint32 idx)
999 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1003 mono_helper_newobj_mscorlib (guint32 idx)
1006 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1007 mono_error_raise_exception (&error);
1009 return mono_object_new (mono_domain_get (), klass);
1013 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1014 * in generated code. So instead we emit a call to this function and place a gdb
1023 mono_create_corlib_exception_0 (guint32 token)
1025 return mono_exception_from_token (mono_defaults.corlib, token);
1029 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1031 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1035 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1037 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1041 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1043 MonoJitTlsData *jit_tls = NULL;
1046 if (mini_get_debug_options ()->better_cast_details) {
1047 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1048 jit_tls->class_cast_from = NULL;
1054 oklass = obj->vtable->klass;
1055 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1057 if (mono_object_isinst (obj, klass))
1060 if (mini_get_debug_options ()->better_cast_details) {
1061 jit_tls->class_cast_from = oklass;
1062 jit_tls->class_cast_to = klass;
1065 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1066 "System", "InvalidCastException"));
1072 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1074 MonoJitTlsData *jit_tls = NULL;
1075 gpointer cached_vtable, obj_vtable;
1077 if (mini_get_debug_options ()->better_cast_details) {
1078 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1079 jit_tls->class_cast_from = NULL;
1085 cached_vtable = *cache;
1086 obj_vtable = obj->vtable;
1088 if (cached_vtable == obj_vtable)
1091 if (mono_object_isinst (obj, klass)) {
1092 *cache = obj_vtable;
1096 if (mini_get_debug_options ()->better_cast_details) {
1097 jit_tls->class_cast_from = obj->vtable->klass;
1098 jit_tls->class_cast_to = klass;
1101 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1102 "System", "InvalidCastException"));
1108 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1110 size_t cached_vtable, obj_vtable;
1115 cached_vtable = (size_t)*cache;
1116 obj_vtable = (size_t)obj->vtable;
1118 if ((cached_vtable & ~0x1) == obj_vtable) {
1119 return (cached_vtable & 0x1) ? NULL : obj;
1122 if (mono_object_isinst (obj, klass)) {
1123 *cache = (gpointer)obj_vtable;
1127 *cache = (gpointer)(obj_vtable | 0x1);
1133 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1135 MonoMarshalSpec **mspecs;
1136 MonoMethodPInvoke piinfo;
1139 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1140 memset (&piinfo, 0, sizeof (piinfo));
1142 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1144 return mono_compile_method (m);
1148 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1153 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
1154 mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
1156 if (mono_method_signature (cmethod)->pinvoke) {
1157 /* Object.GetType () */
1158 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1160 /* Lookup the virtual method */
1161 mono_class_setup_vtable (klass);
1162 g_assert (klass->vtable);
1163 vt_slot = mono_method_get_vtable_slot (cmethod);
1164 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1167 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1168 g_assert (iface_offset != -1);
1169 vt_slot += iface_offset;
1171 m = klass->vtable [vt_slot];
1172 if (cmethod->is_inflated)
1173 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1175 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1177 * Calling a non-vtype method with a vtype receiver, has to box.
1179 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1180 else if (klass->valuetype)
1182 * Calling a vtype method with a vtype receiver
1187 * Calling a non-vtype method
1189 *this_arg = *(gpointer*)mp;
1194 * mono_gsharedvt_constrained_call:
1196 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1197 * the arguments to the method in the format used by mono_runtime_invoke ().
1200 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1204 gpointer new_args [16];
1206 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1207 if (args && deref_arg) {
1208 new_args [0] = *(gpointer*)args [0];
1211 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1212 /* Object.GetType () */
1214 args [0] = this_arg;
1217 return mono_runtime_invoke (m, this_arg, args, NULL);
1221 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1223 if (klass->valuetype)
1224 mono_value_copy (dest, src, klass);
1226 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);