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"
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)
41 mono_raise_exception (mono_get_exception_null_reference ());
43 res = mono_object_get_virtual_method (obj, method);
45 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
46 MonoGenericContext context = { NULL, NULL };
48 if (res->klass->generic_class)
49 context.class_inst = res->klass->generic_class->context.class_inst;
50 else if (res->klass->generic_container)
51 context.class_inst = res->klass->generic_container->context.class_inst;
52 context.method_inst = mono_method_get_context (method)->method_inst;
54 res = mono_class_inflate_generic_method (res, &context);
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)
80 mono_raise_exception (mono_get_exception_null_reference ());
81 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
82 mono_raise_exception (mono_get_exception_array_type_mismatch ());
85 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
88 mono_llmult (gint64 a, gint64 b)
90 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
95 mono_llmult_ovf_un (guint64 a, guint64 b)
100 guint32 bh = b >> 32;
105 // fixme: this is incredible slow
108 goto raise_exception;
110 res = (guint64)al * (guint64)bl;
112 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
115 goto raise_exception;
117 res += ((guint64)t1) << 32;
122 mono_raise_exception (mono_get_exception_overflow ());
127 mono_llmult_ovf (gint64 a, gint64 b)
134 Use Karatsuba algorithm where:
135 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
136 where Ah is the "high half" (most significant 32 bits) of a and
137 where Al is the "low half" (least significant 32 bits) of a and
138 where Bh is the "high half" of b and Bl is the "low half" and
139 where R is the Radix or "size of the half" (in our case 32 bits)
141 Note, for the product of two 64 bit numbers to fit into a 64
142 result, ah and/or bh must be 0. This will save us from doing
143 the AhBh term at all.
145 Also note that we refactor so that we don't overflow 64 bits with
146 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_raise_exception (mono_get_exception_overflow ());
238 mono_lldiv (gint64 a, gint64 b)
242 #ifdef MONO_ARCH_NEED_DIV_CHECK
244 mono_raise_exception (mono_get_exception_divide_by_zero ());
245 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
246 mono_raise_exception (mono_get_exception_arithmetic ());
252 mono_llrem (gint64 a, gint64 b)
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
258 mono_raise_exception (mono_get_exception_divide_by_zero ());
259 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
260 mono_raise_exception (mono_get_exception_arithmetic ());
266 mono_lldiv_un (guint64 a, guint64 b)
270 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 mono_raise_exception (mono_get_exception_divide_by_zero ());
278 mono_llrem_un (guint64 a, guint64 b)
282 #ifdef MONO_ARCH_NEED_DIV_CHECK
284 mono_raise_exception (mono_get_exception_divide_by_zero ());
291 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
294 mono_lshl (guint64 a, gint32 shamt)
298 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
301 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
307 mono_lshr_un (guint64 a, gint32 shamt)
311 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
314 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
320 mono_lshr (gint64 a, gint32 shamt)
324 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
327 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
334 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
337 mono_idiv (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 ());
351 mono_idiv_un (guint32 a, guint32 b)
355 #ifdef MONO_ARCH_NEED_DIV_CHECK
357 mono_raise_exception (mono_get_exception_divide_by_zero ());
363 mono_irem (gint32 a, gint32 b)
367 #ifdef MONO_ARCH_NEED_DIV_CHECK
369 mono_raise_exception (mono_get_exception_divide_by_zero ());
370 else if (b == -1 && a == (0x80000000))
371 mono_raise_exception (mono_get_exception_overflow ());
378 mono_irem_un (guint32 a, guint32 b)
382 #ifdef MONO_ARCH_NEED_DIV_CHECK
384 mono_raise_exception (mono_get_exception_divide_by_zero ());
391 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
394 mono_imul (gint32 a, gint32 b)
402 mono_imul_ovf (gint32 a, gint32 b)
408 res = (gint64)a * (gint64)b;
410 if ((res > 0x7fffffffL) || (res < -2147483648LL))
411 mono_raise_exception (mono_get_exception_overflow ());
417 mono_imul_ovf_un (guint32 a, guint32 b)
423 res = (guint64)a * (guint64)b;
426 mono_raise_exception (mono_get_exception_overflow ());
432 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
434 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;
652 pcount = mono_method_signature (cm)->param_count;
653 rank = cm->klass->rank;
657 lengths = alloca (sizeof (uintptr_t) * pcount);
658 for (i = 0; i < pcount; ++i)
659 lengths [i] = d = va_arg(ap, int);
661 if (rank == pcount) {
662 /* Only lengths provided. */
663 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
664 lower_bounds = alloca (sizeof (intptr_t) * rank);
665 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
670 g_assert (pcount == (rank * 2));
671 /* lower bounds are first. */
672 lower_bounds = (intptr_t*)lengths;
677 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
680 /* Specialized version of mono_array_new_va () which avoids varargs */
682 mono_array_new_1 (MonoMethod *cm, guint32 length)
684 MonoDomain *domain = mono_domain_get ();
685 uintptr_t lengths [1];
686 intptr_t *lower_bounds;
692 pcount = mono_method_signature (cm)->param_count;
693 rank = cm->klass->rank;
695 lengths [0] = length;
697 g_assert (rank == pcount);
699 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
700 lower_bounds = alloca (sizeof (intptr_t) * rank);
701 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
706 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
710 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
712 MonoDomain *domain = mono_domain_get ();
713 uintptr_t lengths [2];
714 intptr_t *lower_bounds;
720 pcount = mono_method_signature (cm)->param_count;
721 rank = cm->klass->rank;
723 lengths [0] = length1;
724 lengths [1] = length2;
726 g_assert (rank == pcount);
728 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
729 lower_bounds = alloca (sizeof (intptr_t) * rank);
730 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
735 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
739 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
741 MonoDomain *domain = mono_domain_get ();
742 uintptr_t lengths [3];
743 intptr_t *lower_bounds;
749 pcount = mono_method_signature (cm)->param_count;
750 rank = cm->klass->rank;
752 lengths [0] = length1;
753 lengths [1] = length2;
754 lengths [2] = length3;
756 g_assert (rank == pcount);
758 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
759 lower_bounds = alloca (sizeof (intptr_t) * rank);
760 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
765 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
769 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
771 MonoDomain *domain = mono_domain_get ();
772 uintptr_t lengths [4];
773 intptr_t *lower_bounds;
779 pcount = mono_method_signature (cm)->param_count;
780 rank = cm->klass->rank;
782 lengths [0] = length1;
783 lengths [1] = length2;
784 lengths [2] = length3;
785 lengths [3] = length4;
787 g_assert (rank == pcount);
789 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
790 lower_bounds = alloca (sizeof (intptr_t) * rank);
791 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
796 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
800 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
807 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
809 mono_class_init (field->parent);
811 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
812 if (!vtable->initialized)
813 mono_runtime_class_init (vtable);
815 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
817 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
818 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
820 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
826 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
828 MonoClass *handle_class;
832 res = mono_ldtoken (image, token, &handle_class, context);
833 mono_class_init (handle_class);
839 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
841 MonoMethodSignature *sig = mono_method_signature (method);
842 MonoGenericContext *generic_context;
844 if (sig->is_inflated) {
845 generic_context = mono_method_get_context (method);
847 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
848 g_assert (generic_container);
849 generic_context = &generic_container->context;
852 return mono_ldtoken_wrapper (image, token, generic_context);
856 mono_fconv_u8 (double v)
861 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
863 mono_fconv_i8 (double v)
865 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
871 mono_fconv_u4 (double v)
873 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
878 /* Solaris doesn't have trunc */
880 extern long double aintl (long double);
883 /* FIXME: This means we will never throw overflow exceptions */
886 #endif /* HAVE_TRUNC */
889 mono_fconv_ovf_i8 (double v)
897 if (isnan(v) || trunc (v) != res) {
898 mono_raise_exception (mono_get_exception_overflow ());
904 mono_fconv_ovf_u8 (double v)
910 * The soft-float implementation of some ARM devices have a buggy guin64 to double
911 * conversion that it looses precision even when the integer if fully representable
914 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
916 * To work around this issue we test for value boundaries instead.
918 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
919 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
920 mono_raise_exception (mono_get_exception_overflow ());
925 if (isnan(v) || trunc (v) != res) {
926 mono_raise_exception (mono_get_exception_overflow ());
932 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
934 mono_lconv_to_r8 (gint64 a)
940 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
942 mono_lconv_to_r4 (gint64 a)
948 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
950 mono_conv_to_r8_un (guint32 a)
956 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
958 mono_lconv_to_r8_un (guint64 a)
964 #if defined(__native_client_codegen__) || defined(__native_client__)
965 /* When we cross-compile to Native Client we can't directly embed calls */
966 /* to the math library on the host. This will use the fmod on the target*/
968 mono_fmod(double a, double b)
975 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
979 MonoGenericContext *context = mono_method_get_context (method);
981 mono_jit_stats.generic_virtual_invocations++;
984 mono_raise_exception (mono_get_exception_null_reference ());
985 vmethod = mono_object_get_virtual_method (obj, method);
986 g_assert (!vmethod->klass->generic_container);
987 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
988 g_assert (!context->method_inst || !context->method_inst->is_open);
990 addr = mono_compile_method (vmethod);
992 if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
993 addr = mono_create_static_rgctx_trampoline (vmethod, addr);
995 /* Since this is a virtual call, have to unbox vtypes */
996 if (obj->vtable->klass->valuetype)
997 *this_arg = mono_object_unbox (obj);
1005 mono_helper_ldstr (MonoImage *image, guint32 idx)
1007 return mono_ldstr (mono_domain_get (), image, idx);
1011 mono_helper_ldstr_mscorlib (guint32 idx)
1013 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1017 mono_helper_newobj_mscorlib (guint32 idx)
1019 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
1023 return mono_object_new (mono_domain_get (), klass);
1027 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1028 * in generated code. So instead we emit a call to this function and place a gdb
1037 mono_create_corlib_exception_0 (guint32 token)
1039 return mono_exception_from_token (mono_defaults.corlib, token);
1043 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1045 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1049 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1051 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1055 mono_object_castclass (MonoObject *obj, MonoClass *klass)
1057 MonoJitTlsData *jit_tls = NULL;
1059 if (mini_get_debug_options ()->better_cast_details) {
1060 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1061 jit_tls->class_cast_from = NULL;
1067 if (mono_object_isinst (obj, klass))
1070 if (mini_get_debug_options ()->better_cast_details) {
1071 jit_tls->class_cast_from = obj->vtable->klass;
1072 jit_tls->class_cast_to = klass;
1075 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1076 "System", "InvalidCastException"));
1082 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1084 MonoJitTlsData *jit_tls = NULL;
1085 gpointer cached_vtable, obj_vtable;
1087 if (mini_get_debug_options ()->better_cast_details) {
1088 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1089 jit_tls->class_cast_from = NULL;
1095 cached_vtable = *cache;
1096 obj_vtable = obj->vtable;
1098 if (cached_vtable == obj_vtable)
1101 if (mono_object_isinst (obj, klass)) {
1102 *cache = obj_vtable;
1106 if (mini_get_debug_options ()->better_cast_details) {
1107 jit_tls->class_cast_from = obj->vtable->klass;
1108 jit_tls->class_cast_to = klass;
1111 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1112 "System", "InvalidCastException"));
1118 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1120 size_t cached_vtable, obj_vtable;
1125 cached_vtable = (size_t)*cache;
1126 obj_vtable = (size_t)obj->vtable;
1128 if ((cached_vtable & ~0x1) == obj_vtable) {
1129 return (cached_vtable & 0x1) ? NULL : obj;
1132 if (mono_object_isinst (obj, klass)) {
1133 *cache = (gpointer)obj_vtable;
1137 *cache = (gpointer)(obj_vtable | 0x1);
1143 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1145 MonoMarshalSpec **mspecs;
1146 MonoMethodPInvoke piinfo;
1149 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1150 memset (&piinfo, 0, sizeof (piinfo));
1152 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1154 return mono_compile_method (m);
1158 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1163 /* Lookup the virtual method */
1164 mono_class_setup_vtable (klass);
1165 g_assert (klass->vtable);
1166 vt_slot = mono_method_get_vtable_slot (cmethod);
1167 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1170 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1171 g_assert (iface_offset);
1172 vt_slot += iface_offset;
1174 m = klass->vtable [vt_slot];
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_object_tostring_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass)
1199 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1200 return mono_runtime_invoke (m, this_arg, NULL, NULL);
1204 mono_object_gethashcode_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass)
1211 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1212 // FIXME: This boxes the result
1213 res = mono_runtime_invoke (m, this_arg, NULL, NULL);
1214 p = mono_object_unbox (res);
1219 mono_object_equals_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass, MonoObject *arg)
1227 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1228 // FIXME: This boxes the result
1229 args = (void**)&arg;
1230 res = mono_runtime_invoke (m, this_arg, args, NULL);
1231 p = mono_object_unbox (res);
1232 return *(MonoBoolean*)p;
1236 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass)
1241 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1242 mono_runtime_invoke (m, this_arg, NULL, NULL);
1246 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1248 if (klass->valuetype)
1249 mono_value_copy (dest, src, klass);
1251 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);