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, &error);
1580 mono_error_raise_exception (&error); // FIXME: Don't raise here
1581 if (addr && !vt->klass->valuetype)
1582 return mono_create_ftnptr (mono_domain_get (), addr);
1584 m = mono_class_get_vtable_entry (vt->klass, slot);
1586 if (is_generic_method_definition (m)) {
1587 MonoGenericContext context = { NULL, NULL };
1588 MonoMethod *declaring;
1591 declaring = mono_method_get_declaring_generic_method (m);
1595 if (m->klass->generic_class)
1596 context.class_inst = m->klass->generic_class->context.class_inst;
1598 g_assert (!m->klass->generic_container);
1600 generic_virtual = imt_method;
1601 g_assert (generic_virtual);
1602 g_assert (generic_virtual->is_inflated);
1603 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1605 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1606 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1609 if (generic_virtual) {
1610 if (vt->klass->valuetype)
1611 need_unbox_tramp = TRUE;
1613 if (m->klass->valuetype)
1614 need_unbox_tramp = TRUE;
1617 // FIXME: This can throw exceptions
1618 addr = compiled_method = mono_compile_method_checked (m, &error);
1619 mono_error_assert_ok (&error);
1622 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1624 if (!gsharedvt && generic_virtual) {
1625 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1626 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1628 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1629 vt, vt->vtable + slot,
1630 generic_virtual, ftndesc);
1637 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1639 g_assert (this_obj);
1641 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1645 * mono_resolve_generic_virtual_call:
1647 * Resolve a generic virtual call.
1648 * This function is called on a slowpath, so it doesn't need to be fast.
1651 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1654 gpointer addr, compiled_method;
1655 gboolean need_unbox_tramp = FALSE;
1657 MonoGenericContext context = { NULL, NULL };
1658 MonoMethod *declaring;
1659 gpointer arg = NULL;
1661 m = mono_class_get_vtable_entry (vt->klass, slot);
1663 g_assert (is_generic_method_definition (m));
1666 declaring = mono_method_get_declaring_generic_method (m);
1670 if (m->klass->generic_class)
1671 context.class_inst = m->klass->generic_class->context.class_inst;
1673 g_assert (!m->klass->generic_container);
1675 g_assert (generic_virtual->is_inflated);
1676 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1678 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1679 g_assert (mono_error_ok (&error));
1681 if (vt->klass->valuetype)
1682 need_unbox_tramp = TRUE;
1684 // FIXME: This can throw exceptions
1685 addr = compiled_method = mono_compile_method_checked (m, &error);
1686 mono_error_assert_ok (&error);
1689 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1692 * This wastes memory but the memory usage is bounded since
1693 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1694 * this vtable slot so we are not called any more for this instantiation.
1696 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1698 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1699 vt, vt->vtable + slot,
1700 generic_virtual, ftndesc);
1705 * mono_resolve_generic_virtual_call:
1707 * Resolve a generic virtual/variant iface call on interfaces.
1708 * This function is called on a slowpath, so it doesn't need to be fast.
1711 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1714 MonoMethod *m, *variant_iface;
1715 gpointer addr, aot_addr, compiled_method;
1716 gboolean need_unbox_tramp = FALSE;
1717 gboolean need_rgctx_tramp;
1718 gpointer arg = NULL;
1721 imt = (gpointer*)vt - MONO_IMT_SIZE;
1723 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1725 if (vt->klass->valuetype)
1726 need_unbox_tramp = TRUE;
1728 // FIXME: This can throw exceptions
1729 addr = compiled_method = mono_compile_method_checked (m, &error);
1730 mono_error_assert_ok (&error);
1733 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1736 * This wastes memory but the memory usage is bounded since
1737 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1738 * this vtable slot so we are not called any more for this instantiation.
1740 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1742 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1744 variant_iface ? variant_iface : generic_virtual, ftndesc);
1749 * mono_init_vtable_slot:
1751 * Initialize slot SLOT of VTABLE.
1752 * Return the contents of the vtable slot.
1755 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1757 gpointer arg = NULL;
1761 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1762 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1765 mono_memory_barrier ();
1767 vtable->vtable [slot] = ftnptr;
1773 * mono_llvmonly_init_delegate:
1775 * Initialize a MonoDelegate object.
1776 * Similar to mono_delegate_ctor ().
1779 mono_llvmonly_init_delegate (MonoDelegate *del)
1782 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1785 * We store a MonoFtnDesc in del->method_code.
1786 * It would be better to store an ftndesc in del->method_ptr too,
1787 * but we don't have a a structure which could own its memory.
1789 if (G_UNLIKELY (!ftndesc)) {
1790 gpointer addr = mono_compile_method_checked (del->method, &error);
1791 if (mono_error_set_pending_exception (&error))
1794 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1795 addr = mono_aot_get_unbox_trampoline (del->method);
1797 gpointer arg = mini_get_delegate_arg (del->method, addr);
1799 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1800 mono_memory_barrier ();
1801 *del->method_code = (gpointer)ftndesc;
1803 del->method_ptr = ftndesc->addr;
1804 del->extra_arg = ftndesc->arg;
1808 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1814 method = mono_object_get_virtual_method (target, method);
1816 del->method = method;
1817 del->method_ptr = mono_compile_method_checked (method, &error);
1818 if (mono_error_set_pending_exception (&error))
1820 if (method->klass->valuetype)
1821 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1822 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1826 mono_get_assembly_object (MonoImage *image)
1830 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1832 mono_error_set_pending_exception (&error);
1837 mono_get_method_object (MonoMethod *method)
1840 MonoObject * result;
1841 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1842 mono_error_set_pending_exception (&error);
1847 mono_ckfinite (double d)
1849 if (isinf (d) || isnan (d))
1850 mono_set_pending_exception (mono_get_exception_arithmetic ());
1855 * mono_interruption_checkpoint_from_trampoline:
1857 * Check whenever the thread has a pending exception, and throw it
1859 * Architectures should move away from calling this function and
1860 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1861 * rewrind to the parent frame, and throw the exception normally.
1864 mono_interruption_checkpoint_from_trampoline (void)
1868 ex = mono_thread_force_interruption_checkpoint_noraise ();
1870 mono_raise_exception (ex);
1874 mono_throw_method_access (MonoMethod *callee, MonoMethod *caller)
1876 char *callee_name = mono_method_full_name (callee, 1);
1877 char *caller_name = mono_method_full_name (caller, 1);
1880 mono_error_init (&error);
1881 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", callee_name, caller_name);
1882 mono_error_set_pending_exception (&error);
1883 g_free (callee_name);
1884 g_free (caller_name);