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)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "jit-icalls.h"
21 #include <mono/utils/mono-error-internals.h>
22 #include <mono/metadata/threads-types.h>
23 #include <mono/metadata/reflection-internals.h>
26 #include "mini-llvm-cpp.h"
30 mono_ldftn (MonoMethod *method)
36 // FIXME: No error handling
38 addr = mono_compile_method_checked (method, &error);
39 mono_error_assert_ok (&error);
42 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
43 /* The caller doesn't pass it */
44 g_assert_not_reached ();
46 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
50 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
51 if (!mono_error_ok (&error)) {
52 mono_error_set_pending_exception (&error);
55 return mono_create_ftnptr (mono_domain_get (), addr);
59 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
65 mono_set_pending_exception (mono_get_exception_null_reference ());
69 res = mono_object_get_virtual_method (obj, method);
71 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
72 MonoGenericContext context = { NULL, NULL };
74 if (res->klass->generic_class)
75 context.class_inst = res->klass->generic_class->context.class_inst;
76 else if (res->klass->generic_container)
77 context.class_inst = res->klass->generic_container->context.class_inst;
78 context.method_inst = mono_method_get_context (method)->method_inst;
80 res = mono_class_inflate_generic_method_checked (res, &context, &error);
81 if (!mono_error_ok (&error)) {
82 mono_error_set_pending_exception (&error);
87 /* An rgctx wrapper is added by the trampolines no need to do it here */
89 return mono_ldftn (res);
93 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
95 return ldvirtfn_internal (obj, method, FALSE);
99 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
101 return ldvirtfn_internal (obj, method, TRUE);
105 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
109 mono_set_pending_exception (mono_get_exception_null_reference ());
112 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
113 if (mono_error_set_pending_exception (&error))
115 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
120 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
123 mono_llmult (gint64 a, gint64 b)
129 mono_llmult_ovf_un (guint64 a, guint64 b)
132 guint32 ah = a >> 32;
134 guint32 bh = b >> 32;
137 // fixme: this is incredible slow
140 goto raise_exception;
142 res = (guint64)al * (guint64)bl;
144 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
147 goto raise_exception;
149 res += ((guint64)t1) << 32;
154 mono_set_pending_exception (mono_get_exception_overflow ());
159 mono_llmult_ovf (gint64 a, gint64 b)
166 Use Karatsuba algorithm where:
167 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
168 where Ah is the "high half" (most significant 32 bits) of a and
169 where Al is the "low half" (least significant 32 bits) of a and
170 where Bh is the "high half" of b and Bl is the "low half" and
171 where R is the Radix or "size of the half" (in our case 32 bits)
173 Note, for the product of two 64 bit numbers to fit into a 64
174 result, ah and/or bh must be 0. This will save us from doing
175 the AhBh term at all.
177 Also note that we refactor so that we don't overflow 64 bits with
178 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
184 /* need to work with absoulte values, so find out what the
185 resulting sign will be and convert any negative numbers
186 from two's complement
190 if (((guint32)ah == 0x80000000) && (al == 0)) {
191 /* This has no two's complement */
197 goto raise_exception;
200 /* flip the bits and add 1 */
211 if (((guint32)bh == 0x80000000) && (bl == 0)) {
212 /* This has no two's complement */
218 goto raise_exception;
221 /* flip the bits and add 1 */
231 /* we overflow for sure if both upper halves are greater
232 than zero because we would need to shift their
233 product 64 bits to the left and that will not fit
234 in a 64 bit result */
236 goto raise_exception;
237 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
238 goto raise_exception;
240 /* do the AlBl term first */
241 t1 = (gint64)al * (gint64)bl;
245 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
246 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
247 /* check for overflow */
249 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
250 goto raise_exception;
255 goto raise_exception;
263 mono_set_pending_exception (mono_get_exception_overflow ());
268 mono_lldiv (gint64 a, gint64 b)
270 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
275 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
276 mono_set_pending_exception (mono_get_exception_arithmetic ());
284 mono_llrem (gint64 a, gint64 b)
286 #ifdef MONO_ARCH_NEED_DIV_CHECK
288 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
291 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
292 mono_set_pending_exception (mono_get_exception_arithmetic ());
300 mono_lldiv_un (guint64 a, guint64 b)
302 #ifdef MONO_ARCH_NEED_DIV_CHECK
304 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
312 mono_llrem_un (guint64 a, guint64 b)
314 #ifdef MONO_ARCH_NEED_DIV_CHECK
316 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
325 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
328 mono_lshl (guint64 a, gint32 shamt)
332 res = a << (shamt & 0x7f);
334 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
340 mono_lshr_un (guint64 a, gint32 shamt)
344 res = a >> (shamt & 0x7f);
346 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
352 mono_lshr (gint64 a, gint32 shamt)
356 res = a >> (shamt & 0x7f);
358 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
365 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
368 mono_idiv (gint32 a, gint32 b)
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
372 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
375 else if (b == -1 && a == (0x80000000)) {
376 mono_set_pending_exception (mono_get_exception_overflow ());
384 mono_idiv_un (guint32 a, guint32 b)
386 #ifdef MONO_ARCH_NEED_DIV_CHECK
388 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
396 mono_irem (gint32 a, gint32 b)
398 #ifdef MONO_ARCH_NEED_DIV_CHECK
400 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
403 else if (b == -1 && a == (0x80000000)) {
404 mono_set_pending_exception (mono_get_exception_overflow ());
412 mono_irem_un (guint32 a, guint32 b)
414 #ifdef MONO_ARCH_NEED_DIV_CHECK
416 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
425 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
428 mono_imul (gint32 a, gint32 b)
434 mono_imul_ovf (gint32 a, gint32 b)
438 res = (gint64)a * (gint64)b;
440 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
441 mono_set_pending_exception (mono_get_exception_overflow ());
449 mono_imul_ovf_un (guint32 a, guint32 b)
453 res = (guint64)a * (guint64)b;
456 mono_set_pending_exception (mono_get_exception_overflow ());
464 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
466 mono_fdiv (double a, double b)
472 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
475 mono_fsub (double a, double b)
481 mono_fadd (double a, double b)
487 mono_fmul (double a, double b)
499 mono_fconv_r4 (double a)
505 mono_conv_to_r8 (int a)
511 mono_conv_to_r4 (int a)
513 return (double)(float)a;
517 mono_fconv_i1 (double a)
523 mono_fconv_i2 (double a)
529 mono_fconv_i4 (double a)
535 mono_fconv_u1 (double a)
541 mono_fconv_u2 (double a)
547 mono_fcmp_eq (double a, double b)
553 mono_fcmp_ge (double a, double b)
559 mono_fcmp_gt (double a, double b)
565 mono_fcmp_le (double a, double b)
571 mono_fcmp_lt (double a, double b)
577 mono_fcmp_ne_un (double a, double b)
579 return isunordered (a, b) || a != b;
583 mono_fcmp_ge_un (double a, double b)
585 return isunordered (a, b) || a >= b;
589 mono_fcmp_gt_un (double a, double b)
591 return isunordered (a, b) || a > b;
595 mono_fcmp_le_un (double a, double b)
597 return isunordered (a, b) || a <= b;
601 mono_fcmp_lt_un (double a, double b)
603 return isunordered (a, b) || a < b;
607 mono_fceq (double a, double b)
613 mono_fcgt (double a, double b)
619 mono_fcgt_un (double a, double b)
621 return isunordered (a, b) || a > b;
625 mono_fclt (double a, double b)
631 mono_fclt_un (double a, double b)
633 return isunordered (a, b) || a < b;
637 mono_isfinite (double a)
642 g_assert_not_reached ();
648 mono_fload_r4 (float *ptr)
654 mono_fstore_r4 (double val, float *ptr)
659 /* returns the integer bitpattern that is passed in the regs or stack */
661 mono_fload_r4_arg (double val)
663 float v = (float)val;
664 return *(guint32*)&v;
670 mono_array_new_va (MonoMethod *cm, ...)
674 MonoDomain *domain = mono_domain_get ();
677 intptr_t *lower_bounds;
682 pcount = mono_method_signature (cm)->param_count;
683 rank = cm->klass->rank;
687 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
688 for (i = 0; i < pcount; ++i)
689 lengths [i] = d = va_arg(ap, int);
691 if (rank == pcount) {
692 /* Only lengths provided. */
693 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
694 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
695 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
700 g_assert (pcount == (rank * 2));
701 /* lower bounds are first. */
702 lower_bounds = (intptr_t*)lengths;
707 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
709 if (!mono_error_ok (&error)) {
710 mono_error_set_pending_exception (&error);
717 /* Specialized version of mono_array_new_va () which avoids varargs */
719 mono_array_new_1 (MonoMethod *cm, guint32 length)
723 MonoDomain *domain = mono_domain_get ();
724 uintptr_t lengths [1];
725 intptr_t *lower_bounds;
729 pcount = mono_method_signature (cm)->param_count;
730 rank = cm->klass->rank;
732 lengths [0] = length;
734 g_assert (rank == pcount);
736 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
737 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
738 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
743 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
745 if (!mono_error_ok (&error)) {
746 mono_error_set_pending_exception (&error);
754 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
758 MonoDomain *domain = mono_domain_get ();
759 uintptr_t lengths [2];
760 intptr_t *lower_bounds;
764 pcount = mono_method_signature (cm)->param_count;
765 rank = cm->klass->rank;
767 lengths [0] = length1;
768 lengths [1] = length2;
770 g_assert (rank == pcount);
772 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
773 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
774 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
779 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
781 if (!mono_error_ok (&error)) {
782 mono_error_set_pending_exception (&error);
790 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
794 MonoDomain *domain = mono_domain_get ();
795 uintptr_t lengths [3];
796 intptr_t *lower_bounds;
800 pcount = mono_method_signature (cm)->param_count;
801 rank = cm->klass->rank;
803 lengths [0] = length1;
804 lengths [1] = length2;
805 lengths [2] = length3;
807 g_assert (rank == pcount);
809 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
810 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
811 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
816 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
818 if (!mono_error_ok (&error)) {
819 mono_error_set_pending_exception (&error);
827 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
831 MonoDomain *domain = mono_domain_get ();
832 uintptr_t lengths [4];
833 intptr_t *lower_bounds;
837 pcount = mono_method_signature (cm)->param_count;
838 rank = cm->klass->rank;
840 lengths [0] = length1;
841 lengths [1] = length2;
842 lengths [2] = length3;
843 lengths [3] = length4;
845 g_assert (rank == pcount);
847 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
848 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
849 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
854 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
856 if (!mono_error_ok (&error)) {
857 mono_error_set_pending_exception (&error);
865 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
871 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
873 mono_class_init (field->parent);
875 vtable = mono_class_vtable_full (domain, field->parent, &error);
876 if (!is_ok (&error)) {
877 mono_error_set_pending_exception (&error);
880 if (!vtable->initialized) {
881 if (!mono_runtime_class_init_full (vtable, &error)) {
882 mono_error_set_pending_exception (&error);
887 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
889 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
890 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
892 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
898 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
901 MonoClass *handle_class;
904 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
905 if (!mono_error_ok (&error)) {
906 mono_error_set_pending_exception (&error);
909 mono_class_init (handle_class);
915 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
917 MonoMethodSignature *sig = mono_method_signature (method);
918 MonoGenericContext *generic_context;
920 if (sig->is_inflated) {
921 generic_context = mono_method_get_context (method);
923 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
924 g_assert (generic_container);
925 generic_context = &generic_container->context;
928 return mono_ldtoken_wrapper (image, token, generic_context);
932 mono_fconv_u8 (double v)
938 mono_rconv_u8 (float v)
943 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
945 mono_fconv_i8 (double v)
952 mono_fconv_u4 (double v)
954 /* MS.NET behaves like this for some reason */
956 if (isinf (v) || isnan (v))
964 /* Solaris doesn't have trunc */
966 extern long double aintl (long double);
969 /* FIXME: This means we will never throw overflow exceptions */
972 #endif /* HAVE_TRUNC */
975 mono_fconv_ovf_i8 (double v)
981 if (isnan(v) || trunc (v) != res) {
982 mono_set_pending_exception (mono_get_exception_overflow ());
989 mono_fconv_ovf_u8 (double v)
994 * The soft-float implementation of some ARM devices have a buggy guin64 to double
995 * conversion that it looses precision even when the integer if fully representable
998 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1000 * To work around this issue we test for value boundaries instead.
1002 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1003 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1004 mono_set_pending_exception (mono_get_exception_overflow ());
1010 if (isnan(v) || trunc (v) != res) {
1011 mono_set_pending_exception (mono_get_exception_overflow ());
1018 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1020 mono_rconv_i8 (float v)
1027 mono_rconv_ovf_i8 (float v)
1033 if (isnan(v) || trunc (v) != res) {
1034 mono_set_pending_exception (mono_get_exception_overflow ());
1041 mono_rconv_ovf_u8 (float v)
1046 if (isnan(v) || trunc (v) != res) {
1047 mono_set_pending_exception (mono_get_exception_overflow ());
1053 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1055 mono_lconv_to_r8 (gint64 a)
1061 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1063 mono_lconv_to_r4 (gint64 a)
1069 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1071 mono_conv_to_r8_un (guint32 a)
1077 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1079 mono_lconv_to_r8_un (guint64 a)
1085 #if defined(__native_client_codegen__) || defined(__native_client__)
1086 /* When we cross-compile to Native Client we can't directly embed calls */
1087 /* to the math library on the host. This will use the fmod on the target*/
1089 mono_fmod(double a, double b)
1096 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1099 MonoMethod *vmethod;
1101 MonoGenericContext *context = mono_method_get_context (method);
1103 mono_jit_stats.generic_virtual_invocations++;
1106 mono_set_pending_exception (mono_get_exception_null_reference ());
1109 vmethod = mono_object_get_virtual_method (obj, method);
1110 g_assert (!vmethod->klass->generic_container);
1111 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1112 g_assert (!context->method_inst || !context->method_inst->is_open);
1114 addr = mono_compile_method_checked (vmethod, &error);
1115 if (mono_error_set_pending_exception (&error))
1118 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1120 /* Since this is a virtual call, have to unbox vtypes */
1121 if (obj->vtable->klass->valuetype)
1122 *this_arg = mono_object_unbox (obj);
1130 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1133 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1134 mono_error_set_pending_exception (&error);
1139 mono_helper_ldstr (MonoImage *image, guint32 idx)
1142 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1143 mono_error_set_pending_exception (&error);
1148 mono_helper_ldstr_mscorlib (guint32 idx)
1151 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1152 mono_error_set_pending_exception (&error);
1157 mono_helper_newobj_mscorlib (guint32 idx)
1160 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1162 if (!mono_error_ok (&error)) {
1163 mono_error_set_pending_exception (&error);
1167 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1168 if (!mono_error_ok (&error))
1169 mono_error_set_pending_exception (&error);
1174 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1175 * in generated code. So instead we emit a call to this function and place a gdb
1184 mono_create_corlib_exception_0 (guint32 token)
1186 return mono_exception_from_token (mono_defaults.corlib, token);
1190 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1192 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1196 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1198 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1202 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1205 MonoJitTlsData *jit_tls = NULL;
1208 if (mini_get_debug_options ()->better_cast_details) {
1209 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1210 jit_tls->class_cast_from = NULL;
1216 oklass = obj->vtable->klass;
1217 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1219 if (mono_object_isinst_checked (obj, klass, &error))
1221 if (mono_error_set_pending_exception (&error))
1224 if (mini_get_debug_options ()->better_cast_details) {
1225 jit_tls->class_cast_from = oklass;
1226 jit_tls->class_cast_to = klass;
1229 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1230 "System", "InvalidCastException"));
1236 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1239 MonoJitTlsData *jit_tls = NULL;
1240 gpointer cached_vtable, obj_vtable;
1242 if (mini_get_debug_options ()->better_cast_details) {
1243 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1244 jit_tls->class_cast_from = NULL;
1250 cached_vtable = *cache;
1251 obj_vtable = obj->vtable;
1253 if (cached_vtable == obj_vtable)
1256 if (mono_object_isinst_checked (obj, klass, &error)) {
1257 *cache = obj_vtable;
1260 if (mono_error_set_pending_exception (&error))
1263 if (mini_get_debug_options ()->better_cast_details) {
1264 jit_tls->class_cast_from = obj->vtable->klass;
1265 jit_tls->class_cast_to = klass;
1268 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1269 "System", "InvalidCastException"));
1275 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1278 size_t cached_vtable, obj_vtable;
1283 cached_vtable = (size_t)*cache;
1284 obj_vtable = (size_t)obj->vtable;
1286 if ((cached_vtable & ~0x1) == obj_vtable) {
1287 return (cached_vtable & 0x1) ? NULL : obj;
1290 if (mono_object_isinst_checked (obj, klass, &error)) {
1291 *cache = (gpointer)obj_vtable;
1294 if (mono_error_set_pending_exception (&error))
1297 *cache = (gpointer)(obj_vtable | 0x1);
1303 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1306 MonoMarshalSpec **mspecs;
1307 MonoMethodPInvoke piinfo;
1310 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1311 memset (&piinfo, 0, sizeof (piinfo));
1313 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1315 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1316 mono_error_set_pending_exception (&error);
1317 return compiled_ptr;
1321 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1324 int vt_slot, iface_offset;
1326 mono_error_init (error);
1328 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1329 MonoObject *this_obj;
1331 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1332 this_obj = *(MonoObject**)mp;
1333 g_assert (this_obj);
1335 klass = this_obj->vtable->klass;
1338 if (mono_method_signature (cmethod)->pinvoke) {
1339 /* Object.GetType () */
1340 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1342 /* Lookup the virtual method */
1343 mono_class_setup_vtable (klass);
1344 g_assert (klass->vtable);
1345 vt_slot = mono_method_get_vtable_slot (cmethod);
1346 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1347 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1348 g_assert (iface_offset != -1);
1349 vt_slot += iface_offset;
1351 m = klass->vtable [vt_slot];
1352 if (cmethod->is_inflated)
1353 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1356 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1358 * Calling a non-vtype method with a vtype receiver, has to box.
1360 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1361 else if (klass->valuetype)
1363 * Calling a vtype method with a vtype receiver
1368 * Calling a non-vtype method
1370 *this_arg = *(gpointer*)mp;
1375 * mono_gsharedvt_constrained_call:
1377 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1378 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1381 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1387 gpointer new_args [16];
1389 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1390 if (!mono_error_ok (&error)) {
1391 mono_error_set_pending_exception (&error);
1397 if (args && deref_arg) {
1398 new_args [0] = *(gpointer*)args [0];
1401 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1402 /* Object.GetType () */
1404 args [0] = this_arg;
1408 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1409 if (!mono_error_ok (&error)) {
1410 mono_error_set_pending_exception (&error);
1418 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1420 if (klass->valuetype)
1421 mono_value_copy (dest, src, klass);
1423 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1427 ves_icall_runtime_class_init (MonoVTable *vtable)
1429 MONO_REQ_GC_UNSAFE_MODE;
1432 mono_runtime_class_init_full (vtable, &error);
1433 mono_error_set_pending_exception (&error);
1438 mono_generic_class_init (MonoVTable *vtable)
1441 mono_runtime_class_init_full (vtable, &error);
1442 mono_error_set_pending_exception (&error);
1446 ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
1449 mono_delegate_ctor (this_obj, target, addr, &error);
1450 mono_error_set_pending_exception (&error);
1454 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1459 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1460 if (!mono_error_ok (&error)) {
1461 mono_error_set_pending_exception (&error);
1468 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1473 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1474 if (!mono_error_ok (&error)) {
1475 mono_error_set_pending_exception (&error);
1482 * resolve_iface_call:
1484 * Return the executable code for the iface method IMT_METHOD called on THIS.
1485 * This function is called on a slowpath, so it doesn't need to be fast.
1486 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1490 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1494 gpointer *imt, *vtable_slot;
1495 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1496 gpointer addr, compiled_method, aot_addr;
1497 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1500 /* The caller will handle it */
1503 vt = this_obj->vtable;
1504 imt = (gpointer*)vt - MONO_IMT_SIZE;
1506 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1508 // FIXME: This can throw exceptions
1509 addr = compiled_method = mono_compile_method_checked (impl_method, &error);
1510 mono_error_assert_ok (&error);
1513 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1514 generic_virtual = imt_method;
1516 if (generic_virtual || variant_iface) {
1517 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1518 need_unbox_tramp = TRUE;
1520 if (impl_method->klass->valuetype)
1521 need_unbox_tramp = TRUE;
1524 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1526 if (generic_virtual || variant_iface) {
1527 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1529 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1538 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1540 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1544 is_generic_method_definition (MonoMethod *m)
1546 MonoGenericContext *context;
1549 if (!m->is_inflated)
1552 context = mono_method_get_context (m);
1553 if (!context->method_inst)
1555 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1563 * Return the executable code for calling vt->vtable [slot].
1564 * This function is called on a slowpath, so it doesn't need to be fast.
1565 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1569 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1572 MonoMethod *m, *generic_virtual = NULL;
1573 gpointer addr, compiled_method;
1574 gboolean need_unbox_tramp = FALSE;
1576 /* Same as in common_call_trampoline () */
1578 /* Avoid loading metadata or creating a generic vtable if possible */
1579 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1580 if (addr && !vt->klass->valuetype)
1581 return mono_create_ftnptr (mono_domain_get (), addr);
1583 m = mono_class_get_vtable_entry (vt->klass, slot);
1585 if (is_generic_method_definition (m)) {
1586 MonoGenericContext context = { NULL, NULL };
1587 MonoMethod *declaring;
1590 declaring = mono_method_get_declaring_generic_method (m);
1594 if (m->klass->generic_class)
1595 context.class_inst = m->klass->generic_class->context.class_inst;
1597 g_assert (!m->klass->generic_container);
1599 generic_virtual = imt_method;
1600 g_assert (generic_virtual);
1601 g_assert (generic_virtual->is_inflated);
1602 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1604 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1605 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1608 if (generic_virtual) {
1609 if (vt->klass->valuetype)
1610 need_unbox_tramp = TRUE;
1612 if (m->klass->valuetype)
1613 need_unbox_tramp = TRUE;
1616 // FIXME: This can throw exceptions
1617 addr = compiled_method = mono_compile_method_checked (m, &error);
1618 mono_error_assert_ok (&error);
1621 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1623 if (!gsharedvt && generic_virtual) {
1624 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1625 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1627 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1628 vt, vt->vtable + slot,
1629 generic_virtual, ftndesc);
1636 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1638 g_assert (this_obj);
1640 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1644 * mono_resolve_generic_virtual_call:
1646 * Resolve a generic virtual call.
1647 * This function is called on a slowpath, so it doesn't need to be fast.
1650 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1653 gpointer addr, compiled_method;
1654 gboolean need_unbox_tramp = FALSE;
1656 MonoGenericContext context = { NULL, NULL };
1657 MonoMethod *declaring;
1658 gpointer arg = NULL;
1660 m = mono_class_get_vtable_entry (vt->klass, slot);
1662 g_assert (is_generic_method_definition (m));
1665 declaring = mono_method_get_declaring_generic_method (m);
1669 if (m->klass->generic_class)
1670 context.class_inst = m->klass->generic_class->context.class_inst;
1672 g_assert (!m->klass->generic_container);
1674 g_assert (generic_virtual->is_inflated);
1675 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1677 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1678 g_assert (mono_error_ok (&error));
1680 if (vt->klass->valuetype)
1681 need_unbox_tramp = TRUE;
1683 // FIXME: This can throw exceptions
1684 addr = compiled_method = mono_compile_method_checked (m, &error);
1685 mono_error_assert_ok (&error);
1688 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1691 * This wastes memory but the memory usage is bounded since
1692 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1693 * this vtable slot so we are not called any more for this instantiation.
1695 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1697 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1698 vt, vt->vtable + slot,
1699 generic_virtual, ftndesc);
1704 * mono_resolve_generic_virtual_call:
1706 * Resolve a generic virtual/variant iface call on interfaces.
1707 * This function is called on a slowpath, so it doesn't need to be fast.
1710 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1713 MonoMethod *m, *variant_iface;
1714 gpointer addr, aot_addr, compiled_method;
1715 gboolean need_unbox_tramp = FALSE;
1716 gboolean need_rgctx_tramp;
1717 gpointer arg = NULL;
1720 imt = (gpointer*)vt - MONO_IMT_SIZE;
1722 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1724 if (vt->klass->valuetype)
1725 need_unbox_tramp = TRUE;
1727 // FIXME: This can throw exceptions
1728 addr = compiled_method = mono_compile_method_checked (m, &error);
1729 mono_error_assert_ok (&error);
1732 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1735 * This wastes memory but the memory usage is bounded since
1736 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1737 * this vtable slot so we are not called any more for this instantiation.
1739 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1741 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1743 variant_iface ? variant_iface : generic_virtual, ftndesc);
1748 * mono_init_vtable_slot:
1750 * Initialize slot SLOT of VTABLE.
1751 * Return the contents of the vtable slot.
1754 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1756 gpointer arg = NULL;
1760 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1761 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1764 mono_memory_barrier ();
1766 vtable->vtable [slot] = ftnptr;
1772 * mono_llvmonly_init_delegate:
1774 * Initialize a MonoDelegate object.
1775 * Similar to mono_delegate_ctor ().
1778 mono_llvmonly_init_delegate (MonoDelegate *del)
1781 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1784 * We store a MonoFtnDesc in del->method_code.
1785 * It would be better to store an ftndesc in del->method_ptr too,
1786 * but we don't have a a structure which could own its memory.
1788 if (G_UNLIKELY (!ftndesc)) {
1789 gpointer addr = mono_compile_method_checked (del->method, &error);
1790 if (mono_error_set_pending_exception (&error))
1793 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1794 addr = mono_aot_get_unbox_trampoline (del->method);
1796 gpointer arg = mini_get_delegate_arg (del->method, addr);
1798 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1799 mono_memory_barrier ();
1800 *del->method_code = (gpointer)ftndesc;
1802 del->method_ptr = ftndesc->addr;
1803 del->extra_arg = ftndesc->arg;
1807 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1813 method = mono_object_get_virtual_method (target, method);
1815 del->method = method;
1816 del->method_ptr = mono_compile_method_checked (method, &error);
1817 if (mono_error_set_pending_exception (&error))
1819 if (method->klass->valuetype)
1820 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1821 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1825 mono_get_assembly_object (MonoImage *image)
1829 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1831 mono_error_set_pending_exception (&error);
1836 mono_get_method_object (MonoMethod *method)
1839 MonoObject * result;
1840 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1841 mono_error_set_pending_exception (&error);
1846 mono_ckfinite (double d)
1848 if (isinf (d) || isnan (d))
1849 mono_set_pending_exception (mono_get_exception_arithmetic ());
1854 * mono_interruption_checkpoint_from_trampoline:
1856 * Check whenever the thread has a pending exception, and throw it
1858 * Architectures should move away from calling this function and
1859 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1860 * rewrind to the parent frame, and throw the exception normally.
1863 mono_interruption_checkpoint_from_trampoline (void)
1867 ex = mono_thread_force_interruption_checkpoint_noraise ();
1869 mono_raise_exception (ex);