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_raw, MonoObject *target_raw, gpointer addr)
1463 HANDLE_FUNCTION_ENTER ();
1465 MONO_HANDLE_DCL (MonoObject, this_obj);
1466 MONO_HANDLE_DCL (MonoObject, target);
1467 mono_delegate_ctor (this_obj, target, addr, &error);
1468 mono_error_set_pending_exception (&error);
1469 HANDLE_FUNCTION_RETURN ();
1473 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1478 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1479 if (!mono_error_ok (&error)) {
1480 mono_error_set_pending_exception (&error);
1487 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1492 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1493 if (!mono_error_ok (&error)) {
1494 mono_error_set_pending_exception (&error);
1501 * resolve_iface_call:
1503 * Return the executable code for the iface method IMT_METHOD called on THIS.
1504 * This function is called on a slowpath, so it doesn't need to be fast.
1505 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1509 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1512 gpointer *imt, *vtable_slot;
1513 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1514 gpointer addr, compiled_method, aot_addr;
1515 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1519 /* The caller will handle it */
1522 vt = this_obj->vtable;
1523 imt = (gpointer*)vt - MONO_IMT_SIZE;
1525 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1526 return_val_if_nok (error, NULL);
1528 // FIXME: This can throw exceptions
1529 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1530 mono_error_assert_ok (error);
1533 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1534 generic_virtual = imt_method;
1536 if (generic_virtual || variant_iface) {
1537 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1538 need_unbox_tramp = TRUE;
1540 if (impl_method->klass->valuetype)
1541 need_unbox_tramp = TRUE;
1544 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1546 if (generic_virtual || variant_iface) {
1547 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1549 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1558 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1561 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1562 if (!is_ok (&error)) {
1563 MonoException *ex = mono_error_convert_to_exception (&error);
1564 mono_llvm_throw_exception ((MonoObject*)ex);
1570 is_generic_method_definition (MonoMethod *m)
1572 MonoGenericContext *context;
1575 if (!m->is_inflated)
1578 context = mono_method_get_context (m);
1579 if (!context->method_inst)
1581 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1589 * Return the executable code for calling vt->vtable [slot].
1590 * This function is called on a slowpath, so it doesn't need to be fast.
1591 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1595 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1597 MonoMethod *m, *generic_virtual = NULL;
1598 gpointer addr, compiled_method;
1599 gboolean need_unbox_tramp = FALSE;
1602 /* Same as in common_call_trampoline () */
1604 /* Avoid loading metadata or creating a generic vtable if possible */
1605 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1606 return_val_if_nok (error, NULL);
1607 if (addr && !vt->klass->valuetype)
1608 return mono_create_ftnptr (mono_domain_get (), addr);
1610 m = mono_class_get_vtable_entry (vt->klass, slot);
1612 if (is_generic_method_definition (m)) {
1613 MonoGenericContext context = { NULL, NULL };
1614 MonoMethod *declaring;
1617 declaring = mono_method_get_declaring_generic_method (m);
1621 if (mono_class_is_ginst (m->klass))
1622 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1624 g_assert (!mono_class_is_gtd (m->klass));
1626 generic_virtual = imt_method;
1627 g_assert (generic_virtual);
1628 g_assert (generic_virtual->is_inflated);
1629 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1631 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1632 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1635 if (generic_virtual) {
1636 if (vt->klass->valuetype)
1637 need_unbox_tramp = TRUE;
1639 if (m->klass->valuetype)
1640 need_unbox_tramp = TRUE;
1643 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1644 m = mono_marshal_get_synchronized_wrapper (m);
1646 // FIXME: This can throw exceptions
1647 addr = compiled_method = mono_compile_method_checked (m, error);
1648 mono_error_assert_ok (error);
1651 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1653 if (!gsharedvt && generic_virtual) {
1654 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1655 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1657 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1658 vt, vt->vtable + slot,
1659 generic_virtual, ftndesc);
1666 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1668 g_assert (this_obj);
1671 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1672 if (!is_ok (&error)) {
1673 MonoException *ex = mono_error_convert_to_exception (&error);
1674 mono_llvm_throw_exception ((MonoObject*)ex);
1680 * mono_resolve_generic_virtual_call:
1682 * Resolve a generic virtual call.
1683 * This function is called on a slowpath, so it doesn't need to be fast.
1686 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1689 gpointer addr, compiled_method;
1690 gboolean need_unbox_tramp = FALSE;
1692 MonoGenericContext context = { NULL, NULL };
1693 MonoMethod *declaring;
1694 gpointer arg = NULL;
1696 m = mono_class_get_vtable_entry (vt->klass, slot);
1698 g_assert (is_generic_method_definition (m));
1701 declaring = mono_method_get_declaring_generic_method (m);
1705 if (mono_class_is_ginst (m->klass))
1706 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1708 g_assert (!mono_class_is_gtd (m->klass));
1710 g_assert (generic_virtual->is_inflated);
1711 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1713 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1714 g_assert (mono_error_ok (&error));
1716 if (vt->klass->valuetype)
1717 need_unbox_tramp = TRUE;
1719 // FIXME: This can throw exceptions
1720 addr = compiled_method = mono_compile_method_checked (m, &error);
1721 mono_error_assert_ok (&error);
1724 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1727 * This wastes memory but the memory usage is bounded since
1728 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1729 * this vtable slot so we are not called any more for this instantiation.
1731 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1733 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1734 vt, vt->vtable + slot,
1735 generic_virtual, ftndesc);
1740 * mono_resolve_generic_virtual_call:
1742 * Resolve a generic virtual/variant iface call on interfaces.
1743 * This function is called on a slowpath, so it doesn't need to be fast.
1746 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1749 MonoMethod *m, *variant_iface;
1750 gpointer addr, aot_addr, compiled_method;
1751 gboolean need_unbox_tramp = FALSE;
1752 gboolean need_rgctx_tramp;
1753 gpointer arg = NULL;
1756 imt = (gpointer*)vt - MONO_IMT_SIZE;
1758 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1759 if (!is_ok (&error)) {
1760 MonoException *ex = mono_error_convert_to_exception (&error);
1761 mono_llvm_throw_exception ((MonoObject*)ex);
1764 if (vt->klass->valuetype)
1765 need_unbox_tramp = TRUE;
1767 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1768 m = mono_marshal_get_synchronized_wrapper (m);
1770 addr = compiled_method = mono_compile_method_checked (m, &error);
1771 mono_error_raise_exception (&error);
1774 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1777 * This wastes memory but the memory usage is bounded since
1778 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1779 * this vtable slot so we are not called any more for this instantiation.
1781 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1783 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1785 variant_iface ? variant_iface : generic_virtual, ftndesc);
1790 * mono_init_vtable_slot:
1792 * Initialize slot SLOT of VTABLE.
1793 * Return the contents of the vtable slot.
1796 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1799 gpointer arg = NULL;
1803 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1804 if (mono_error_set_pending_exception (&error))
1806 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1809 mono_memory_barrier ();
1811 vtable->vtable [slot] = ftnptr;
1817 * mono_llvmonly_init_delegate:
1819 * Initialize a MonoDelegate object.
1820 * Similar to mono_delegate_ctor ().
1823 mono_llvmonly_init_delegate (MonoDelegate *del)
1826 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1829 * We store a MonoFtnDesc in del->method_code.
1830 * It would be better to store an ftndesc in del->method_ptr too,
1831 * but we don't have a a structure which could own its memory.
1833 if (G_UNLIKELY (!ftndesc)) {
1834 MonoMethod *m = del->method;
1835 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1836 m = mono_marshal_get_synchronized_wrapper (m);
1838 gpointer addr = mono_compile_method_checked (m, &error);
1839 if (mono_error_set_pending_exception (&error))
1842 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1843 addr = mono_aot_get_unbox_trampoline (m);
1845 gpointer arg = mini_get_delegate_arg (del->method, addr);
1847 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1848 mono_memory_barrier ();
1849 *del->method_code = (gpointer)ftndesc;
1851 del->method_ptr = ftndesc->addr;
1852 del->extra_arg = ftndesc->arg;
1856 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1862 method = mono_object_get_virtual_method (target, method);
1864 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1865 method = mono_marshal_get_synchronized_wrapper (method);
1867 del->method = method;
1868 del->method_ptr = mono_compile_method_checked (method, &error);
1869 if (mono_error_set_pending_exception (&error))
1871 if (method->klass->valuetype)
1872 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1873 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1877 mono_get_assembly_object (MonoImage *image)
1880 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
1881 ICALL_RETURN_OBJ (result);
1885 mono_get_method_object (MonoMethod *method)
1888 MonoObject * result;
1889 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1890 mono_error_set_pending_exception (&error);
1895 mono_ckfinite (double d)
1897 if (isinf (d) || isnan (d))
1898 mono_set_pending_exception (mono_get_exception_arithmetic ());
1903 * mono_interruption_checkpoint_from_trampoline:
1905 * Check whenever the thread has a pending exception, and throw it
1907 * Architectures should move away from calling this function and
1908 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1909 * rewrind to the parent frame, and throw the exception normally.
1912 mono_interruption_checkpoint_from_trampoline (void)
1916 ex = mono_thread_force_interruption_checkpoint_noraise ();
1918 mono_raise_exception (ex);
1922 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1924 char *caller_name = mono_method_full_name (caller, 1);
1925 char *callee_name = mono_method_full_name (callee, 1);
1928 error_init (&error);
1929 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1930 mono_error_set_pending_exception (&error);
1931 g_free (callee_name);
1932 g_free (caller_name);
1936 mono_dummy_jit_icall (void)