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>
23 #include "mini-llvm-cpp.h"
27 mono_ldftn (MonoMethod *method)
32 // FIXME: No error handling
34 addr = mono_compile_method (method);
37 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
38 /* The caller doesn't pass it */
39 g_assert_not_reached ();
41 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
45 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
47 return mono_create_ftnptr (mono_domain_get (), addr);
51 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
57 mono_set_pending_exception (mono_get_exception_null_reference ());
61 res = mono_object_get_virtual_method (obj, method);
63 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
64 MonoGenericContext context = { NULL, NULL };
66 if (res->klass->generic_class)
67 context.class_inst = res->klass->generic_class->context.class_inst;
68 else if (res->klass->generic_container)
69 context.class_inst = res->klass->generic_container->context.class_inst;
70 context.method_inst = mono_method_get_context (method)->method_inst;
72 res = mono_class_inflate_generic_method_checked (res, &context, &error);
73 if (!mono_error_ok (&error)) {
74 mono_error_set_pending_exception (&error);
79 /* An rgctx wrapper is added by the trampolines no need to do it here */
81 return mono_ldftn (res);
85 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
87 return ldvirtfn_internal (obj, method, FALSE);
91 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
93 return ldvirtfn_internal (obj, method, TRUE);
97 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
100 mono_set_pending_exception (mono_get_exception_null_reference ());
103 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
104 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
109 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
112 mono_llmult (gint64 a, gint64 b)
118 mono_llmult_ovf_un (guint64 a, guint64 b)
121 guint32 ah = a >> 32;
123 guint32 bh = b >> 32;
126 // fixme: this is incredible slow
129 goto raise_exception;
131 res = (guint64)al * (guint64)bl;
133 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
136 goto raise_exception;
138 res += ((guint64)t1) << 32;
143 mono_set_pending_exception (mono_get_exception_overflow ());
148 mono_llmult_ovf (gint64 a, gint64 b)
155 Use Karatsuba algorithm where:
156 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
157 where Ah is the "high half" (most significant 32 bits) of a and
158 where Al is the "low half" (least significant 32 bits) of a and
159 where Bh is the "high half" of b and Bl is the "low half" and
160 where R is the Radix or "size of the half" (in our case 32 bits)
162 Note, for the product of two 64 bit numbers to fit into a 64
163 result, ah and/or bh must be 0. This will save us from doing
164 the AhBh term at all.
166 Also note that we refactor so that we don't overflow 64 bits with
167 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
173 /* need to work with absoulte values, so find out what the
174 resulting sign will be and convert any negative numbers
175 from two's complement
179 if (((guint32)ah == 0x80000000) && (al == 0)) {
180 /* This has no two's complement */
186 goto raise_exception;
189 /* flip the bits and add 1 */
200 if (((guint32)bh == 0x80000000) && (bl == 0)) {
201 /* This has no two's complement */
207 goto raise_exception;
210 /* flip the bits and add 1 */
220 /* we overflow for sure if both upper halves are greater
221 than zero because we would need to shift their
222 product 64 bits to the left and that will not fit
223 in a 64 bit result */
225 goto raise_exception;
226 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
227 goto raise_exception;
229 /* do the AlBl term first */
230 t1 = (gint64)al * (gint64)bl;
234 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
235 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
236 /* check for overflow */
238 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
239 goto raise_exception;
244 goto raise_exception;
252 mono_set_pending_exception (mono_get_exception_overflow ());
257 mono_lldiv (gint64 a, gint64 b)
259 #ifdef MONO_ARCH_NEED_DIV_CHECK
261 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
264 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
265 mono_set_pending_exception (mono_get_exception_arithmetic ());
273 mono_llrem (gint64 a, gint64 b)
275 #ifdef MONO_ARCH_NEED_DIV_CHECK
277 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
280 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
281 mono_set_pending_exception (mono_get_exception_arithmetic ());
289 mono_lldiv_un (guint64 a, guint64 b)
291 #ifdef MONO_ARCH_NEED_DIV_CHECK
293 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
301 mono_llrem_un (guint64 a, guint64 b)
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
305 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
314 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
317 mono_lshl (guint64 a, gint32 shamt)
321 res = a << (shamt & 0x7f);
323 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
329 mono_lshr_un (guint64 a, gint32 shamt)
333 res = a >> (shamt & 0x7f);
335 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
341 mono_lshr (gint64 a, gint32 shamt)
345 res = a >> (shamt & 0x7f);
347 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
354 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
357 mono_idiv (gint32 a, gint32 b)
359 #ifdef MONO_ARCH_NEED_DIV_CHECK
361 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
364 else if (b == -1 && a == (0x80000000)) {
365 mono_set_pending_exception (mono_get_exception_overflow ());
373 mono_idiv_un (guint32 a, guint32 b)
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
377 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
385 mono_irem (gint32 a, gint32 b)
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
389 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
392 else if (b == -1 && a == (0x80000000)) {
393 mono_set_pending_exception (mono_get_exception_overflow ());
401 mono_irem_un (guint32 a, guint32 b)
403 #ifdef MONO_ARCH_NEED_DIV_CHECK
405 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
414 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
417 mono_imul (gint32 a, gint32 b)
423 mono_imul_ovf (gint32 a, gint32 b)
427 res = (gint64)a * (gint64)b;
429 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
430 mono_set_pending_exception (mono_get_exception_overflow ());
438 mono_imul_ovf_un (guint32 a, guint32 b)
442 res = (guint64)a * (guint64)b;
445 mono_set_pending_exception (mono_get_exception_overflow ());
453 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
455 mono_fdiv (double a, double b)
461 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
464 mono_fsub (double a, double b)
470 mono_fadd (double a, double b)
476 mono_fmul (double a, double b)
488 mono_fconv_r4 (double a)
494 mono_conv_to_r8 (int a)
500 mono_conv_to_r4 (int a)
502 return (double)(float)a;
506 mono_fconv_i1 (double a)
512 mono_fconv_i2 (double a)
518 mono_fconv_i4 (double a)
524 mono_fconv_u1 (double a)
530 mono_fconv_u2 (double a)
536 mono_fcmp_eq (double a, double b)
542 mono_fcmp_ge (double a, double b)
548 mono_fcmp_gt (double a, double b)
554 mono_fcmp_le (double a, double b)
560 mono_fcmp_lt (double a, double b)
566 mono_fcmp_ne_un (double a, double b)
568 return isunordered (a, b) || a != b;
572 mono_fcmp_ge_un (double a, double b)
574 return isunordered (a, b) || a >= b;
578 mono_fcmp_gt_un (double a, double b)
580 return isunordered (a, b) || a > b;
584 mono_fcmp_le_un (double a, double b)
586 return isunordered (a, b) || a <= b;
590 mono_fcmp_lt_un (double a, double b)
592 return isunordered (a, b) || a < b;
596 mono_fceq (double a, double b)
602 mono_fcgt (double a, double b)
608 mono_fcgt_un (double a, double b)
610 return isunordered (a, b) || a > b;
614 mono_fclt (double a, double b)
620 mono_fclt_un (double a, double b)
622 return isunordered (a, b) || a < b;
626 mono_isfinite (double a)
631 g_assert_not_reached ();
637 mono_fload_r4 (float *ptr)
643 mono_fstore_r4 (double val, float *ptr)
648 /* returns the integer bitpattern that is passed in the regs or stack */
650 mono_fload_r4_arg (double val)
652 float v = (float)val;
653 return *(guint32*)&v;
659 mono_array_new_va (MonoMethod *cm, ...)
661 MonoDomain *domain = mono_domain_get ();
664 intptr_t *lower_bounds;
669 pcount = mono_method_signature (cm)->param_count;
670 rank = cm->klass->rank;
674 lengths = alloca (sizeof (uintptr_t) * pcount);
675 for (i = 0; i < pcount; ++i)
676 lengths [i] = d = va_arg(ap, int);
678 if (rank == pcount) {
679 /* Only lengths provided. */
680 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
681 lower_bounds = alloca (sizeof (intptr_t) * rank);
682 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
687 g_assert (pcount == (rank * 2));
688 /* lower bounds are first. */
689 lower_bounds = (intptr_t*)lengths;
694 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
697 /* Specialized version of mono_array_new_va () which avoids varargs */
699 mono_array_new_1 (MonoMethod *cm, guint32 length)
701 MonoDomain *domain = mono_domain_get ();
702 uintptr_t lengths [1];
703 intptr_t *lower_bounds;
707 pcount = mono_method_signature (cm)->param_count;
708 rank = cm->klass->rank;
710 lengths [0] = length;
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_2 (MonoMethod *cm, guint32 length1, guint32 length2)
727 MonoDomain *domain = mono_domain_get ();
728 uintptr_t lengths [2];
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;
739 g_assert (rank == pcount);
741 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
742 lower_bounds = alloca (sizeof (intptr_t) * rank);
743 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
748 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
752 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
754 MonoDomain *domain = mono_domain_get ();
755 uintptr_t lengths [3];
756 intptr_t *lower_bounds;
760 pcount = mono_method_signature (cm)->param_count;
761 rank = cm->klass->rank;
763 lengths [0] = length1;
764 lengths [1] = length2;
765 lengths [2] = length3;
767 g_assert (rank == pcount);
769 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
770 lower_bounds = alloca (sizeof (intptr_t) * rank);
771 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
776 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
780 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
782 MonoDomain *domain = mono_domain_get ();
783 uintptr_t lengths [4];
784 intptr_t *lower_bounds;
788 pcount = mono_method_signature (cm)->param_count;
789 rank = cm->klass->rank;
791 lengths [0] = length1;
792 lengths [1] = length2;
793 lengths [2] = length3;
794 lengths [3] = length4;
796 g_assert (rank == pcount);
798 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
799 lower_bounds = alloca (sizeof (intptr_t) * rank);
800 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
805 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
809 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
814 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
816 mono_class_init (field->parent);
818 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
819 if (!vtable->initialized)
820 mono_runtime_class_init (vtable);
822 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
824 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
825 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
827 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
833 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
836 MonoClass *handle_class;
839 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
840 if (!mono_error_ok (&error)) {
841 mono_error_set_pending_exception (&error);
844 mono_class_init (handle_class);
850 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
852 MonoMethodSignature *sig = mono_method_signature (method);
853 MonoGenericContext *generic_context;
855 if (sig->is_inflated) {
856 generic_context = mono_method_get_context (method);
858 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
859 g_assert (generic_container);
860 generic_context = &generic_container->context;
863 return mono_ldtoken_wrapper (image, token, generic_context);
867 mono_fconv_u8 (double v)
873 mono_rconv_u8 (float v)
878 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
880 mono_fconv_i8 (double v)
887 mono_fconv_u4 (double v)
889 /* MS.NET behaves like this for some reason */
891 if (isinf (v) || isnan (v))
899 /* Solaris doesn't have trunc */
901 extern long double aintl (long double);
904 /* FIXME: This means we will never throw overflow exceptions */
907 #endif /* HAVE_TRUNC */
910 mono_fconv_ovf_i8 (double v)
916 if (isnan(v) || trunc (v) != res) {
917 mono_set_pending_exception (mono_get_exception_overflow ());
924 mono_fconv_ovf_u8 (double v)
929 * The soft-float implementation of some ARM devices have a buggy guin64 to double
930 * conversion that it looses precision even when the integer if fully representable
933 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
935 * To work around this issue we test for value boundaries instead.
937 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
938 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
939 mono_set_pending_exception (mono_get_exception_overflow ());
945 if (isnan(v) || trunc (v) != res) {
946 mono_set_pending_exception (mono_get_exception_overflow ());
953 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
955 mono_rconv_i8 (float v)
962 mono_rconv_ovf_i8 (float v)
968 if (isnan(v) || trunc (v) != res) {
969 mono_set_pending_exception (mono_get_exception_overflow ());
976 mono_rconv_ovf_u8 (float v)
981 if (isnan(v) || trunc (v) != res) {
982 mono_set_pending_exception (mono_get_exception_overflow ());
988 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
990 mono_lconv_to_r8 (gint64 a)
996 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
998 mono_lconv_to_r4 (gint64 a)
1004 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1006 mono_conv_to_r8_un (guint32 a)
1012 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1014 mono_lconv_to_r8_un (guint64 a)
1020 #if defined(__native_client_codegen__) || defined(__native_client__)
1021 /* When we cross-compile to Native Client we can't directly embed calls */
1022 /* to the math library on the host. This will use the fmod on the target*/
1024 mono_fmod(double a, double b)
1031 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1033 MonoMethod *vmethod;
1035 MonoGenericContext *context = mono_method_get_context (method);
1037 mono_jit_stats.generic_virtual_invocations++;
1040 mono_set_pending_exception (mono_get_exception_null_reference ());
1043 vmethod = mono_object_get_virtual_method (obj, method);
1044 g_assert (!vmethod->klass->generic_container);
1045 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1046 g_assert (!context->method_inst || !context->method_inst->is_open);
1048 addr = mono_compile_method (vmethod);
1050 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1052 /* Since this is a virtual call, have to unbox vtypes */
1053 if (obj->vtable->klass->valuetype)
1054 *this_arg = mono_object_unbox (obj);
1062 mono_helper_ldstr (MonoImage *image, guint32 idx)
1064 return mono_ldstr (mono_domain_get (), image, idx);
1068 mono_helper_ldstr_mscorlib (guint32 idx)
1070 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1074 mono_helper_newobj_mscorlib (guint32 idx)
1077 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1079 if (!mono_error_ok (&error)) {
1080 mono_error_set_pending_exception (&error);
1084 return mono_object_new (mono_domain_get (), klass);
1088 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1089 * in generated code. So instead we emit a call to this function and place a gdb
1098 mono_create_corlib_exception_0 (guint32 token)
1100 return mono_exception_from_token (mono_defaults.corlib, token);
1104 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1106 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1110 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1112 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1116 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1118 MonoJitTlsData *jit_tls = NULL;
1121 if (mini_get_debug_options ()->better_cast_details) {
1122 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1123 jit_tls->class_cast_from = NULL;
1129 oklass = obj->vtable->klass;
1130 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1132 if (mono_object_isinst (obj, klass))
1135 if (mini_get_debug_options ()->better_cast_details) {
1136 jit_tls->class_cast_from = oklass;
1137 jit_tls->class_cast_to = klass;
1140 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1141 "System", "InvalidCastException"));
1147 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1149 MonoJitTlsData *jit_tls = NULL;
1150 gpointer cached_vtable, obj_vtable;
1152 if (mini_get_debug_options ()->better_cast_details) {
1153 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1154 jit_tls->class_cast_from = NULL;
1160 cached_vtable = *cache;
1161 obj_vtable = obj->vtable;
1163 if (cached_vtable == obj_vtable)
1166 if (mono_object_isinst (obj, klass)) {
1167 *cache = obj_vtable;
1171 if (mini_get_debug_options ()->better_cast_details) {
1172 jit_tls->class_cast_from = obj->vtable->klass;
1173 jit_tls->class_cast_to = klass;
1176 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1177 "System", "InvalidCastException"));
1183 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1185 size_t cached_vtable, obj_vtable;
1190 cached_vtable = (size_t)*cache;
1191 obj_vtable = (size_t)obj->vtable;
1193 if ((cached_vtable & ~0x1) == obj_vtable) {
1194 return (cached_vtable & 0x1) ? NULL : obj;
1197 if (mono_object_isinst (obj, klass)) {
1198 *cache = (gpointer)obj_vtable;
1202 *cache = (gpointer)(obj_vtable | 0x1);
1208 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1210 MonoMarshalSpec **mspecs;
1211 MonoMethodPInvoke piinfo;
1214 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1215 memset (&piinfo, 0, sizeof (piinfo));
1217 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1219 return mono_compile_method (m);
1223 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1228 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1229 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1233 if (mono_method_signature (cmethod)->pinvoke) {
1234 /* Object.GetType () */
1235 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1237 /* Lookup the virtual method */
1238 mono_class_setup_vtable (klass);
1239 g_assert (klass->vtable);
1240 vt_slot = mono_method_get_vtable_slot (cmethod);
1241 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1244 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1245 g_assert (iface_offset != -1);
1246 vt_slot += iface_offset;
1248 m = klass->vtable [vt_slot];
1249 if (cmethod->is_inflated)
1250 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1252 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1254 * Calling a non-vtype method with a vtype receiver, has to box.
1256 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1257 else if (klass->valuetype)
1259 * Calling a vtype method with a vtype receiver
1264 * Calling a non-vtype method
1266 *this_arg = *(gpointer*)mp;
1271 * mono_gsharedvt_constrained_call:
1273 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1274 * the arguments to the method in the format used by mono_runtime_invoke ().
1277 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1281 gpointer new_args [16];
1283 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1286 if (args && deref_arg) {
1287 new_args [0] = *(gpointer*)args [0];
1290 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1291 /* Object.GetType () */
1293 args [0] = this_arg;
1296 return mono_runtime_invoke (m, this_arg, args, NULL);
1300 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1302 if (klass->valuetype)
1303 mono_value_copy (dest, src, klass);
1305 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1309 mono_generic_class_init (MonoVTable *vtable)
1311 mono_runtime_class_init (vtable);
1315 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1317 return mono_class_fill_runtime_generic_context (vtable, index);
1321 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1323 return mono_method_fill_runtime_generic_context (mrgctx, index);
1327 * mono_resolve_iface_call:
1329 * Return the executable code for the iface method IMT_METHOD called on THIS.
1332 mono_resolve_iface_call (MonoObject *this, int imt_slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
1335 gpointer *imt, *vtable_slot;
1336 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1337 gpointer addr, compiled_method, aot_addr;
1338 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1340 // FIXME: Optimize this
1343 /* The caller will handle it */
1347 imt = (gpointer*)vt - MONO_IMT_SIZE;
1349 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1351 // FIXME: This can throw exceptions
1352 addr = compiled_method = mono_compile_method (impl_method);
1355 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
1356 generic_virtual = imt_method;
1357 need_rgctx_tramp = TRUE;
1360 if (generic_virtual || variant_iface) {
1361 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1362 need_unbox_tramp = TRUE;
1364 if (impl_method->klass->valuetype)
1365 need_unbox_tramp = TRUE;
1368 addr = mini_add_method_trampoline (impl_method, addr, need_rgctx_tramp, need_unbox_tramp);
1370 if (generic_virtual || variant_iface) {
1371 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1373 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1378 *vtable_slot = addr;
1380 if (need_rgctx_tramp && out_rgctx_arg) {
1381 MonoMethod *m = impl_method;
1385 * The exact compiled method might not be shared so it doesn't have an rgctx arg.
1387 ji = mini_jit_info_table_find (mono_domain_get (), compiled_method, NULL);
1388 if (!ji || (ji && ji->has_generic_jit_info)) {
1389 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && m->klass->rank && strstr (m->name, "System.Collections.Generic"))
1390 m = mono_aot_get_array_helper_from_wrapper (m);
1391 *out_rgctx_arg = mini_method_get_rgctx (m);
1399 is_generic_method_definition (MonoMethod *m)
1401 MonoGenericContext *context;
1404 if (!m->is_inflated)
1407 context = mono_method_get_context (m);
1408 if (!context->method_inst)
1410 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1416 * mono_resolve_vcall:
1418 * Return the executable code for calling this->vtable [slot].
1421 mono_resolve_vcall (MonoObject *this, int slot, MonoMethod *imt_method)
1424 MonoMethod *m, *generic_virtual = NULL;
1425 gpointer *vtable_slot;
1427 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1429 // FIXME: Optimize this
1432 /* The caller will handle it */
1437 vtable_slot = &(vt->vtable [slot]);
1439 /* Same as in common_call_trampoline () */
1441 /* Avoid loading metadata or creating a generic vtable if possible */
1442 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1443 if (addr && !vt->klass->valuetype) {
1444 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
1445 *vtable_slot = addr;
1447 return mono_create_ftnptr (mono_domain_get (), addr);
1450 m = mono_class_get_vtable_entry (vt->klass, slot);
1452 if (is_generic_method_definition (m)) {
1454 MonoGenericContext context = { NULL, NULL };
1455 MonoMethod *declaring;
1458 declaring = mono_method_get_declaring_generic_method (m);
1462 if (m->klass->generic_class)
1463 context.class_inst = m->klass->generic_class->context.class_inst;
1465 g_assert (!m->klass->generic_container);
1467 generic_virtual = imt_method;
1468 g_assert (generic_virtual);
1469 g_assert (generic_virtual->is_inflated);
1470 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1472 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1473 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1474 /* FIXME: only do this if the method is sharable */
1476 //g_assert_not_reached ();
1477 //need_rgctx_tramp = TRUE;
1480 if (generic_virtual) {
1481 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1482 need_unbox_tramp = TRUE;
1484 if (m->klass->valuetype)
1485 need_unbox_tramp = TRUE;
1488 // FIXME: This can throw exceptions
1489 addr = mono_compile_method (m);
1492 addr = mini_add_method_trampoline (m, addr, need_rgctx_tramp, need_unbox_tramp);
1494 *vtable_slot = addr;
1500 * mono_init_delegate:
1502 * Initialize a MonoDelegate object.
1503 * Similar to mono_delegate_ctor ().
1506 mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1508 MONO_OBJECT_SETREF (del, target, target);
1509 del->method = method;
1510 del->method_ptr = mono_compile_method (method);
1511 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1512 del->rgctx = mini_method_get_rgctx (method);
1516 mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1520 method = mono_object_get_virtual_method (target, method);
1522 MONO_OBJECT_SETREF (del, target, target);
1523 del->method = method;
1524 del->method_ptr = mono_compile_method (method);
1525 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1526 del->rgctx = mini_method_get_rgctx (method);
1530 mono_get_assembly_object (MonoImage *image)
1532 return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1536 mono_ckfinite (double d)
1538 if (isinf (d) || isnan (d))
1539 mono_set_pending_exception (mono_get_exception_arithmetic ());