3 * internal calls used by the JIT
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2002 Ximian, Inc.
10 * Copyright 2003-2011 Novell Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include "jit-icalls.h"
22 #include <mono/utils/mono-error-internals.h>
23 #include <mono/metadata/exception-internals.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/reflection-internals.h>
28 #include "mini-llvm-cpp.h"
32 mono_ldftn (MonoMethod *method)
38 // FIXME: No error handling
40 addr = mono_compile_method_checked (method, &error);
41 mono_error_assert_ok (&error);
44 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
45 /* The caller doesn't pass it */
46 g_assert_not_reached ();
48 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
52 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
53 if (!mono_error_ok (&error)) {
54 mono_error_set_pending_exception (&error);
57 return mono_create_ftnptr (mono_domain_get (), addr);
61 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
67 mono_set_pending_exception (mono_get_exception_null_reference ());
71 res = mono_object_get_virtual_method (obj, method);
73 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
74 MonoGenericContext context = { NULL, NULL };
76 if (mono_class_is_ginst (res->klass))
77 context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
78 else if (mono_class_is_gtd (res->klass))
79 context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
80 context.method_inst = mono_method_get_context (method)->method_inst;
82 res = mono_class_inflate_generic_method_checked (res, &context, &error);
83 if (!mono_error_ok (&error)) {
84 mono_error_set_pending_exception (&error);
89 /* An rgctx wrapper is added by the trampolines no need to do it here */
91 return mono_ldftn (res);
95 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
97 return ldvirtfn_internal (obj, method, FALSE);
101 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
103 return ldvirtfn_internal (obj, method, TRUE);
107 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
111 mono_set_pending_exception (mono_get_exception_null_reference ());
114 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
115 if (mono_error_set_pending_exception (&error))
117 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
122 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
125 mono_llmult (gint64 a, gint64 b)
131 mono_llmult_ovf_un (guint64 a, guint64 b)
134 guint32 ah = a >> 32;
136 guint32 bh = b >> 32;
139 // fixme: this is incredible slow
142 goto raise_exception;
144 res = (guint64)al * (guint64)bl;
146 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
149 goto raise_exception;
151 res += ((guint64)t1) << 32;
156 mono_set_pending_exception (mono_get_exception_overflow ());
161 mono_llmult_ovf (gint64 a, gint64 b)
168 Use Karatsuba algorithm where:
169 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
170 where Ah is the "high half" (most significant 32 bits) of a and
171 where Al is the "low half" (least significant 32 bits) of a and
172 where Bh is the "high half" of b and Bl is the "low half" and
173 where R is the Radix or "size of the half" (in our case 32 bits)
175 Note, for the product of two 64 bit numbers to fit into a 64
176 result, ah and/or bh must be 0. This will save us from doing
177 the AhBh term at all.
179 Also note that we refactor so that we don't overflow 64 bits with
180 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
186 /* need to work with absoulte values, so find out what the
187 resulting sign will be and convert any negative numbers
188 from two's complement
192 if (((guint32)ah == 0x80000000) && (al == 0)) {
193 /* This has no two's complement */
199 goto raise_exception;
202 /* flip the bits and add 1 */
213 if (((guint32)bh == 0x80000000) && (bl == 0)) {
214 /* This has no two's complement */
220 goto raise_exception;
223 /* flip the bits and add 1 */
233 /* we overflow for sure if both upper halves are greater
234 than zero because we would need to shift their
235 product 64 bits to the left and that will not fit
236 in a 64 bit result */
238 goto raise_exception;
239 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
240 goto raise_exception;
242 /* do the AlBl term first */
243 t1 = (gint64)al * (gint64)bl;
247 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
248 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
249 /* check for overflow */
251 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
252 goto raise_exception;
257 goto raise_exception;
265 mono_set_pending_exception (mono_get_exception_overflow ());
270 mono_lldiv (gint64 a, gint64 b)
272 #ifdef MONO_ARCH_NEED_DIV_CHECK
274 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
277 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
278 mono_set_pending_exception (mono_get_exception_arithmetic ());
286 mono_llrem (gint64 a, gint64 b)
288 #ifdef MONO_ARCH_NEED_DIV_CHECK
290 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
293 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
294 mono_set_pending_exception (mono_get_exception_arithmetic ());
302 mono_lldiv_un (guint64 a, guint64 b)
304 #ifdef MONO_ARCH_NEED_DIV_CHECK
306 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
314 mono_llrem_un (guint64 a, guint64 b)
316 #ifdef MONO_ARCH_NEED_DIV_CHECK
318 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
327 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
330 mono_lshl (guint64 a, gint32 shamt)
334 res = a << (shamt & 0x7f);
336 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
342 mono_lshr_un (guint64 a, gint32 shamt)
346 res = a >> (shamt & 0x7f);
348 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
354 mono_lshr (gint64 a, gint32 shamt)
358 res = a >> (shamt & 0x7f);
360 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
367 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
370 mono_idiv (gint32 a, gint32 b)
372 #ifdef MONO_ARCH_NEED_DIV_CHECK
374 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
377 else if (b == -1 && a == (0x80000000)) {
378 mono_set_pending_exception (mono_get_exception_overflow ());
386 mono_idiv_un (guint32 a, guint32 b)
388 #ifdef MONO_ARCH_NEED_DIV_CHECK
390 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
398 mono_irem (gint32 a, gint32 b)
400 #ifdef MONO_ARCH_NEED_DIV_CHECK
402 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
405 else if (b == -1 && a == (0x80000000)) {
406 mono_set_pending_exception (mono_get_exception_overflow ());
414 mono_irem_un (guint32 a, guint32 b)
416 #ifdef MONO_ARCH_NEED_DIV_CHECK
418 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
427 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
430 mono_imul (gint32 a, gint32 b)
436 mono_imul_ovf (gint32 a, gint32 b)
440 res = (gint64)a * (gint64)b;
442 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
443 mono_set_pending_exception (mono_get_exception_overflow ());
451 mono_imul_ovf_un (guint32 a, guint32 b)
455 res = (guint64)a * (guint64)b;
458 mono_set_pending_exception (mono_get_exception_overflow ());
466 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
468 mono_fdiv (double a, double b)
474 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
477 mono_fsub (double a, double b)
483 mono_fadd (double a, double b)
489 mono_fmul (double a, double b)
501 mono_fconv_r4 (double a)
507 mono_conv_to_r8 (int a)
513 mono_conv_to_r4 (int a)
515 return (double)(float)a;
519 mono_fconv_i1 (double a)
525 mono_fconv_i2 (double a)
531 mono_fconv_i4 (double a)
537 mono_fconv_u1 (double a)
543 mono_fconv_u2 (double a)
549 mono_fcmp_eq (double a, double b)
555 mono_fcmp_ge (double a, double b)
561 mono_fcmp_gt (double a, double b)
567 mono_fcmp_le (double a, double b)
573 mono_fcmp_lt (double a, double b)
579 mono_fcmp_ne_un (double a, double b)
581 return isunordered (a, b) || a != b;
585 mono_fcmp_ge_un (double a, double b)
587 return isunordered (a, b) || a >= b;
591 mono_fcmp_gt_un (double a, double b)
593 return isunordered (a, b) || a > b;
597 mono_fcmp_le_un (double a, double b)
599 return isunordered (a, b) || a <= b;
603 mono_fcmp_lt_un (double a, double b)
605 return isunordered (a, b) || a < b;
609 mono_fceq (double a, double b)
615 mono_fcgt (double a, double b)
621 mono_fcgt_un (double a, double b)
623 return isunordered (a, b) || a > b;
627 mono_fclt (double a, double b)
633 mono_fclt_un (double a, double b)
635 return isunordered (a, b) || a < b;
639 mono_isfinite (double a)
644 g_assert_not_reached ();
650 mono_fload_r4 (float *ptr)
656 mono_fstore_r4 (double val, float *ptr)
661 /* returns the integer bitpattern that is passed in the regs or stack */
663 mono_fload_r4_arg (double val)
665 float v = (float)val;
666 return *(guint32*)&v;
672 mono_array_new_va (MonoMethod *cm, ...)
676 MonoDomain *domain = mono_domain_get ();
679 intptr_t *lower_bounds;
684 pcount = mono_method_signature (cm)->param_count;
685 rank = cm->klass->rank;
689 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
690 for (i = 0; i < pcount; ++i)
691 lengths [i] = d = va_arg(ap, int);
693 if (rank == pcount) {
694 /* Only lengths provided. */
695 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
696 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
697 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
702 g_assert (pcount == (rank * 2));
703 /* lower bounds are first. */
704 lower_bounds = (intptr_t*)lengths;
709 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
711 if (!mono_error_ok (&error)) {
712 mono_error_set_pending_exception (&error);
719 /* Specialized version of mono_array_new_va () which avoids varargs */
721 mono_array_new_1 (MonoMethod *cm, guint32 length)
725 MonoDomain *domain = mono_domain_get ();
726 uintptr_t lengths [1];
727 intptr_t *lower_bounds;
731 pcount = mono_method_signature (cm)->param_count;
732 rank = cm->klass->rank;
734 lengths [0] = length;
736 g_assert (rank == pcount);
738 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
739 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
740 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
745 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
747 if (!mono_error_ok (&error)) {
748 mono_error_set_pending_exception (&error);
756 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
760 MonoDomain *domain = mono_domain_get ();
761 uintptr_t lengths [2];
762 intptr_t *lower_bounds;
766 pcount = mono_method_signature (cm)->param_count;
767 rank = cm->klass->rank;
769 lengths [0] = length1;
770 lengths [1] = length2;
772 g_assert (rank == pcount);
774 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
775 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
776 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
781 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
783 if (!mono_error_ok (&error)) {
784 mono_error_set_pending_exception (&error);
792 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
796 MonoDomain *domain = mono_domain_get ();
797 uintptr_t lengths [3];
798 intptr_t *lower_bounds;
802 pcount = mono_method_signature (cm)->param_count;
803 rank = cm->klass->rank;
805 lengths [0] = length1;
806 lengths [1] = length2;
807 lengths [2] = length3;
809 g_assert (rank == pcount);
811 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
812 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
813 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
818 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
820 if (!mono_error_ok (&error)) {
821 mono_error_set_pending_exception (&error);
829 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
833 MonoDomain *domain = mono_domain_get ();
834 uintptr_t lengths [4];
835 intptr_t *lower_bounds;
839 pcount = mono_method_signature (cm)->param_count;
840 rank = cm->klass->rank;
842 lengths [0] = length1;
843 lengths [1] = length2;
844 lengths [2] = length3;
845 lengths [3] = length4;
847 g_assert (rank == pcount);
849 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
850 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
851 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
856 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
858 if (!mono_error_ok (&error)) {
859 mono_error_set_pending_exception (&error);
867 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
873 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
875 mono_class_init (field->parent);
877 vtable = mono_class_vtable_full (domain, field->parent, &error);
878 if (!is_ok (&error)) {
879 mono_error_set_pending_exception (&error);
882 if (!vtable->initialized) {
883 if (!mono_runtime_class_init_full (vtable, &error)) {
884 mono_error_set_pending_exception (&error);
889 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
891 if (field->offset == -1) {
893 g_assert (domain->special_static_fields);
894 mono_domain_lock (domain);
895 addr = g_hash_table_lookup (domain->special_static_fields, field);
896 mono_domain_unlock (domain);
897 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
899 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
905 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
908 MonoClass *handle_class;
911 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
912 if (!mono_error_ok (&error)) {
913 mono_error_set_pending_exception (&error);
916 mono_class_init (handle_class);
922 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
924 MonoMethodSignature *sig = mono_method_signature (method);
925 MonoGenericContext *generic_context;
927 if (sig->is_inflated) {
928 generic_context = mono_method_get_context (method);
930 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
931 g_assert (generic_container);
932 generic_context = &generic_container->context;
935 return mono_ldtoken_wrapper (image, token, generic_context);
939 mono_fconv_u8 (double v)
945 mono_rconv_u8 (float v)
950 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
952 mono_fconv_i8 (double v)
959 mono_fconv_u4 (double v)
961 /* MS.NET behaves like this for some reason */
963 if (isinf (v) || isnan (v))
971 /* Solaris doesn't have trunc */
973 extern long double aintl (long double);
976 /* FIXME: This means we will never throw overflow exceptions */
979 #endif /* HAVE_TRUNC */
982 mono_fconv_ovf_i8 (double v)
988 if (isnan(v) || trunc (v) != res) {
989 mono_set_pending_exception (mono_get_exception_overflow ());
996 mono_fconv_ovf_u8 (double v)
1001 * The soft-float implementation of some ARM devices have a buggy guin64 to double
1002 * conversion that it looses precision even when the integer if fully representable
1005 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1007 * To work around this issue we test for value boundaries instead.
1009 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1010 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1011 mono_set_pending_exception (mono_get_exception_overflow ());
1017 if (isnan(v) || trunc (v) != res) {
1018 mono_set_pending_exception (mono_get_exception_overflow ());
1025 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1027 mono_rconv_i8 (float v)
1034 mono_rconv_ovf_i8 (float v)
1040 if (isnan(v) || trunc (v) != res) {
1041 mono_set_pending_exception (mono_get_exception_overflow ());
1048 mono_rconv_ovf_u8 (float v)
1053 if (isnan(v) || trunc (v) != res) {
1054 mono_set_pending_exception (mono_get_exception_overflow ());
1060 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1062 mono_lconv_to_r8 (gint64 a)
1068 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1070 mono_lconv_to_r4 (gint64 a)
1076 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1078 mono_conv_to_r8_un (guint32 a)
1084 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1086 mono_lconv_to_r8_un (guint64 a)
1093 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1096 MonoMethod *vmethod;
1098 MonoGenericContext *context = mono_method_get_context (method);
1100 mono_jit_stats.generic_virtual_invocations++;
1103 mono_set_pending_exception (mono_get_exception_null_reference ());
1106 vmethod = mono_object_get_virtual_method (obj, method);
1107 g_assert (!mono_class_is_gtd (vmethod->klass));
1108 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1109 g_assert (!context->method_inst || !context->method_inst->is_open);
1111 addr = mono_compile_method_checked (vmethod, &error);
1112 if (mono_error_set_pending_exception (&error))
1115 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1117 /* Since this is a virtual call, have to unbox vtypes */
1118 if (obj->vtable->klass->valuetype)
1119 *this_arg = mono_object_unbox (obj);
1127 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1130 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1131 mono_error_set_pending_exception (&error);
1136 mono_helper_ldstr (MonoImage *image, guint32 idx)
1139 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1140 mono_error_set_pending_exception (&error);
1145 mono_helper_ldstr_mscorlib (guint32 idx)
1148 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1149 mono_error_set_pending_exception (&error);
1154 mono_helper_newobj_mscorlib (guint32 idx)
1157 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1159 if (!mono_error_ok (&error)) {
1160 mono_error_set_pending_exception (&error);
1164 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1165 if (!mono_error_ok (&error))
1166 mono_error_set_pending_exception (&error);
1171 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1172 * in generated code. So instead we emit a call to this function and place a gdb
1181 mono_create_corlib_exception_0 (guint32 token)
1183 return mono_exception_from_token (mono_defaults.corlib, token);
1187 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1190 MonoException *ret = mono_exception_from_token_two_strings_checked (
1191 mono_defaults.corlib, token, arg, NULL, &error);
1192 mono_error_set_pending_exception (&error);
1197 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1200 MonoException *ret = mono_exception_from_token_two_strings_checked (
1201 mono_defaults.corlib, token, arg1, arg2, &error);
1202 mono_error_set_pending_exception (&error);
1207 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1210 MonoJitTlsData *jit_tls = NULL;
1213 if (mini_get_debug_options ()->better_cast_details) {
1214 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1215 jit_tls->class_cast_from = NULL;
1221 oklass = obj->vtable->klass;
1222 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1224 if (mono_object_isinst_checked (obj, klass, &error))
1226 if (mono_error_set_pending_exception (&error))
1229 if (mini_get_debug_options ()->better_cast_details) {
1230 jit_tls->class_cast_from = oklass;
1231 jit_tls->class_cast_to = klass;
1234 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1235 "System", "InvalidCastException"));
1241 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1244 MonoJitTlsData *jit_tls = NULL;
1245 gpointer cached_vtable, obj_vtable;
1247 if (mini_get_debug_options ()->better_cast_details) {
1248 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1249 jit_tls->class_cast_from = NULL;
1255 cached_vtable = *cache;
1256 obj_vtable = obj->vtable;
1258 if (cached_vtable == obj_vtable)
1261 if (mono_object_isinst_checked (obj, klass, &error)) {
1262 *cache = obj_vtable;
1265 if (mono_error_set_pending_exception (&error))
1268 if (mini_get_debug_options ()->better_cast_details) {
1269 jit_tls->class_cast_from = obj->vtable->klass;
1270 jit_tls->class_cast_to = klass;
1273 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1274 "System", "InvalidCastException"));
1280 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1283 size_t cached_vtable, obj_vtable;
1288 cached_vtable = (size_t)*cache;
1289 obj_vtable = (size_t)obj->vtable;
1291 if ((cached_vtable & ~0x1) == obj_vtable) {
1292 return (cached_vtable & 0x1) ? NULL : obj;
1295 if (mono_object_isinst_checked (obj, klass, &error)) {
1296 *cache = (gpointer)obj_vtable;
1299 if (mono_error_set_pending_exception (&error))
1302 *cache = (gpointer)(obj_vtable | 0x1);
1308 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1311 MonoMarshalSpec **mspecs;
1312 MonoMethodPInvoke piinfo;
1315 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1316 memset (&piinfo, 0, sizeof (piinfo));
1318 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1320 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1321 mono_error_set_pending_exception (&error);
1322 return compiled_ptr;
1326 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1329 int vt_slot, iface_offset;
1333 if (mono_class_is_interface (klass)) {
1334 MonoObject *this_obj;
1336 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1337 this_obj = *(MonoObject**)mp;
1338 g_assert (this_obj);
1340 klass = this_obj->vtable->klass;
1343 if (mono_method_signature (cmethod)->pinvoke) {
1344 /* Object.GetType () */
1345 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1347 /* Lookup the virtual method */
1348 mono_class_setup_vtable (klass);
1349 g_assert (klass->vtable);
1350 vt_slot = mono_method_get_vtable_slot (cmethod);
1351 if (mono_class_is_interface (cmethod->klass)) {
1352 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1353 g_assert (iface_offset != -1);
1354 vt_slot += iface_offset;
1356 m = klass->vtable [vt_slot];
1357 if (cmethod->is_inflated)
1358 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1361 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1363 * Calling a non-vtype method with a vtype receiver, has to box.
1365 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1366 else if (klass->valuetype)
1368 * Calling a vtype method with a vtype receiver
1373 * Calling a non-vtype method
1375 *this_arg = *(gpointer*)mp;
1380 * mono_gsharedvt_constrained_call:
1382 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1383 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1386 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1392 gpointer new_args [16];
1394 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1395 if (!mono_error_ok (&error)) {
1396 mono_error_set_pending_exception (&error);
1402 if (args && deref_arg) {
1403 new_args [0] = *(gpointer*)args [0];
1406 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1407 /* Object.GetType () */
1409 args [0] = this_arg;
1413 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1414 if (!mono_error_ok (&error)) {
1415 mono_error_set_pending_exception (&error);
1423 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1425 if (klass->valuetype)
1426 mono_value_copy (dest, src, klass);
1428 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1432 ves_icall_runtime_class_init (MonoVTable *vtable)
1434 MONO_REQ_GC_UNSAFE_MODE;
1437 mono_runtime_class_init_full (vtable, &error);
1438 mono_error_set_pending_exception (&error);
1443 mono_generic_class_init (MonoVTable *vtable)
1446 mono_runtime_class_init_full (vtable, &error);
1447 mono_error_set_pending_exception (&error);
1451 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1453 HANDLE_FUNCTION_ENTER ();
1455 MONO_HANDLE_DCL (MonoObject, this_obj);
1456 MONO_HANDLE_DCL (MonoObject, target);
1457 mono_delegate_ctor (this_obj, target, addr, &error);
1458 mono_error_set_pending_exception (&error);
1459 HANDLE_FUNCTION_RETURN ();
1463 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1468 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1469 if (!mono_error_ok (&error)) {
1470 mono_error_set_pending_exception (&error);
1477 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1482 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1483 if (!mono_error_ok (&error)) {
1484 mono_error_set_pending_exception (&error);
1491 * resolve_iface_call:
1493 * Return the executable code for the iface method IMT_METHOD called on THIS.
1494 * This function is called on a slowpath, so it doesn't need to be fast.
1495 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1499 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1502 gpointer *imt, *vtable_slot;
1503 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1504 gpointer addr, compiled_method, aot_addr;
1505 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1509 /* The caller will handle it */
1512 vt = this_obj->vtable;
1513 imt = (gpointer*)vt - MONO_IMT_SIZE;
1515 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1516 return_val_if_nok (error, NULL);
1518 // FIXME: This can throw exceptions
1519 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1520 mono_error_assert_ok (error);
1523 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1524 generic_virtual = imt_method;
1526 if (generic_virtual || variant_iface) {
1527 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1528 need_unbox_tramp = TRUE;
1530 if (impl_method->klass->valuetype)
1531 need_unbox_tramp = TRUE;
1534 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1536 if (generic_virtual || variant_iface) {
1537 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1539 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1548 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1551 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1552 if (!is_ok (&error)) {
1553 MonoException *ex = mono_error_convert_to_exception (&error);
1554 mono_llvm_throw_exception ((MonoObject*)ex);
1560 is_generic_method_definition (MonoMethod *m)
1562 MonoGenericContext *context;
1565 if (!m->is_inflated)
1568 context = mono_method_get_context (m);
1569 if (!context->method_inst)
1571 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1579 * Return the executable code for calling vt->vtable [slot].
1580 * This function is called on a slowpath, so it doesn't need to be fast.
1581 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1585 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1587 MonoMethod *m, *generic_virtual = NULL;
1588 gpointer addr, compiled_method;
1589 gboolean need_unbox_tramp = FALSE;
1592 /* Same as in common_call_trampoline () */
1594 /* Avoid loading metadata or creating a generic vtable if possible */
1595 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1596 return_val_if_nok (error, NULL);
1597 if (addr && !vt->klass->valuetype)
1598 return mono_create_ftnptr (mono_domain_get (), addr);
1600 m = mono_class_get_vtable_entry (vt->klass, slot);
1602 if (is_generic_method_definition (m)) {
1603 MonoGenericContext context = { NULL, NULL };
1604 MonoMethod *declaring;
1607 declaring = mono_method_get_declaring_generic_method (m);
1611 if (mono_class_is_ginst (m->klass))
1612 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1614 g_assert (!mono_class_is_gtd (m->klass));
1616 generic_virtual = imt_method;
1617 g_assert (generic_virtual);
1618 g_assert (generic_virtual->is_inflated);
1619 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1621 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1622 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1625 if (generic_virtual) {
1626 if (vt->klass->valuetype)
1627 need_unbox_tramp = TRUE;
1629 if (m->klass->valuetype)
1630 need_unbox_tramp = TRUE;
1633 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1634 m = mono_marshal_get_synchronized_wrapper (m);
1636 // FIXME: This can throw exceptions
1637 addr = compiled_method = mono_compile_method_checked (m, error);
1638 mono_error_assert_ok (error);
1641 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1643 if (!gsharedvt && generic_virtual) {
1644 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1645 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1647 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1648 vt, vt->vtable + slot,
1649 generic_virtual, ftndesc);
1656 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1658 g_assert (this_obj);
1661 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1662 if (!is_ok (&error)) {
1663 MonoException *ex = mono_error_convert_to_exception (&error);
1664 mono_llvm_throw_exception ((MonoObject*)ex);
1670 * mono_resolve_generic_virtual_call:
1672 * Resolve a generic virtual call.
1673 * This function is called on a slowpath, so it doesn't need to be fast.
1676 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1679 gpointer addr, compiled_method;
1680 gboolean need_unbox_tramp = FALSE;
1682 MonoGenericContext context = { NULL, NULL };
1683 MonoMethod *declaring;
1684 gpointer arg = NULL;
1686 m = mono_class_get_vtable_entry (vt->klass, slot);
1688 g_assert (is_generic_method_definition (m));
1691 declaring = mono_method_get_declaring_generic_method (m);
1695 if (mono_class_is_ginst (m->klass))
1696 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1698 g_assert (!mono_class_is_gtd (m->klass));
1700 g_assert (generic_virtual->is_inflated);
1701 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1703 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1704 g_assert (mono_error_ok (&error));
1706 if (vt->klass->valuetype)
1707 need_unbox_tramp = TRUE;
1709 // FIXME: This can throw exceptions
1710 addr = compiled_method = mono_compile_method_checked (m, &error);
1711 mono_error_assert_ok (&error);
1714 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1717 * This wastes memory but the memory usage is bounded since
1718 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1719 * this vtable slot so we are not called any more for this instantiation.
1721 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1723 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1724 vt, vt->vtable + slot,
1725 generic_virtual, ftndesc);
1730 * mono_resolve_generic_virtual_call:
1732 * Resolve a generic virtual/variant iface call on interfaces.
1733 * This function is called on a slowpath, so it doesn't need to be fast.
1736 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1739 MonoMethod *m, *variant_iface;
1740 gpointer addr, aot_addr, compiled_method;
1741 gboolean need_unbox_tramp = FALSE;
1742 gboolean need_rgctx_tramp;
1743 gpointer arg = NULL;
1746 imt = (gpointer*)vt - MONO_IMT_SIZE;
1748 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1749 if (!is_ok (&error)) {
1750 MonoException *ex = mono_error_convert_to_exception (&error);
1751 mono_llvm_throw_exception ((MonoObject*)ex);
1754 if (vt->klass->valuetype)
1755 need_unbox_tramp = TRUE;
1757 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1758 m = mono_marshal_get_synchronized_wrapper (m);
1760 addr = compiled_method = mono_compile_method_checked (m, &error);
1761 mono_error_raise_exception (&error);
1764 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1767 * This wastes memory but the memory usage is bounded since
1768 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1769 * this vtable slot so we are not called any more for this instantiation.
1771 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1773 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1775 variant_iface ? variant_iface : generic_virtual, ftndesc);
1780 * mono_init_vtable_slot:
1782 * Initialize slot SLOT of VTABLE.
1783 * Return the contents of the vtable slot.
1786 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1789 gpointer arg = NULL;
1793 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1794 if (mono_error_set_pending_exception (&error))
1796 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1799 mono_memory_barrier ();
1801 vtable->vtable [slot] = ftnptr;
1807 * mono_llvmonly_init_delegate:
1809 * Initialize a MonoDelegate object.
1810 * Similar to mono_delegate_ctor ().
1813 mono_llvmonly_init_delegate (MonoDelegate *del)
1816 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1819 * We store a MonoFtnDesc in del->method_code.
1820 * It would be better to store an ftndesc in del->method_ptr too,
1821 * but we don't have a a structure which could own its memory.
1823 if (G_UNLIKELY (!ftndesc)) {
1824 MonoMethod *m = del->method;
1825 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1826 m = mono_marshal_get_synchronized_wrapper (m);
1828 gpointer addr = mono_compile_method_checked (m, &error);
1829 if (mono_error_set_pending_exception (&error))
1832 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1833 addr = mono_aot_get_unbox_trampoline (m);
1835 gpointer arg = mini_get_delegate_arg (del->method, addr);
1837 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1838 mono_memory_barrier ();
1839 *del->method_code = (gpointer)ftndesc;
1841 del->method_ptr = ftndesc->addr;
1842 del->extra_arg = ftndesc->arg;
1846 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1852 method = mono_object_get_virtual_method (target, method);
1854 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1855 method = mono_marshal_get_synchronized_wrapper (method);
1857 del->method = method;
1858 del->method_ptr = mono_compile_method_checked (method, &error);
1859 if (mono_error_set_pending_exception (&error))
1861 if (method->klass->valuetype)
1862 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1863 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1867 mono_get_assembly_object (MonoImage *image)
1870 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
1871 ICALL_RETURN_OBJ (result);
1875 mono_get_method_object (MonoMethod *method)
1878 MonoObject * result;
1879 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1880 mono_error_set_pending_exception (&error);
1885 mono_ckfinite (double d)
1887 if (isinf (d) || isnan (d))
1888 mono_set_pending_exception (mono_get_exception_arithmetic ());
1893 * mono_interruption_checkpoint_from_trampoline:
1895 * Check whenever the thread has a pending exception, and throw it
1897 * Architectures should move away from calling this function and
1898 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1899 * rewrind to the parent frame, and throw the exception normally.
1902 mono_interruption_checkpoint_from_trampoline (void)
1906 ex = mono_thread_force_interruption_checkpoint_noraise ();
1908 mono_raise_exception (ex);
1912 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1914 char *caller_name = mono_method_full_name (caller, 1);
1915 char *callee_name = mono_method_full_name (callee, 1);
1918 error_init (&error);
1919 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1920 mono_error_set_pending_exception (&error);
1921 g_free (callee_name);
1922 g_free (caller_name);
1926 mono_dummy_jit_icall (void)