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 mono_helper_ldstr (MonoImage *image, guint32 idx)
1132 return mono_ldstr (mono_domain_get (), image, idx);
1136 mono_helper_ldstr_mscorlib (guint32 idx)
1138 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1142 mono_helper_newobj_mscorlib (guint32 idx)
1145 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1147 if (!mono_error_ok (&error)) {
1148 mono_error_set_pending_exception (&error);
1152 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1153 if (!mono_error_ok (&error))
1154 mono_error_set_pending_exception (&error);
1159 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1160 * in generated code. So instead we emit a call to this function and place a gdb
1169 mono_create_corlib_exception_0 (guint32 token)
1171 return mono_exception_from_token (mono_defaults.corlib, token);
1175 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1177 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1181 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1183 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1187 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1190 MonoJitTlsData *jit_tls = NULL;
1193 if (mini_get_debug_options ()->better_cast_details) {
1194 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1195 jit_tls->class_cast_from = NULL;
1201 oklass = obj->vtable->klass;
1202 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1204 if (mono_object_isinst_checked (obj, klass, &error))
1206 if (mono_error_set_pending_exception (&error))
1209 if (mini_get_debug_options ()->better_cast_details) {
1210 jit_tls->class_cast_from = oklass;
1211 jit_tls->class_cast_to = klass;
1214 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1215 "System", "InvalidCastException"));
1221 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1224 MonoJitTlsData *jit_tls = NULL;
1225 gpointer cached_vtable, obj_vtable;
1227 if (mini_get_debug_options ()->better_cast_details) {
1228 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1229 jit_tls->class_cast_from = NULL;
1235 cached_vtable = *cache;
1236 obj_vtable = obj->vtable;
1238 if (cached_vtable == obj_vtable)
1241 if (mono_object_isinst_checked (obj, klass, &error)) {
1242 *cache = obj_vtable;
1245 if (mono_error_set_pending_exception (&error))
1248 if (mini_get_debug_options ()->better_cast_details) {
1249 jit_tls->class_cast_from = obj->vtable->klass;
1250 jit_tls->class_cast_to = klass;
1253 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1254 "System", "InvalidCastException"));
1260 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1263 size_t cached_vtable, obj_vtable;
1268 cached_vtable = (size_t)*cache;
1269 obj_vtable = (size_t)obj->vtable;
1271 if ((cached_vtable & ~0x1) == obj_vtable) {
1272 return (cached_vtable & 0x1) ? NULL : obj;
1275 if (mono_object_isinst_checked (obj, klass, &error)) {
1276 *cache = (gpointer)obj_vtable;
1279 if (mono_error_set_pending_exception (&error))
1282 *cache = (gpointer)(obj_vtable | 0x1);
1288 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1291 MonoMarshalSpec **mspecs;
1292 MonoMethodPInvoke piinfo;
1295 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1296 memset (&piinfo, 0, sizeof (piinfo));
1298 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1300 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1301 mono_error_set_pending_exception (&error);
1302 return compiled_ptr;
1306 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1309 int vt_slot, iface_offset;
1311 mono_error_init (error);
1313 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1314 MonoObject *this_obj;
1316 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1317 this_obj = *(MonoObject**)mp;
1318 g_assert (this_obj);
1320 klass = this_obj->vtable->klass;
1323 if (mono_method_signature (cmethod)->pinvoke) {
1324 /* Object.GetType () */
1325 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1327 /* Lookup the virtual method */
1328 mono_class_setup_vtable (klass);
1329 g_assert (klass->vtable);
1330 vt_slot = mono_method_get_vtable_slot (cmethod);
1331 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1332 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1333 g_assert (iface_offset != -1);
1334 vt_slot += iface_offset;
1336 m = klass->vtable [vt_slot];
1337 if (cmethod->is_inflated)
1338 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1341 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1343 * Calling a non-vtype method with a vtype receiver, has to box.
1345 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1346 else if (klass->valuetype)
1348 * Calling a vtype method with a vtype receiver
1353 * Calling a non-vtype method
1355 *this_arg = *(gpointer*)mp;
1360 * mono_gsharedvt_constrained_call:
1362 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1363 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1366 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1372 gpointer new_args [16];
1374 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1375 if (!mono_error_ok (&error)) {
1376 mono_error_set_pending_exception (&error);
1382 if (args && deref_arg) {
1383 new_args [0] = *(gpointer*)args [0];
1386 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1387 /* Object.GetType () */
1389 args [0] = this_arg;
1393 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1394 if (!mono_error_ok (&error)) {
1395 mono_error_set_pending_exception (&error);
1403 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1405 if (klass->valuetype)
1406 mono_value_copy (dest, src, klass);
1408 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1412 ves_icall_runtime_class_init (MonoVTable *vtable)
1414 MONO_REQ_GC_UNSAFE_MODE;
1417 mono_runtime_class_init_full (vtable, &error);
1418 mono_error_set_pending_exception (&error);
1423 mono_generic_class_init (MonoVTable *vtable)
1426 mono_runtime_class_init_full (vtable, &error);
1427 mono_error_set_pending_exception (&error);
1431 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1436 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1437 if (!mono_error_ok (&error)) {
1438 mono_error_set_pending_exception (&error);
1445 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1450 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1451 if (!mono_error_ok (&error)) {
1452 mono_error_set_pending_exception (&error);
1459 * resolve_iface_call:
1461 * Return the executable code for the iface method IMT_METHOD called on THIS.
1462 * This function is called on a slowpath, so it doesn't need to be fast.
1463 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1467 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1471 gpointer *imt, *vtable_slot;
1472 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1473 gpointer addr, compiled_method, aot_addr;
1474 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1477 /* The caller will handle it */
1480 vt = this_obj->vtable;
1481 imt = (gpointer*)vt - MONO_IMT_SIZE;
1483 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1485 // FIXME: This can throw exceptions
1486 addr = compiled_method = mono_compile_method_checked (impl_method, &error);
1487 mono_error_assert_ok (&error);
1490 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1491 generic_virtual = imt_method;
1493 if (generic_virtual || variant_iface) {
1494 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1495 need_unbox_tramp = TRUE;
1497 if (impl_method->klass->valuetype)
1498 need_unbox_tramp = TRUE;
1501 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1503 if (generic_virtual || variant_iface) {
1504 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1506 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1515 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1517 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1521 is_generic_method_definition (MonoMethod *m)
1523 MonoGenericContext *context;
1526 if (!m->is_inflated)
1529 context = mono_method_get_context (m);
1530 if (!context->method_inst)
1532 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1540 * Return the executable code for calling vt->vtable [slot].
1541 * This function is called on a slowpath, so it doesn't need to be fast.
1542 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1546 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1549 MonoMethod *m, *generic_virtual = NULL;
1550 gpointer addr, compiled_method;
1551 gboolean need_unbox_tramp = FALSE;
1553 /* Same as in common_call_trampoline () */
1555 /* Avoid loading metadata or creating a generic vtable if possible */
1556 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1557 if (addr && !vt->klass->valuetype)
1558 return mono_create_ftnptr (mono_domain_get (), addr);
1560 m = mono_class_get_vtable_entry (vt->klass, slot);
1562 if (is_generic_method_definition (m)) {
1563 MonoGenericContext context = { NULL, NULL };
1564 MonoMethod *declaring;
1567 declaring = mono_method_get_declaring_generic_method (m);
1571 if (m->klass->generic_class)
1572 context.class_inst = m->klass->generic_class->context.class_inst;
1574 g_assert (!m->klass->generic_container);
1576 generic_virtual = imt_method;
1577 g_assert (generic_virtual);
1578 g_assert (generic_virtual->is_inflated);
1579 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1581 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1582 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
1585 if (generic_virtual) {
1586 if (vt->klass->valuetype)
1587 need_unbox_tramp = TRUE;
1589 if (m->klass->valuetype)
1590 need_unbox_tramp = TRUE;
1593 // FIXME: This can throw exceptions
1594 addr = compiled_method = mono_compile_method_checked (m, &error);
1595 mono_error_assert_ok (&error);
1598 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1600 if (!gsharedvt && generic_virtual) {
1601 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1602 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1604 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1605 vt, vt->vtable + slot,
1606 generic_virtual, ftndesc);
1613 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1615 g_assert (this_obj);
1617 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1621 * mono_resolve_generic_virtual_call:
1623 * Resolve a generic virtual call.
1624 * This function is called on a slowpath, so it doesn't need to be fast.
1627 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1630 gpointer addr, compiled_method;
1631 gboolean need_unbox_tramp = FALSE;
1633 MonoGenericContext context = { NULL, NULL };
1634 MonoMethod *declaring;
1635 gpointer arg = NULL;
1637 m = mono_class_get_vtable_entry (vt->klass, slot);
1639 g_assert (is_generic_method_definition (m));
1642 declaring = mono_method_get_declaring_generic_method (m);
1646 if (m->klass->generic_class)
1647 context.class_inst = m->klass->generic_class->context.class_inst;
1649 g_assert (!m->klass->generic_container);
1651 g_assert (generic_virtual->is_inflated);
1652 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1654 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1655 g_assert (mono_error_ok (&error));
1657 if (vt->klass->valuetype)
1658 need_unbox_tramp = TRUE;
1660 // FIXME: This can throw exceptions
1661 addr = compiled_method = mono_compile_method_checked (m, &error);
1662 mono_error_assert_ok (&error);
1665 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1668 * This wastes memory but the memory usage is bounded since
1669 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1670 * this vtable slot so we are not called any more for this instantiation.
1672 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1674 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1675 vt, vt->vtable + slot,
1676 generic_virtual, ftndesc);
1681 * mono_resolve_generic_virtual_call:
1683 * Resolve a generic virtual/variant iface call on interfaces.
1684 * This function is called on a slowpath, so it doesn't need to be fast.
1687 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1690 MonoMethod *m, *variant_iface;
1691 gpointer addr, aot_addr, compiled_method;
1692 gboolean need_unbox_tramp = FALSE;
1693 gboolean need_rgctx_tramp;
1694 gpointer arg = NULL;
1697 imt = (gpointer*)vt - MONO_IMT_SIZE;
1699 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1701 if (vt->klass->valuetype)
1702 need_unbox_tramp = TRUE;
1704 // FIXME: This can throw exceptions
1705 addr = compiled_method = mono_compile_method_checked (m, &error);
1706 mono_error_assert_ok (&error);
1709 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1712 * This wastes memory but the memory usage is bounded since
1713 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1714 * this vtable slot so we are not called any more for this instantiation.
1716 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1718 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1720 variant_iface ? variant_iface : generic_virtual, ftndesc);
1725 * mono_init_vtable_slot:
1727 * Initialize slot SLOT of VTABLE.
1728 * Return the contents of the vtable slot.
1731 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1733 gpointer arg = NULL;
1737 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1738 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1741 mono_memory_barrier ();
1743 vtable->vtable [slot] = ftnptr;
1749 * mono_llvmonly_init_delegate:
1751 * Initialize a MonoDelegate object.
1752 * Similar to mono_delegate_ctor ().
1755 mono_llvmonly_init_delegate (MonoDelegate *del)
1758 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1761 * We store a MonoFtnDesc in del->method_code.
1762 * It would be better to store an ftndesc in del->method_ptr too,
1763 * but we don't have a a structure which could own its memory.
1765 if (G_UNLIKELY (!ftndesc)) {
1766 gpointer addr = mono_compile_method_checked (del->method, &error);
1767 if (mono_error_set_pending_exception (&error))
1770 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1771 addr = mono_aot_get_unbox_trampoline (del->method);
1773 gpointer arg = mini_get_delegate_arg (del->method, addr);
1775 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1776 mono_memory_barrier ();
1777 *del->method_code = (gpointer)ftndesc;
1779 del->method_ptr = ftndesc->addr;
1780 del->extra_arg = ftndesc->arg;
1784 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1790 method = mono_object_get_virtual_method (target, method);
1792 del->method = method;
1793 del->method_ptr = mono_compile_method_checked (method, &error);
1794 if (mono_error_set_pending_exception (&error))
1796 if (method->klass->valuetype)
1797 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1798 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1802 mono_get_assembly_object (MonoImage *image)
1806 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1808 mono_error_set_pending_exception (&error);
1813 mono_get_method_object (MonoMethod *method)
1816 MonoObject * result;
1817 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1818 mono_error_set_pending_exception (&error);
1823 mono_ckfinite (double d)
1825 if (isinf (d) || isnan (d))
1826 mono_set_pending_exception (mono_get_exception_arithmetic ());
1831 * mono_interruption_checkpoint_from_trampoline:
1833 * Check whenever the thread has a pending exception, and throw it
1835 * Architectures should move away from calling this function and
1836 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1837 * rewrind to the parent frame, and throw the exception normally.
1840 mono_interruption_checkpoint_from_trampoline (void)
1844 ex = mono_thread_force_interruption_checkpoint_noraise ();
1846 mono_raise_exception (ex);