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)
1092 #if defined(__native_client_codegen__) || defined(__native_client__)
1093 /* When we cross-compile to Native Client we can't directly embed calls */
1094 /* to the math library on the host. This will use the fmod on the target*/
1096 mono_fmod(double a, double b)
1103 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1106 MonoMethod *vmethod;
1108 MonoGenericContext *context = mono_method_get_context (method);
1110 mono_jit_stats.generic_virtual_invocations++;
1113 mono_set_pending_exception (mono_get_exception_null_reference ());
1116 vmethod = mono_object_get_virtual_method (obj, method);
1117 g_assert (!mono_class_is_gtd (vmethod->klass));
1118 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1119 g_assert (!context->method_inst || !context->method_inst->is_open);
1121 addr = mono_compile_method_checked (vmethod, &error);
1122 if (mono_error_set_pending_exception (&error))
1125 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1127 /* Since this is a virtual call, have to unbox vtypes */
1128 if (obj->vtable->klass->valuetype)
1129 *this_arg = mono_object_unbox (obj);
1137 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1140 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1141 mono_error_set_pending_exception (&error);
1146 mono_helper_ldstr (MonoImage *image, guint32 idx)
1149 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1150 mono_error_set_pending_exception (&error);
1155 mono_helper_ldstr_mscorlib (guint32 idx)
1158 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1159 mono_error_set_pending_exception (&error);
1164 mono_helper_newobj_mscorlib (guint32 idx)
1167 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1169 if (!mono_error_ok (&error)) {
1170 mono_error_set_pending_exception (&error);
1174 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1175 if (!mono_error_ok (&error))
1176 mono_error_set_pending_exception (&error);
1181 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1182 * in generated code. So instead we emit a call to this function and place a gdb
1191 mono_create_corlib_exception_0 (guint32 token)
1193 return mono_exception_from_token (mono_defaults.corlib, token);
1197 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1200 MonoException *ret = mono_exception_from_token_two_strings_checked (
1201 mono_defaults.corlib, token, arg, NULL, &error);
1202 mono_error_set_pending_exception (&error);
1207 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1210 MonoException *ret = mono_exception_from_token_two_strings_checked (
1211 mono_defaults.corlib, token, arg1, arg2, &error);
1212 mono_error_set_pending_exception (&error);
1217 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1220 MonoJitTlsData *jit_tls = NULL;
1223 if (mini_get_debug_options ()->better_cast_details) {
1224 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1225 jit_tls->class_cast_from = NULL;
1231 oklass = obj->vtable->klass;
1232 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1234 if (mono_object_isinst_checked (obj, klass, &error))
1236 if (mono_error_set_pending_exception (&error))
1239 if (mini_get_debug_options ()->better_cast_details) {
1240 jit_tls->class_cast_from = oklass;
1241 jit_tls->class_cast_to = klass;
1244 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1245 "System", "InvalidCastException"));
1251 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1254 MonoJitTlsData *jit_tls = NULL;
1255 gpointer cached_vtable, obj_vtable;
1257 if (mini_get_debug_options ()->better_cast_details) {
1258 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1259 jit_tls->class_cast_from = NULL;
1265 cached_vtable = *cache;
1266 obj_vtable = obj->vtable;
1268 if (cached_vtable == obj_vtable)
1271 if (mono_object_isinst_checked (obj, klass, &error)) {
1272 *cache = obj_vtable;
1275 if (mono_error_set_pending_exception (&error))
1278 if (mini_get_debug_options ()->better_cast_details) {
1279 jit_tls->class_cast_from = obj->vtable->klass;
1280 jit_tls->class_cast_to = klass;
1283 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1284 "System", "InvalidCastException"));
1290 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1293 size_t cached_vtable, obj_vtable;
1298 cached_vtable = (size_t)*cache;
1299 obj_vtable = (size_t)obj->vtable;
1301 if ((cached_vtable & ~0x1) == obj_vtable) {
1302 return (cached_vtable & 0x1) ? NULL : obj;
1305 if (mono_object_isinst_checked (obj, klass, &error)) {
1306 *cache = (gpointer)obj_vtable;
1309 if (mono_error_set_pending_exception (&error))
1312 *cache = (gpointer)(obj_vtable | 0x1);
1318 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1321 MonoMarshalSpec **mspecs;
1322 MonoMethodPInvoke piinfo;
1325 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1326 memset (&piinfo, 0, sizeof (piinfo));
1328 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1330 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1331 mono_error_set_pending_exception (&error);
1332 return compiled_ptr;
1336 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1339 int vt_slot, iface_offset;
1343 if (mono_class_is_interface (klass)) {
1344 MonoObject *this_obj;
1346 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1347 this_obj = *(MonoObject**)mp;
1348 g_assert (this_obj);
1350 klass = this_obj->vtable->klass;
1353 if (mono_method_signature (cmethod)->pinvoke) {
1354 /* Object.GetType () */
1355 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1357 /* Lookup the virtual method */
1358 mono_class_setup_vtable (klass);
1359 g_assert (klass->vtable);
1360 vt_slot = mono_method_get_vtable_slot (cmethod);
1361 if (mono_class_is_interface (cmethod->klass)) {
1362 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1363 g_assert (iface_offset != -1);
1364 vt_slot += iface_offset;
1366 m = klass->vtable [vt_slot];
1367 if (cmethod->is_inflated)
1368 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1371 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1373 * Calling a non-vtype method with a vtype receiver, has to box.
1375 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1376 else if (klass->valuetype)
1378 * Calling a vtype method with a vtype receiver
1383 * Calling a non-vtype method
1385 *this_arg = *(gpointer*)mp;
1390 * mono_gsharedvt_constrained_call:
1392 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1393 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1396 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1402 gpointer new_args [16];
1404 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1405 if (!mono_error_ok (&error)) {
1406 mono_error_set_pending_exception (&error);
1412 if (args && deref_arg) {
1413 new_args [0] = *(gpointer*)args [0];
1416 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1417 /* Object.GetType () */
1419 args [0] = this_arg;
1423 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1424 if (!mono_error_ok (&error)) {
1425 mono_error_set_pending_exception (&error);
1433 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1435 if (klass->valuetype)
1436 mono_value_copy (dest, src, klass);
1438 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1442 ves_icall_runtime_class_init (MonoVTable *vtable)
1444 MONO_REQ_GC_UNSAFE_MODE;
1447 mono_runtime_class_init_full (vtable, &error);
1448 mono_error_set_pending_exception (&error);
1453 mono_generic_class_init (MonoVTable *vtable)
1456 mono_runtime_class_init_full (vtable, &error);
1457 mono_error_set_pending_exception (&error);
1461 ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
1464 mono_delegate_ctor (this_obj, target, addr, &error);
1465 mono_error_set_pending_exception (&error);
1469 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1474 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1475 if (!mono_error_ok (&error)) {
1476 mono_error_set_pending_exception (&error);
1483 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1488 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1489 if (!mono_error_ok (&error)) {
1490 mono_error_set_pending_exception (&error);
1497 * resolve_iface_call:
1499 * Return the executable code for the iface method IMT_METHOD called on THIS.
1500 * This function is called on a slowpath, so it doesn't need to be fast.
1501 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1505 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1508 gpointer *imt, *vtable_slot;
1509 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1510 gpointer addr, compiled_method, aot_addr;
1511 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1515 /* The caller will handle it */
1518 vt = this_obj->vtable;
1519 imt = (gpointer*)vt - MONO_IMT_SIZE;
1521 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1522 return_val_if_nok (error, NULL);
1524 // FIXME: This can throw exceptions
1525 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1526 mono_error_assert_ok (error);
1529 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1530 generic_virtual = imt_method;
1532 if (generic_virtual || variant_iface) {
1533 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1534 need_unbox_tramp = TRUE;
1536 if (impl_method->klass->valuetype)
1537 need_unbox_tramp = TRUE;
1540 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1542 if (generic_virtual || variant_iface) {
1543 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1545 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1554 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1557 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1558 if (!is_ok (&error)) {
1559 MonoException *ex = mono_error_convert_to_exception (&error);
1560 mono_llvm_throw_exception ((MonoObject*)ex);
1566 is_generic_method_definition (MonoMethod *m)
1568 MonoGenericContext *context;
1571 if (!m->is_inflated)
1574 context = mono_method_get_context (m);
1575 if (!context->method_inst)
1577 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1585 * Return the executable code for calling vt->vtable [slot].
1586 * This function is called on a slowpath, so it doesn't need to be fast.
1587 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1591 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1593 MonoMethod *m, *generic_virtual = NULL;
1594 gpointer addr, compiled_method;
1595 gboolean need_unbox_tramp = FALSE;
1598 /* Same as in common_call_trampoline () */
1600 /* Avoid loading metadata or creating a generic vtable if possible */
1601 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1602 return_val_if_nok (error, NULL);
1603 if (addr && !vt->klass->valuetype)
1604 return mono_create_ftnptr (mono_domain_get (), addr);
1606 m = mono_class_get_vtable_entry (vt->klass, slot);
1608 if (is_generic_method_definition (m)) {
1609 MonoGenericContext context = { NULL, NULL };
1610 MonoMethod *declaring;
1613 declaring = mono_method_get_declaring_generic_method (m);
1617 if (mono_class_is_ginst (m->klass))
1618 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1620 g_assert (!mono_class_is_gtd (m->klass));
1622 generic_virtual = imt_method;
1623 g_assert (generic_virtual);
1624 g_assert (generic_virtual->is_inflated);
1625 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1627 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1628 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1631 if (generic_virtual) {
1632 if (vt->klass->valuetype)
1633 need_unbox_tramp = TRUE;
1635 if (m->klass->valuetype)
1636 need_unbox_tramp = TRUE;
1639 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1640 m = mono_marshal_get_synchronized_wrapper (m);
1642 // FIXME: This can throw exceptions
1643 addr = compiled_method = mono_compile_method_checked (m, error);
1644 mono_error_assert_ok (error);
1647 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1649 if (!gsharedvt && generic_virtual) {
1650 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1651 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1653 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1654 vt, vt->vtable + slot,
1655 generic_virtual, ftndesc);
1662 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1664 g_assert (this_obj);
1667 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1668 if (!is_ok (&error)) {
1669 MonoException *ex = mono_error_convert_to_exception (&error);
1670 mono_llvm_throw_exception ((MonoObject*)ex);
1676 * mono_resolve_generic_virtual_call:
1678 * Resolve a generic virtual call.
1679 * This function is called on a slowpath, so it doesn't need to be fast.
1682 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1685 gpointer addr, compiled_method;
1686 gboolean need_unbox_tramp = FALSE;
1688 MonoGenericContext context = { NULL, NULL };
1689 MonoMethod *declaring;
1690 gpointer arg = NULL;
1692 m = mono_class_get_vtable_entry (vt->klass, slot);
1694 g_assert (is_generic_method_definition (m));
1697 declaring = mono_method_get_declaring_generic_method (m);
1701 if (mono_class_is_ginst (m->klass))
1702 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1704 g_assert (!mono_class_is_gtd (m->klass));
1706 g_assert (generic_virtual->is_inflated);
1707 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1709 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1710 g_assert (mono_error_ok (&error));
1712 if (vt->klass->valuetype)
1713 need_unbox_tramp = TRUE;
1715 // FIXME: This can throw exceptions
1716 addr = compiled_method = mono_compile_method_checked (m, &error);
1717 mono_error_assert_ok (&error);
1720 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1723 * This wastes memory but the memory usage is bounded since
1724 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1725 * this vtable slot so we are not called any more for this instantiation.
1727 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1729 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1730 vt, vt->vtable + slot,
1731 generic_virtual, ftndesc);
1736 * mono_resolve_generic_virtual_call:
1738 * Resolve a generic virtual/variant iface call on interfaces.
1739 * This function is called on a slowpath, so it doesn't need to be fast.
1742 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1745 MonoMethod *m, *variant_iface;
1746 gpointer addr, aot_addr, compiled_method;
1747 gboolean need_unbox_tramp = FALSE;
1748 gboolean need_rgctx_tramp;
1749 gpointer arg = NULL;
1752 imt = (gpointer*)vt - MONO_IMT_SIZE;
1754 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1755 if (!is_ok (&error)) {
1756 MonoException *ex = mono_error_convert_to_exception (&error);
1757 mono_llvm_throw_exception ((MonoObject*)ex);
1760 if (vt->klass->valuetype)
1761 need_unbox_tramp = TRUE;
1763 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1764 m = mono_marshal_get_synchronized_wrapper (m);
1766 addr = compiled_method = mono_compile_method_checked (m, &error);
1767 mono_error_raise_exception (&error);
1770 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1773 * This wastes memory but the memory usage is bounded since
1774 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1775 * this vtable slot so we are not called any more for this instantiation.
1777 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1779 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1781 variant_iface ? variant_iface : generic_virtual, ftndesc);
1786 * mono_init_vtable_slot:
1788 * Initialize slot SLOT of VTABLE.
1789 * Return the contents of the vtable slot.
1792 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1795 gpointer arg = NULL;
1799 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1800 if (mono_error_set_pending_exception (&error))
1802 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1805 mono_memory_barrier ();
1807 vtable->vtable [slot] = ftnptr;
1813 * mono_llvmonly_init_delegate:
1815 * Initialize a MonoDelegate object.
1816 * Similar to mono_delegate_ctor ().
1819 mono_llvmonly_init_delegate (MonoDelegate *del)
1822 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1825 * We store a MonoFtnDesc in del->method_code.
1826 * It would be better to store an ftndesc in del->method_ptr too,
1827 * but we don't have a a structure which could own its memory.
1829 if (G_UNLIKELY (!ftndesc)) {
1830 MonoMethod *m = del->method;
1831 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1832 m = mono_marshal_get_synchronized_wrapper (m);
1834 gpointer addr = mono_compile_method_checked (m, &error);
1835 if (mono_error_set_pending_exception (&error))
1838 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1839 addr = mono_aot_get_unbox_trampoline (m);
1841 gpointer arg = mini_get_delegate_arg (del->method, addr);
1843 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1844 mono_memory_barrier ();
1845 *del->method_code = (gpointer)ftndesc;
1847 del->method_ptr = ftndesc->addr;
1848 del->extra_arg = ftndesc->arg;
1852 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1858 method = mono_object_get_virtual_method (target, method);
1860 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1861 method = mono_marshal_get_synchronized_wrapper (method);
1863 del->method = method;
1864 del->method_ptr = mono_compile_method_checked (method, &error);
1865 if (mono_error_set_pending_exception (&error))
1867 if (method->klass->valuetype)
1868 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1869 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1873 mono_get_assembly_object (MonoImage *image)
1876 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
1877 ICALL_RETURN_OBJ (result);
1881 mono_get_method_object (MonoMethod *method)
1884 MonoObject * result;
1885 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1886 mono_error_set_pending_exception (&error);
1891 mono_ckfinite (double d)
1893 if (isinf (d) || isnan (d))
1894 mono_set_pending_exception (mono_get_exception_arithmetic ());
1899 * mono_interruption_checkpoint_from_trampoline:
1901 * Check whenever the thread has a pending exception, and throw it
1903 * Architectures should move away from calling this function and
1904 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1905 * rewrind to the parent frame, and throw the exception normally.
1908 mono_interruption_checkpoint_from_trampoline (void)
1912 ex = mono_thread_force_interruption_checkpoint_noraise ();
1914 mono_raise_exception (ex);
1918 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1920 char *caller_name = mono_method_full_name (caller, 1);
1921 char *callee_name = mono_method_full_name (callee, 1);
1924 error_init (&error);
1925 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1926 mono_error_set_pending_exception (&error);
1927 g_free (callee_name);
1928 g_free (caller_name);
1932 mono_dummy_jit_icall (void)