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>
21 #include <mono/metadata/threads-types.h>
22 #include <mono/metadata/reflection-internals.h>
25 #include "mini-llvm-cpp.h"
29 mono_ldftn (MonoMethod *method)
35 // FIXME: No error handling
37 addr = mono_compile_method (method);
40 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
41 /* The caller doesn't pass it */
42 g_assert_not_reached ();
44 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
48 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
49 if (!mono_error_ok (&error)) {
50 mono_error_set_pending_exception (&error);
53 return mono_create_ftnptr (mono_domain_get (), addr);
57 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
63 mono_set_pending_exception (mono_get_exception_null_reference ());
67 res = mono_object_get_virtual_method (obj, method);
69 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
70 MonoGenericContext context = { NULL, NULL };
72 if (res->klass->generic_class)
73 context.class_inst = res->klass->generic_class->context.class_inst;
74 else if (res->klass->generic_container)
75 context.class_inst = res->klass->generic_container->context.class_inst;
76 context.method_inst = mono_method_get_context (method)->method_inst;
78 res = mono_class_inflate_generic_method_checked (res, &context, &error);
79 if (!mono_error_ok (&error)) {
80 mono_error_set_pending_exception (&error);
85 /* An rgctx wrapper is added by the trampolines no need to do it here */
87 return mono_ldftn (res);
91 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
93 return ldvirtfn_internal (obj, method, FALSE);
97 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
99 return ldvirtfn_internal (obj, method, TRUE);
103 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
106 mono_set_pending_exception (mono_get_exception_null_reference ());
109 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
110 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
115 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
118 mono_llmult (gint64 a, gint64 b)
124 mono_llmult_ovf_un (guint64 a, guint64 b)
127 guint32 ah = a >> 32;
129 guint32 bh = b >> 32;
132 // fixme: this is incredible slow
135 goto raise_exception;
137 res = (guint64)al * (guint64)bl;
139 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
142 goto raise_exception;
144 res += ((guint64)t1) << 32;
149 mono_set_pending_exception (mono_get_exception_overflow ());
154 mono_llmult_ovf (gint64 a, gint64 b)
161 Use Karatsuba algorithm where:
162 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
163 where Ah is the "high half" (most significant 32 bits) of a and
164 where Al is the "low half" (least significant 32 bits) of a and
165 where Bh is the "high half" of b and Bl is the "low half" and
166 where R is the Radix or "size of the half" (in our case 32 bits)
168 Note, for the product of two 64 bit numbers to fit into a 64
169 result, ah and/or bh must be 0. This will save us from doing
170 the AhBh term at all.
172 Also note that we refactor so that we don't overflow 64 bits with
173 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
179 /* need to work with absoulte values, so find out what the
180 resulting sign will be and convert any negative numbers
181 from two's complement
185 if (((guint32)ah == 0x80000000) && (al == 0)) {
186 /* This has no two's complement */
192 goto raise_exception;
195 /* flip the bits and add 1 */
206 if (((guint32)bh == 0x80000000) && (bl == 0)) {
207 /* This has no two's complement */
213 goto raise_exception;
216 /* flip the bits and add 1 */
226 /* we overflow for sure if both upper halves are greater
227 than zero because we would need to shift their
228 product 64 bits to the left and that will not fit
229 in a 64 bit result */
231 goto raise_exception;
232 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
233 goto raise_exception;
235 /* do the AlBl term first */
236 t1 = (gint64)al * (gint64)bl;
240 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
241 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
242 /* check for overflow */
244 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
245 goto raise_exception;
250 goto raise_exception;
258 mono_set_pending_exception (mono_get_exception_overflow ());
263 mono_lldiv (gint64 a, gint64 b)
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
267 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
270 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
271 mono_set_pending_exception (mono_get_exception_arithmetic ());
279 mono_llrem (gint64 a, gint64 b)
281 #ifdef MONO_ARCH_NEED_DIV_CHECK
283 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
286 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
287 mono_set_pending_exception (mono_get_exception_arithmetic ());
295 mono_lldiv_un (guint64 a, guint64 b)
297 #ifdef MONO_ARCH_NEED_DIV_CHECK
299 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
307 mono_llrem_un (guint64 a, guint64 b)
309 #ifdef MONO_ARCH_NEED_DIV_CHECK
311 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
320 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
323 mono_lshl (guint64 a, gint32 shamt)
327 res = a << (shamt & 0x7f);
329 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
335 mono_lshr_un (guint64 a, gint32 shamt)
339 res = a >> (shamt & 0x7f);
341 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
347 mono_lshr (gint64 a, gint32 shamt)
351 res = a >> (shamt & 0x7f);
353 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
360 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
363 mono_idiv (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_idiv_un (guint32 a, guint32 b)
381 #ifdef MONO_ARCH_NEED_DIV_CHECK
383 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
391 mono_irem (gint32 a, gint32 b)
393 #ifdef MONO_ARCH_NEED_DIV_CHECK
395 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
398 else if (b == -1 && a == (0x80000000)) {
399 mono_set_pending_exception (mono_get_exception_overflow ());
407 mono_irem_un (guint32 a, guint32 b)
409 #ifdef MONO_ARCH_NEED_DIV_CHECK
411 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
420 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
423 mono_imul (gint32 a, gint32 b)
429 mono_imul_ovf (gint32 a, gint32 b)
433 res = (gint64)a * (gint64)b;
435 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
436 mono_set_pending_exception (mono_get_exception_overflow ());
444 mono_imul_ovf_un (guint32 a, guint32 b)
448 res = (guint64)a * (guint64)b;
451 mono_set_pending_exception (mono_get_exception_overflow ());
459 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
461 mono_fdiv (double a, double b)
467 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
470 mono_fsub (double a, double b)
476 mono_fadd (double a, double b)
482 mono_fmul (double a, double b)
494 mono_fconv_r4 (double a)
500 mono_conv_to_r8 (int a)
506 mono_conv_to_r4 (int a)
508 return (double)(float)a;
512 mono_fconv_i1 (double a)
518 mono_fconv_i2 (double a)
524 mono_fconv_i4 (double a)
530 mono_fconv_u1 (double a)
536 mono_fconv_u2 (double a)
542 mono_fcmp_eq (double a, double b)
548 mono_fcmp_ge (double a, double b)
554 mono_fcmp_gt (double a, double b)
560 mono_fcmp_le (double a, double b)
566 mono_fcmp_lt (double a, double b)
572 mono_fcmp_ne_un (double a, double b)
574 return isunordered (a, b) || a != b;
578 mono_fcmp_ge_un (double a, double b)
580 return isunordered (a, b) || a >= b;
584 mono_fcmp_gt_un (double a, double b)
586 return isunordered (a, b) || a > b;
590 mono_fcmp_le_un (double a, double b)
592 return isunordered (a, b) || a <= b;
596 mono_fcmp_lt_un (double a, double b)
598 return isunordered (a, b) || a < b;
602 mono_fceq (double a, double b)
608 mono_fcgt (double a, double b)
614 mono_fcgt_un (double a, double b)
616 return isunordered (a, b) || a > b;
620 mono_fclt (double a, double b)
626 mono_fclt_un (double a, double b)
628 return isunordered (a, b) || a < b;
632 mono_isfinite (double a)
637 g_assert_not_reached ();
643 mono_fload_r4 (float *ptr)
649 mono_fstore_r4 (double val, float *ptr)
654 /* returns the integer bitpattern that is passed in the regs or stack */
656 mono_fload_r4_arg (double val)
658 float v = (float)val;
659 return *(guint32*)&v;
665 mono_array_new_va (MonoMethod *cm, ...)
669 MonoDomain *domain = mono_domain_get ();
672 intptr_t *lower_bounds;
677 pcount = mono_method_signature (cm)->param_count;
678 rank = cm->klass->rank;
682 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
683 for (i = 0; i < pcount; ++i)
684 lengths [i] = d = va_arg(ap, int);
686 if (rank == pcount) {
687 /* Only lengths provided. */
688 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
689 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
690 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
695 g_assert (pcount == (rank * 2));
696 /* lower bounds are first. */
697 lower_bounds = (intptr_t*)lengths;
702 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
704 if (!mono_error_ok (&error)) {
705 mono_error_set_pending_exception (&error);
712 /* Specialized version of mono_array_new_va () which avoids varargs */
714 mono_array_new_1 (MonoMethod *cm, guint32 length)
718 MonoDomain *domain = mono_domain_get ();
719 uintptr_t lengths [1];
720 intptr_t *lower_bounds;
724 pcount = mono_method_signature (cm)->param_count;
725 rank = cm->klass->rank;
727 lengths [0] = length;
729 g_assert (rank == pcount);
731 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
732 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
733 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
738 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
740 if (!mono_error_ok (&error)) {
741 mono_error_set_pending_exception (&error);
749 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
753 MonoDomain *domain = mono_domain_get ();
754 uintptr_t lengths [2];
755 intptr_t *lower_bounds;
759 pcount = mono_method_signature (cm)->param_count;
760 rank = cm->klass->rank;
762 lengths [0] = length1;
763 lengths [1] = length2;
765 g_assert (rank == pcount);
767 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
768 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
769 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
774 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
776 if (!mono_error_ok (&error)) {
777 mono_error_set_pending_exception (&error);
785 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
789 MonoDomain *domain = mono_domain_get ();
790 uintptr_t lengths [3];
791 intptr_t *lower_bounds;
795 pcount = mono_method_signature (cm)->param_count;
796 rank = cm->klass->rank;
798 lengths [0] = length1;
799 lengths [1] = length2;
800 lengths [2] = length3;
802 g_assert (rank == pcount);
804 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
805 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
806 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
811 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
813 if (!mono_error_ok (&error)) {
814 mono_error_set_pending_exception (&error);
822 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
826 MonoDomain *domain = mono_domain_get ();
827 uintptr_t lengths [4];
828 intptr_t *lower_bounds;
832 pcount = mono_method_signature (cm)->param_count;
833 rank = cm->klass->rank;
835 lengths [0] = length1;
836 lengths [1] = length2;
837 lengths [2] = length3;
838 lengths [3] = length4;
840 g_assert (rank == pcount);
842 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
843 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
844 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
849 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
851 if (!mono_error_ok (&error)) {
852 mono_error_set_pending_exception (&error);
860 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
866 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
868 mono_class_init (field->parent);
870 vtable = mono_class_vtable_full (domain, field->parent, &error);
871 if (!is_ok (&error)) {
872 mono_error_set_pending_exception (&error);
875 if (!vtable->initialized) {
876 if (!mono_runtime_class_init_full (vtable, &error)) {
877 mono_error_set_pending_exception (&error);
882 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
884 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
885 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
887 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
893 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
896 MonoClass *handle_class;
899 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
900 if (!mono_error_ok (&error)) {
901 mono_error_set_pending_exception (&error);
904 mono_class_init (handle_class);
910 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
912 MonoMethodSignature *sig = mono_method_signature (method);
913 MonoGenericContext *generic_context;
915 if (sig->is_inflated) {
916 generic_context = mono_method_get_context (method);
918 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
919 g_assert (generic_container);
920 generic_context = &generic_container->context;
923 return mono_ldtoken_wrapper (image, token, generic_context);
927 mono_fconv_u8 (double v)
933 mono_rconv_u8 (float v)
938 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
940 mono_fconv_i8 (double v)
947 mono_fconv_u4 (double v)
949 /* MS.NET behaves like this for some reason */
951 if (isinf (v) || isnan (v))
959 /* Solaris doesn't have trunc */
961 extern long double aintl (long double);
964 /* FIXME: This means we will never throw overflow exceptions */
967 #endif /* HAVE_TRUNC */
970 mono_fconv_ovf_i8 (double v)
976 if (isnan(v) || trunc (v) != res) {
977 mono_set_pending_exception (mono_get_exception_overflow ());
984 mono_fconv_ovf_u8 (double v)
989 * The soft-float implementation of some ARM devices have a buggy guin64 to double
990 * conversion that it looses precision even when the integer if fully representable
993 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
995 * To work around this issue we test for value boundaries instead.
997 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
998 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
999 mono_set_pending_exception (mono_get_exception_overflow ());
1005 if (isnan(v) || trunc (v) != res) {
1006 mono_set_pending_exception (mono_get_exception_overflow ());
1013 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1015 mono_rconv_i8 (float v)
1022 mono_rconv_ovf_i8 (float v)
1028 if (isnan(v) || trunc (v) != res) {
1029 mono_set_pending_exception (mono_get_exception_overflow ());
1036 mono_rconv_ovf_u8 (float v)
1041 if (isnan(v) || trunc (v) != res) {
1042 mono_set_pending_exception (mono_get_exception_overflow ());
1048 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1050 mono_lconv_to_r8 (gint64 a)
1056 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1058 mono_lconv_to_r4 (gint64 a)
1064 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1066 mono_conv_to_r8_un (guint32 a)
1072 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1074 mono_lconv_to_r8_un (guint64 a)
1080 #if defined(__native_client_codegen__) || defined(__native_client__)
1081 /* When we cross-compile to Native Client we can't directly embed calls */
1082 /* to the math library on the host. This will use the fmod on the target*/
1084 mono_fmod(double a, double b)
1091 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1093 MonoMethod *vmethod;
1095 MonoGenericContext *context = mono_method_get_context (method);
1097 mono_jit_stats.generic_virtual_invocations++;
1100 mono_set_pending_exception (mono_get_exception_null_reference ());
1103 vmethod = mono_object_get_virtual_method (obj, method);
1104 g_assert (!vmethod->klass->generic_container);
1105 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1106 g_assert (!context->method_inst || !context->method_inst->is_open);
1108 addr = mono_compile_method (vmethod);
1110 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1112 /* Since this is a virtual call, have to unbox vtypes */
1113 if (obj->vtable->klass->valuetype)
1114 *this_arg = mono_object_unbox (obj);
1122 mono_helper_ldstr (MonoImage *image, guint32 idx)
1124 return mono_ldstr (mono_domain_get (), image, idx);
1128 mono_helper_ldstr_mscorlib (guint32 idx)
1130 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1134 mono_helper_newobj_mscorlib (guint32 idx)
1137 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1139 if (!mono_error_ok (&error)) {
1140 mono_error_set_pending_exception (&error);
1144 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1145 if (!mono_error_ok (&error))
1146 mono_error_set_pending_exception (&error);
1151 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1152 * in generated code. So instead we emit a call to this function and place a gdb
1161 mono_create_corlib_exception_0 (guint32 token)
1163 return mono_exception_from_token (mono_defaults.corlib, token);
1167 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1169 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1173 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1175 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1179 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1181 MonoJitTlsData *jit_tls = NULL;
1184 if (mini_get_debug_options ()->better_cast_details) {
1185 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1186 jit_tls->class_cast_from = NULL;
1192 oklass = obj->vtable->klass;
1193 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1195 if (mono_object_isinst (obj, klass))
1198 if (mini_get_debug_options ()->better_cast_details) {
1199 jit_tls->class_cast_from = oklass;
1200 jit_tls->class_cast_to = klass;
1203 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1204 "System", "InvalidCastException"));
1210 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1212 MonoJitTlsData *jit_tls = NULL;
1213 gpointer cached_vtable, obj_vtable;
1215 if (mini_get_debug_options ()->better_cast_details) {
1216 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1217 jit_tls->class_cast_from = NULL;
1223 cached_vtable = *cache;
1224 obj_vtable = obj->vtable;
1226 if (cached_vtable == obj_vtable)
1229 if (mono_object_isinst (obj, klass)) {
1230 *cache = obj_vtable;
1234 if (mini_get_debug_options ()->better_cast_details) {
1235 jit_tls->class_cast_from = obj->vtable->klass;
1236 jit_tls->class_cast_to = klass;
1239 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1240 "System", "InvalidCastException"));
1246 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1248 size_t cached_vtable, obj_vtable;
1253 cached_vtable = (size_t)*cache;
1254 obj_vtable = (size_t)obj->vtable;
1256 if ((cached_vtable & ~0x1) == obj_vtable) {
1257 return (cached_vtable & 0x1) ? NULL : obj;
1260 if (mono_object_isinst (obj, klass)) {
1261 *cache = (gpointer)obj_vtable;
1265 *cache = (gpointer)(obj_vtable | 0x1);
1271 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1273 MonoMarshalSpec **mspecs;
1274 MonoMethodPInvoke piinfo;
1277 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1278 memset (&piinfo, 0, sizeof (piinfo));
1280 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1282 return mono_compile_method (m);
1286 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1289 int vt_slot, iface_offset;
1291 mono_error_init (error);
1293 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1294 MonoObject *this_obj;
1296 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1297 this_obj = *(MonoObject**)mp;
1298 g_assert (this_obj);
1300 klass = this_obj->vtable->klass;
1303 if (mono_method_signature (cmethod)->pinvoke) {
1304 /* Object.GetType () */
1305 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1307 /* Lookup the virtual method */
1308 mono_class_setup_vtable (klass);
1309 g_assert (klass->vtable);
1310 vt_slot = mono_method_get_vtable_slot (cmethod);
1311 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1312 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1313 g_assert (iface_offset != -1);
1314 vt_slot += iface_offset;
1316 m = klass->vtable [vt_slot];
1317 if (cmethod->is_inflated)
1318 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1321 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1323 * Calling a non-vtype method with a vtype receiver, has to box.
1325 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1326 else if (klass->valuetype)
1328 * Calling a vtype method with a vtype receiver
1333 * Calling a non-vtype method
1335 *this_arg = *(gpointer*)mp;
1340 * mono_gsharedvt_constrained_call:
1342 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1343 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1346 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1352 gpointer new_args [16];
1354 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1355 if (!mono_error_ok (&error)) {
1356 mono_error_set_pending_exception (&error);
1362 if (args && deref_arg) {
1363 new_args [0] = *(gpointer*)args [0];
1366 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1367 /* Object.GetType () */
1369 args [0] = this_arg;
1373 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1374 if (!mono_error_ok (&error)) {
1375 mono_error_set_pending_exception (&error);
1383 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1385 if (klass->valuetype)
1386 mono_value_copy (dest, src, klass);
1388 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1392 ves_icall_runtime_class_init (MonoVTable *vtable)
1394 MONO_REQ_GC_UNSAFE_MODE;
1397 mono_runtime_class_init_full (vtable, &error);
1398 mono_error_set_pending_exception (&error);
1403 mono_generic_class_init (MonoVTable *vtable)
1406 mono_runtime_class_init_full (vtable, &error);
1407 mono_error_set_pending_exception (&error);
1411 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1416 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1417 if (!mono_error_ok (&error)) {
1418 mono_error_set_pending_exception (&error);
1425 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1430 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1431 if (!mono_error_ok (&error)) {
1432 mono_error_set_pending_exception (&error);
1439 * resolve_iface_call:
1441 * Return the executable code for the iface method IMT_METHOD called on THIS.
1442 * This function is called on a slowpath, so it doesn't need to be fast.
1443 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1447 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1450 gpointer *imt, *vtable_slot;
1451 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1452 gpointer addr, compiled_method, aot_addr;
1453 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1456 /* The caller will handle it */
1459 vt = this_obj->vtable;
1460 imt = (gpointer*)vt - MONO_IMT_SIZE;
1462 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1464 // FIXME: This can throw exceptions
1465 addr = compiled_method = mono_compile_method (impl_method);
1468 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1469 generic_virtual = imt_method;
1471 if (generic_virtual || variant_iface) {
1472 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1473 need_unbox_tramp = TRUE;
1475 if (impl_method->klass->valuetype)
1476 need_unbox_tramp = TRUE;
1479 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1481 if (generic_virtual || variant_iface) {
1482 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1484 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1493 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1495 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1499 is_generic_method_definition (MonoMethod *m)
1501 MonoGenericContext *context;
1504 if (!m->is_inflated)
1507 context = mono_method_get_context (m);
1508 if (!context->method_inst)
1510 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1518 * Return the executable code for calling vt->vtable [slot].
1519 * This function is called on a slowpath, so it doesn't need to be fast.
1520 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1524 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1526 MonoMethod *m, *generic_virtual = NULL;
1527 gpointer addr, compiled_method;
1528 gboolean need_unbox_tramp = FALSE;
1530 /* Same as in common_call_trampoline () */
1532 /* Avoid loading metadata or creating a generic vtable if possible */
1533 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1534 if (addr && !vt->klass->valuetype)
1535 return mono_create_ftnptr (mono_domain_get (), addr);
1537 m = mono_class_get_vtable_entry (vt->klass, slot);
1539 if (is_generic_method_definition (m)) {
1541 MonoGenericContext context = { NULL, NULL };
1542 MonoMethod *declaring;
1545 declaring = mono_method_get_declaring_generic_method (m);
1549 if (m->klass->generic_class)
1550 context.class_inst = m->klass->generic_class->context.class_inst;
1552 g_assert (!m->klass->generic_container);
1554 generic_virtual = imt_method;
1555 g_assert (generic_virtual);
1556 g_assert (generic_virtual->is_inflated);
1557 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1559 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1560 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1563 if (generic_virtual) {
1564 if (vt->klass->valuetype)
1565 need_unbox_tramp = TRUE;
1567 if (m->klass->valuetype)
1568 need_unbox_tramp = TRUE;
1571 // FIXME: This can throw exceptions
1572 addr = compiled_method = mono_compile_method (m);
1575 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1577 if (!gsharedvt && generic_virtual) {
1578 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1579 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1581 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1582 vt, vt->vtable + slot,
1583 generic_virtual, ftndesc);
1590 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1592 g_assert (this_obj);
1594 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1598 * mono_resolve_generic_virtual_call:
1600 * Resolve a generic virtual call.
1601 * This function is called on a slowpath, so it doesn't need to be fast.
1604 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1607 gpointer addr, compiled_method;
1608 gboolean need_unbox_tramp = FALSE;
1610 MonoGenericContext context = { NULL, NULL };
1611 MonoMethod *declaring;
1612 gpointer arg = NULL;
1614 m = mono_class_get_vtable_entry (vt->klass, slot);
1616 g_assert (is_generic_method_definition (m));
1619 declaring = mono_method_get_declaring_generic_method (m);
1623 if (m->klass->generic_class)
1624 context.class_inst = m->klass->generic_class->context.class_inst;
1626 g_assert (!m->klass->generic_container);
1628 g_assert (generic_virtual->is_inflated);
1629 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1631 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1632 g_assert (mono_error_ok (&error));
1634 if (vt->klass->valuetype)
1635 need_unbox_tramp = TRUE;
1637 // FIXME: This can throw exceptions
1638 addr = compiled_method = mono_compile_method (m);
1641 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1644 * This wastes memory but the memory usage is bounded since
1645 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1646 * this vtable slot so we are not called any more for this instantiation.
1648 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1650 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1651 vt, vt->vtable + slot,
1652 generic_virtual, ftndesc);
1657 * mono_resolve_generic_virtual_call:
1659 * Resolve a generic virtual/variant iface call on interfaces.
1660 * This function is called on a slowpath, so it doesn't need to be fast.
1663 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1665 MonoMethod *m, *variant_iface;
1666 gpointer addr, aot_addr, compiled_method;
1667 gboolean need_unbox_tramp = FALSE;
1668 gboolean need_rgctx_tramp;
1669 gpointer arg = NULL;
1672 imt = (gpointer*)vt - MONO_IMT_SIZE;
1674 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1676 if (vt->klass->valuetype)
1677 need_unbox_tramp = TRUE;
1679 // FIXME: This can throw exceptions
1680 addr = compiled_method = mono_compile_method (m);
1683 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1686 * This wastes memory but the memory usage is bounded since
1687 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1688 * this vtable slot so we are not called any more for this instantiation.
1690 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1692 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1694 variant_iface ? variant_iface : generic_virtual, ftndesc);
1699 * mono_init_vtable_slot:
1701 * Initialize slot SLOT of VTABLE.
1702 * Return the contents of the vtable slot.
1705 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1707 gpointer arg = NULL;
1711 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1712 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1715 mono_memory_barrier ();
1717 vtable->vtable [slot] = ftnptr;
1723 * mono_llvmonly_init_delegate:
1725 * Initialize a MonoDelegate object.
1726 * Similar to mono_delegate_ctor ().
1729 mono_llvmonly_init_delegate (MonoDelegate *del)
1731 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1734 * We store a MonoFtnDesc in del->method_code.
1735 * It would be better to store an ftndesc in del->method_ptr too,
1736 * but we don't have a a structure which could own its memory.
1738 if (G_UNLIKELY (!ftndesc)) {
1739 gpointer addr = mono_compile_method (del->method);
1741 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1742 addr = mono_aot_get_unbox_trampoline (del->method);
1744 gpointer arg = mini_get_delegate_arg (del->method, addr);
1746 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1747 mono_memory_barrier ();
1748 *del->method_code = (gpointer)ftndesc;
1750 del->method_ptr = ftndesc->addr;
1751 del->extra_arg = ftndesc->arg;
1755 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1759 method = mono_object_get_virtual_method (target, method);
1761 del->method = method;
1762 del->method_ptr = mono_compile_method (method);
1763 if (method->klass->valuetype)
1764 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1765 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1769 mono_get_assembly_object (MonoImage *image)
1773 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1775 mono_error_set_pending_exception (&error);
1780 mono_get_method_object (MonoMethod *method)
1783 MonoObject * result;
1784 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1785 mono_error_set_pending_exception (&error);
1790 mono_ckfinite (double d)
1792 if (isinf (d) || isnan (d))
1793 mono_set_pending_exception (mono_get_exception_arithmetic ());
1798 * mono_interruption_checkpoint_from_trampoline:
1800 * Check whenever the thread has a pending exception, and throw it
1802 * Architectures should move away from calling this function and
1803 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1804 * rewrind to the parent frame, and throw the exception normally.
1807 mono_interruption_checkpoint_from_trampoline (void)
1811 ex = mono_thread_force_interruption_checkpoint_noraise ();
1813 mono_raise_exception (ex);