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>
26 #include <mono/utils/unlocked.h>
29 #include "mini-llvm-cpp.h"
33 mono_ldftn (MonoMethod *method)
39 // FIXME: No error handling
41 addr = mono_compile_method_checked (method, &error);
42 mono_error_assert_ok (&error);
45 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
46 /* The caller doesn't pass it */
47 g_assert_not_reached ();
49 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
53 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
54 if (!mono_error_ok (&error)) {
55 mono_error_set_pending_exception (&error);
58 return mono_create_ftnptr (mono_domain_get (), addr);
62 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
68 mono_set_pending_exception (mono_get_exception_null_reference ());
72 res = mono_object_get_virtual_method (obj, method);
74 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
75 MonoGenericContext context = { NULL, NULL };
77 if (mono_class_is_ginst (res->klass))
78 context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
79 else if (mono_class_is_gtd (res->klass))
80 context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
81 context.method_inst = mono_method_get_context (method)->method_inst;
83 res = mono_class_inflate_generic_method_checked (res, &context, &error);
84 if (!mono_error_ok (&error)) {
85 mono_error_set_pending_exception (&error);
90 /* An rgctx wrapper is added by the trampolines no need to do it here */
92 return mono_ldftn (res);
96 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
98 return ldvirtfn_internal (obj, method, FALSE);
102 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
104 return ldvirtfn_internal (obj, method, TRUE);
108 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
112 mono_set_pending_exception (mono_get_exception_null_reference ());
115 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
116 if (mono_error_set_pending_exception (&error))
118 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
123 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
126 mono_llmult (gint64 a, gint64 b)
132 mono_llmult_ovf_un (guint64 a, guint64 b)
135 guint32 ah = a >> 32;
137 guint32 bh = b >> 32;
140 // fixme: this is incredible slow
143 goto raise_exception;
145 res = (guint64)al * (guint64)bl;
147 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
150 goto raise_exception;
152 res += ((guint64)t1) << 32;
157 mono_set_pending_exception (mono_get_exception_overflow ());
162 mono_llmult_ovf (gint64 a, gint64 b)
169 Use Karatsuba algorithm where:
170 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
171 where Ah is the "high half" (most significant 32 bits) of a and
172 where Al is the "low half" (least significant 32 bits) of a and
173 where Bh is the "high half" of b and Bl is the "low half" and
174 where R is the Radix or "size of the half" (in our case 32 bits)
176 Note, for the product of two 64 bit numbers to fit into a 64
177 result, ah and/or bh must be 0. This will save us from doing
178 the AhBh term at all.
180 Also note that we refactor so that we don't overflow 64 bits with
181 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
187 /* need to work with absoulte values, so find out what the
188 resulting sign will be and convert any negative numbers
189 from two's complement
193 if (((guint32)ah == 0x80000000) && (al == 0)) {
194 /* This has no two's complement */
200 goto raise_exception;
203 /* flip the bits and add 1 */
214 if (((guint32)bh == 0x80000000) && (bl == 0)) {
215 /* This has no two's complement */
221 goto raise_exception;
224 /* flip the bits and add 1 */
234 /* we overflow for sure if both upper halves are greater
235 than zero because we would need to shift their
236 product 64 bits to the left and that will not fit
237 in a 64 bit result */
239 goto raise_exception;
240 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
241 goto raise_exception;
243 /* do the AlBl term first */
244 t1 = (gint64)al * (gint64)bl;
248 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
249 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
250 /* check for overflow */
252 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
253 goto raise_exception;
258 goto raise_exception;
266 mono_set_pending_exception (mono_get_exception_overflow ());
271 mono_lldiv (gint64 a, gint64 b)
273 #ifdef MONO_ARCH_NEED_DIV_CHECK
275 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
278 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
279 mono_set_pending_exception (mono_get_exception_arithmetic ());
287 mono_llrem (gint64 a, gint64 b)
289 #ifdef MONO_ARCH_NEED_DIV_CHECK
291 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
294 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
295 mono_set_pending_exception (mono_get_exception_arithmetic ());
303 mono_lldiv_un (guint64 a, guint64 b)
305 #ifdef MONO_ARCH_NEED_DIV_CHECK
307 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
315 mono_llrem_un (guint64 a, guint64 b)
317 #ifdef MONO_ARCH_NEED_DIV_CHECK
319 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
328 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
331 mono_lshl (guint64 a, gint32 shamt)
335 res = a << (shamt & 0x7f);
337 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
343 mono_lshr_un (guint64 a, gint32 shamt)
347 res = a >> (shamt & 0x7f);
349 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
355 mono_lshr (gint64 a, gint32 shamt)
359 res = a >> (shamt & 0x7f);
361 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
368 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
371 mono_idiv (gint32 a, gint32 b)
373 #ifdef MONO_ARCH_NEED_DIV_CHECK
375 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
378 else if (b == -1 && a == (0x80000000)) {
379 mono_set_pending_exception (mono_get_exception_overflow ());
387 mono_idiv_un (guint32 a, guint32 b)
389 #ifdef MONO_ARCH_NEED_DIV_CHECK
391 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
399 mono_irem (gint32 a, gint32 b)
401 #ifdef MONO_ARCH_NEED_DIV_CHECK
403 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
406 else if (b == -1 && a == (0x80000000)) {
407 mono_set_pending_exception (mono_get_exception_overflow ());
415 mono_irem_un (guint32 a, guint32 b)
417 #ifdef MONO_ARCH_NEED_DIV_CHECK
419 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
428 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
431 mono_imul (gint32 a, gint32 b)
437 mono_imul_ovf (gint32 a, gint32 b)
441 res = (gint64)a * (gint64)b;
443 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
444 mono_set_pending_exception (mono_get_exception_overflow ());
452 mono_imul_ovf_un (guint32 a, guint32 b)
456 res = (guint64)a * (guint64)b;
459 mono_set_pending_exception (mono_get_exception_overflow ());
467 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
469 mono_fdiv (double a, double b)
475 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
478 mono_fsub (double a, double b)
484 mono_fadd (double a, double b)
490 mono_fmul (double a, double b)
502 mono_fconv_r4 (double a)
508 mono_conv_to_r8 (int a)
514 mono_conv_to_r4 (int a)
516 return (double)(float)a;
520 mono_fconv_i1 (double a)
526 mono_fconv_i2 (double a)
532 mono_fconv_i4 (double a)
538 mono_fconv_u1 (double a)
544 mono_fconv_u2 (double a)
550 mono_fcmp_eq (double a, double b)
556 mono_fcmp_ge (double a, double b)
562 mono_fcmp_gt (double a, double b)
568 mono_fcmp_le (double a, double b)
574 mono_fcmp_lt (double a, double b)
580 mono_fcmp_ne_un (double a, double b)
582 return isunordered (a, b) || a != b;
586 mono_fcmp_ge_un (double a, double b)
588 return isunordered (a, b) || a >= b;
592 mono_fcmp_gt_un (double a, double b)
594 return isunordered (a, b) || a > b;
598 mono_fcmp_le_un (double a, double b)
600 return isunordered (a, b) || a <= b;
604 mono_fcmp_lt_un (double a, double b)
606 return isunordered (a, b) || a < b;
610 mono_fceq (double a, double b)
616 mono_fcgt (double a, double b)
622 mono_fcgt_un (double a, double b)
624 return isunordered (a, b) || a > b;
628 mono_fclt (double a, double b)
634 mono_fclt_un (double a, double b)
636 return isunordered (a, b) || a < b;
640 mono_isfinite (double a)
645 g_assert_not_reached ();
651 mono_fload_r4 (float *ptr)
657 mono_fstore_r4 (double val, float *ptr)
662 /* returns the integer bitpattern that is passed in the regs or stack */
664 mono_fload_r4_arg (double val)
666 float v = (float)val;
667 return *(guint32*)&v;
673 mono_array_new_va (MonoMethod *cm, ...)
677 MonoDomain *domain = mono_domain_get ();
680 intptr_t *lower_bounds;
685 pcount = mono_method_signature (cm)->param_count;
686 rank = cm->klass->rank;
690 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
691 for (i = 0; i < pcount; ++i)
692 lengths [i] = d = va_arg(ap, int);
694 if (rank == pcount) {
695 /* Only lengths provided. */
696 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
697 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
698 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
703 g_assert (pcount == (rank * 2));
704 /* lower bounds are first. */
705 lower_bounds = (intptr_t*)lengths;
710 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
712 if (!mono_error_ok (&error)) {
713 mono_error_set_pending_exception (&error);
720 /* Specialized version of mono_array_new_va () which avoids varargs */
722 mono_array_new_1 (MonoMethod *cm, guint32 length)
726 MonoDomain *domain = mono_domain_get ();
727 uintptr_t lengths [1];
728 intptr_t *lower_bounds;
732 pcount = mono_method_signature (cm)->param_count;
733 rank = cm->klass->rank;
735 lengths [0] = length;
737 g_assert (rank == pcount);
739 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
740 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
741 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
746 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
748 if (!mono_error_ok (&error)) {
749 mono_error_set_pending_exception (&error);
757 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
761 MonoDomain *domain = mono_domain_get ();
762 uintptr_t lengths [2];
763 intptr_t *lower_bounds;
767 pcount = mono_method_signature (cm)->param_count;
768 rank = cm->klass->rank;
770 lengths [0] = length1;
771 lengths [1] = length2;
773 g_assert (rank == pcount);
775 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
776 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
777 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
782 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
784 if (!mono_error_ok (&error)) {
785 mono_error_set_pending_exception (&error);
793 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
797 MonoDomain *domain = mono_domain_get ();
798 uintptr_t lengths [3];
799 intptr_t *lower_bounds;
803 pcount = mono_method_signature (cm)->param_count;
804 rank = cm->klass->rank;
806 lengths [0] = length1;
807 lengths [1] = length2;
808 lengths [2] = length3;
810 g_assert (rank == pcount);
812 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
813 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
814 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
819 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
821 if (!mono_error_ok (&error)) {
822 mono_error_set_pending_exception (&error);
830 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
834 MonoDomain *domain = mono_domain_get ();
835 uintptr_t lengths [4];
836 intptr_t *lower_bounds;
840 pcount = mono_method_signature (cm)->param_count;
841 rank = cm->klass->rank;
843 lengths [0] = length1;
844 lengths [1] = length2;
845 lengths [2] = length3;
846 lengths [3] = length4;
848 g_assert (rank == pcount);
850 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
851 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
852 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
857 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
859 if (!mono_error_ok (&error)) {
860 mono_error_set_pending_exception (&error);
868 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
874 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
876 mono_class_init (field->parent);
878 vtable = mono_class_vtable_full (domain, field->parent, &error);
879 if (!is_ok (&error)) {
880 mono_error_set_pending_exception (&error);
883 if (!vtable->initialized) {
884 if (!mono_runtime_class_init_full (vtable, &error)) {
885 mono_error_set_pending_exception (&error);
890 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
892 if (field->offset == -1) {
894 g_assert (domain->special_static_fields);
895 mono_domain_lock (domain);
896 addr = g_hash_table_lookup (domain->special_static_fields, field);
897 mono_domain_unlock (domain);
898 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
900 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
906 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
909 MonoClass *handle_class;
912 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
913 if (!mono_error_ok (&error)) {
914 mono_error_set_pending_exception (&error);
917 mono_class_init (handle_class);
923 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
925 MonoMethodSignature *sig = mono_method_signature (method);
926 MonoGenericContext *generic_context;
928 if (sig->is_inflated) {
929 generic_context = mono_method_get_context (method);
931 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
932 g_assert (generic_container);
933 generic_context = &generic_container->context;
936 return mono_ldtoken_wrapper (image, token, generic_context);
940 mono_fconv_u8 (double v)
946 mono_rconv_u8 (float v)
951 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
953 mono_fconv_i8 (double v)
960 mono_fconv_u4 (double v)
962 /* MS.NET behaves like this for some reason */
964 if (isinf (v) || isnan (v))
972 /* Solaris doesn't have trunc */
974 extern long double aintl (long double);
977 /* FIXME: This means we will never throw overflow exceptions */
980 #endif /* HAVE_TRUNC */
983 mono_fconv_ovf_i8 (double v)
989 if (isnan(v) || trunc (v) != res) {
990 mono_set_pending_exception (mono_get_exception_overflow ());
997 mono_fconv_ovf_u8 (double v)
1002 * The soft-float implementation of some ARM devices have a buggy guin64 to double
1003 * conversion that it looses precision even when the integer if fully representable
1006 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1008 * To work around this issue we test for value boundaries instead.
1010 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1011 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1012 mono_set_pending_exception (mono_get_exception_overflow ());
1018 if (isnan(v) || trunc (v) != res) {
1019 mono_set_pending_exception (mono_get_exception_overflow ());
1026 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1028 mono_rconv_i8 (float v)
1035 mono_rconv_ovf_i8 (float v)
1041 if (isnan(v) || trunc (v) != res) {
1042 mono_set_pending_exception (mono_get_exception_overflow ());
1049 mono_rconv_ovf_u8 (float v)
1054 if (isnan(v) || trunc (v) != res) {
1055 mono_set_pending_exception (mono_get_exception_overflow ());
1061 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1063 mono_lconv_to_r8 (gint64 a)
1069 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1071 mono_lconv_to_r4 (gint64 a)
1077 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1079 mono_conv_to_r8_un (guint32 a)
1085 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1087 mono_lconv_to_r8_un (guint64 a)
1094 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1097 MonoMethod *vmethod;
1099 MonoGenericContext *context = mono_method_get_context (method);
1101 UnlockedIncrement (&mono_jit_stats.generic_virtual_invocations);
1104 mono_set_pending_exception (mono_get_exception_null_reference ());
1107 vmethod = mono_object_get_virtual_method (obj, method);
1108 g_assert (!mono_class_is_gtd (vmethod->klass));
1109 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1110 g_assert (!context->method_inst || !context->method_inst->is_open);
1112 addr = mono_compile_method_checked (vmethod, &error);
1113 if (mono_error_set_pending_exception (&error))
1116 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1118 /* Since this is a virtual call, have to unbox vtypes */
1119 if (obj->vtable->klass->valuetype)
1120 *this_arg = mono_object_unbox (obj);
1128 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1131 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1132 mono_error_set_pending_exception (&error);
1137 mono_helper_ldstr (MonoImage *image, guint32 idx)
1140 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1141 mono_error_set_pending_exception (&error);
1146 mono_helper_ldstr_mscorlib (guint32 idx)
1149 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1150 mono_error_set_pending_exception (&error);
1155 mono_helper_newobj_mscorlib (guint32 idx)
1158 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1160 if (!mono_error_ok (&error)) {
1161 mono_error_set_pending_exception (&error);
1165 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1166 if (!mono_error_ok (&error))
1167 mono_error_set_pending_exception (&error);
1172 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1173 * in generated code. So instead we emit a call to this function and place a gdb
1182 mono_create_corlib_exception_0 (guint32 token)
1184 return mono_exception_from_token (mono_defaults.corlib, token);
1188 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1191 MonoException *ret = mono_exception_from_token_two_strings_checked (
1192 mono_defaults.corlib, token, arg, NULL, &error);
1193 mono_error_set_pending_exception (&error);
1198 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1201 MonoException *ret = mono_exception_from_token_two_strings_checked (
1202 mono_defaults.corlib, token, arg1, arg2, &error);
1203 mono_error_set_pending_exception (&error);
1208 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1211 MonoJitTlsData *jit_tls = NULL;
1214 if (mini_get_debug_options ()->better_cast_details) {
1215 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1216 jit_tls->class_cast_from = NULL;
1222 oklass = obj->vtable->klass;
1223 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1225 if (mono_object_isinst_checked (obj, klass, &error))
1227 if (mono_error_set_pending_exception (&error))
1230 if (mini_get_debug_options ()->better_cast_details) {
1231 jit_tls->class_cast_from = oklass;
1232 jit_tls->class_cast_to = klass;
1235 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1236 "System", "InvalidCastException"));
1242 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1245 MonoJitTlsData *jit_tls = NULL;
1246 gpointer cached_vtable, obj_vtable;
1248 if (mini_get_debug_options ()->better_cast_details) {
1249 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1250 jit_tls->class_cast_from = NULL;
1256 cached_vtable = *cache;
1257 obj_vtable = obj->vtable;
1259 if (cached_vtable == obj_vtable)
1262 if (mono_object_isinst_checked (obj, klass, &error)) {
1263 *cache = obj_vtable;
1266 if (mono_error_set_pending_exception (&error))
1269 if (mini_get_debug_options ()->better_cast_details) {
1270 jit_tls->class_cast_from = obj->vtable->klass;
1271 jit_tls->class_cast_to = klass;
1274 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1275 "System", "InvalidCastException"));
1281 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1284 size_t cached_vtable, obj_vtable;
1289 cached_vtable = (size_t)*cache;
1290 obj_vtable = (size_t)obj->vtable;
1292 if ((cached_vtable & ~0x1) == obj_vtable) {
1293 return (cached_vtable & 0x1) ? NULL : obj;
1296 if (mono_object_isinst_checked (obj, klass, &error)) {
1297 *cache = (gpointer)obj_vtable;
1300 if (mono_error_set_pending_exception (&error))
1303 *cache = (gpointer)(obj_vtable | 0x1);
1309 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1312 MonoMarshalSpec **mspecs;
1313 MonoMethodPInvoke piinfo;
1316 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1317 memset (&piinfo, 0, sizeof (piinfo));
1319 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1321 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1322 mono_error_set_pending_exception (&error);
1323 return compiled_ptr;
1327 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1330 int vt_slot, iface_offset;
1331 gboolean is_iface = FALSE;
1335 if (mono_class_is_interface (klass)) {
1336 MonoObject *this_obj;
1340 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1341 this_obj = *(MonoObject**)mp;
1342 g_assert (this_obj);
1344 klass = this_obj->vtable->klass;
1347 if (mono_method_signature (cmethod)->pinvoke) {
1348 /* Object.GetType () */
1349 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1351 /* Lookup the virtual method */
1352 mono_class_setup_vtable (klass);
1353 g_assert (klass->vtable);
1354 vt_slot = mono_method_get_vtable_slot (cmethod);
1355 if (mono_class_is_interface (cmethod->klass)) {
1356 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1357 g_assert (iface_offset != -1);
1358 vt_slot += iface_offset;
1360 m = klass->vtable [vt_slot];
1361 if (cmethod->is_inflated)
1362 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1365 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class)) {
1367 * Calling a non-vtype method with a vtype receiver, has to box.
1369 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1370 } else if (klass->valuetype) {
1373 * The original type is an interface, so the receiver is a ref,
1374 the called method is a vtype method, need to unbox.
1376 MonoObject *this_obj = *(MonoObject**)mp;
1378 *this_arg = mono_object_unbox (this_obj);
1381 * Calling a vtype method with a vtype receiver
1387 * Calling a non-vtype method
1389 *this_arg = *(gpointer*)mp;
1396 * mono_gsharedvt_constrained_call:
1398 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1399 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1402 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1408 gpointer new_args [16];
1410 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1411 if (!mono_error_ok (&error)) {
1412 mono_error_set_pending_exception (&error);
1418 if (args && deref_arg) {
1419 new_args [0] = *(gpointer*)args [0];
1422 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1423 /* Object.GetType () */
1425 args [0] = this_arg;
1429 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1430 if (!mono_error_ok (&error)) {
1431 mono_error_set_pending_exception (&error);
1439 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1441 if (klass->valuetype)
1442 mono_value_copy (dest, src, klass);
1444 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1448 ves_icall_runtime_class_init (MonoVTable *vtable)
1450 MONO_REQ_GC_UNSAFE_MODE;
1453 mono_runtime_class_init_full (vtable, &error);
1454 mono_error_set_pending_exception (&error);
1459 mono_generic_class_init (MonoVTable *vtable)
1462 mono_runtime_class_init_full (vtable, &error);
1463 mono_error_set_pending_exception (&error);
1467 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1469 HANDLE_FUNCTION_ENTER ();
1471 MONO_HANDLE_DCL (MonoObject, this_obj);
1472 MONO_HANDLE_DCL (MonoObject, target);
1473 mono_delegate_ctor (this_obj, target, addr, &error);
1474 mono_error_set_pending_exception (&error);
1475 HANDLE_FUNCTION_RETURN ();
1479 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1484 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1485 if (!mono_error_ok (&error)) {
1486 mono_error_set_pending_exception (&error);
1493 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1498 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1499 if (!mono_error_ok (&error)) {
1500 mono_error_set_pending_exception (&error);
1507 * resolve_iface_call:
1509 * Return the executable code for the iface method IMT_METHOD called on THIS.
1510 * This function is called on a slowpath, so it doesn't need to be fast.
1511 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1515 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1518 gpointer *imt, *vtable_slot;
1519 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1520 gpointer addr, compiled_method, aot_addr;
1521 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1525 /* The caller will handle it */
1528 vt = this_obj->vtable;
1529 imt = (gpointer*)vt - MONO_IMT_SIZE;
1531 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1532 return_val_if_nok (error, NULL);
1534 // FIXME: This can throw exceptions
1535 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1536 mono_error_assert_ok (error);
1539 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1540 generic_virtual = imt_method;
1542 if (generic_virtual || variant_iface) {
1543 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1544 need_unbox_tramp = TRUE;
1546 if (impl_method->klass->valuetype)
1547 need_unbox_tramp = TRUE;
1550 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1552 if (generic_virtual || variant_iface) {
1553 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1555 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1564 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1567 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1568 if (!is_ok (&error)) {
1569 MonoException *ex = mono_error_convert_to_exception (&error);
1570 mono_llvm_throw_exception ((MonoObject*)ex);
1576 is_generic_method_definition (MonoMethod *m)
1578 MonoGenericContext *context;
1581 if (!m->is_inflated)
1584 context = mono_method_get_context (m);
1585 if (!context->method_inst)
1587 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1595 * Return the executable code for calling vt->vtable [slot].
1596 * This function is called on a slowpath, so it doesn't need to be fast.
1597 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1601 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1603 MonoMethod *m, *generic_virtual = NULL;
1604 gpointer addr, compiled_method;
1605 gboolean need_unbox_tramp = FALSE;
1608 /* Same as in common_call_trampoline () */
1610 /* Avoid loading metadata or creating a generic vtable if possible */
1611 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1612 return_val_if_nok (error, NULL);
1613 if (addr && !vt->klass->valuetype)
1614 return mono_create_ftnptr (mono_domain_get (), addr);
1616 m = mono_class_get_vtable_entry (vt->klass, slot);
1618 if (is_generic_method_definition (m)) {
1619 MonoGenericContext context = { NULL, NULL };
1620 MonoMethod *declaring;
1623 declaring = mono_method_get_declaring_generic_method (m);
1627 if (mono_class_is_ginst (m->klass))
1628 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1630 g_assert (!mono_class_is_gtd (m->klass));
1632 generic_virtual = imt_method;
1633 g_assert (generic_virtual);
1634 g_assert (generic_virtual->is_inflated);
1635 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1637 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1638 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1641 if (generic_virtual) {
1642 if (vt->klass->valuetype)
1643 need_unbox_tramp = TRUE;
1645 if (m->klass->valuetype)
1646 need_unbox_tramp = TRUE;
1649 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1650 m = mono_marshal_get_synchronized_wrapper (m);
1652 // FIXME: This can throw exceptions
1653 addr = compiled_method = mono_compile_method_checked (m, error);
1654 mono_error_assert_ok (error);
1657 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1659 if (!gsharedvt && generic_virtual) {
1660 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1661 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1663 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1664 vt, vt->vtable + slot,
1665 generic_virtual, ftndesc);
1672 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1674 g_assert (this_obj);
1677 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1678 if (!is_ok (&error)) {
1679 MonoException *ex = mono_error_convert_to_exception (&error);
1680 mono_llvm_throw_exception ((MonoObject*)ex);
1686 * mono_resolve_generic_virtual_call:
1688 * Resolve a generic virtual call.
1689 * This function is called on a slowpath, so it doesn't need to be fast.
1692 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1695 gpointer addr, compiled_method;
1696 gboolean need_unbox_tramp = FALSE;
1698 MonoGenericContext context = { NULL, NULL };
1699 MonoMethod *declaring;
1700 gpointer arg = NULL;
1702 m = mono_class_get_vtable_entry (vt->klass, slot);
1704 g_assert (is_generic_method_definition (m));
1707 declaring = mono_method_get_declaring_generic_method (m);
1711 if (mono_class_is_ginst (m->klass))
1712 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1714 g_assert (!mono_class_is_gtd (m->klass));
1716 g_assert (generic_virtual->is_inflated);
1717 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1719 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1720 g_assert (mono_error_ok (&error));
1722 if (vt->klass->valuetype)
1723 need_unbox_tramp = TRUE;
1725 // FIXME: This can throw exceptions
1726 addr = compiled_method = mono_compile_method_checked (m, &error);
1727 mono_error_assert_ok (&error);
1730 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1733 * This wastes memory but the memory usage is bounded since
1734 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1735 * this vtable slot so we are not called any more for this instantiation.
1737 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1739 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1740 vt, vt->vtable + slot,
1741 generic_virtual, ftndesc);
1746 * mono_resolve_generic_virtual_call:
1748 * Resolve a generic virtual/variant iface call on interfaces.
1749 * This function is called on a slowpath, so it doesn't need to be fast.
1752 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1755 MonoMethod *m, *variant_iface;
1756 gpointer addr, aot_addr, compiled_method;
1757 gboolean need_unbox_tramp = FALSE;
1758 gboolean need_rgctx_tramp;
1759 gpointer arg = NULL;
1762 imt = (gpointer*)vt - MONO_IMT_SIZE;
1764 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1765 if (!is_ok (&error)) {
1766 MonoException *ex = mono_error_convert_to_exception (&error);
1767 mono_llvm_throw_exception ((MonoObject*)ex);
1770 if (vt->klass->valuetype)
1771 need_unbox_tramp = TRUE;
1773 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1774 m = mono_marshal_get_synchronized_wrapper (m);
1776 addr = compiled_method = mono_compile_method_checked (m, &error);
1777 mono_error_raise_exception (&error);
1780 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1783 * This wastes memory but the memory usage is bounded since
1784 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1785 * this vtable slot so we are not called any more for this instantiation.
1787 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1789 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1791 variant_iface ? variant_iface : generic_virtual, ftndesc);
1796 * mono_init_vtable_slot:
1798 * Initialize slot SLOT of VTABLE.
1799 * Return the contents of the vtable slot.
1802 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1805 gpointer arg = NULL;
1809 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1810 if (mono_error_set_pending_exception (&error))
1812 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1815 mono_memory_barrier ();
1817 vtable->vtable [slot] = ftnptr;
1823 * mono_llvmonly_init_delegate:
1825 * Initialize a MonoDelegate object.
1826 * Similar to mono_delegate_ctor ().
1829 mono_llvmonly_init_delegate (MonoDelegate *del)
1832 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1835 * We store a MonoFtnDesc in del->method_code.
1836 * It would be better to store an ftndesc in del->method_ptr too,
1837 * but we don't have a a structure which could own its memory.
1839 if (G_UNLIKELY (!ftndesc)) {
1840 MonoMethod *m = del->method;
1841 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1842 m = mono_marshal_get_synchronized_wrapper (m);
1844 gpointer addr = mono_compile_method_checked (m, &error);
1845 if (mono_error_set_pending_exception (&error))
1848 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1849 addr = mono_aot_get_unbox_trampoline (m);
1851 gpointer arg = mini_get_delegate_arg (del->method, addr);
1853 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1854 mono_memory_barrier ();
1855 *del->method_code = (gpointer)ftndesc;
1857 del->method_ptr = ftndesc->addr;
1858 del->extra_arg = ftndesc->arg;
1862 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1868 method = mono_object_get_virtual_method (target, method);
1870 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1871 method = mono_marshal_get_synchronized_wrapper (method);
1873 del->method = method;
1874 del->method_ptr = mono_compile_method_checked (method, &error);
1875 if (mono_error_set_pending_exception (&error))
1877 if (method->klass->valuetype)
1878 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1879 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1883 mono_get_assembly_object (MonoImage *image)
1886 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
1887 ICALL_RETURN_OBJ (result);
1891 mono_get_method_object (MonoMethod *method)
1894 MonoObject * result;
1895 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1896 mono_error_set_pending_exception (&error);
1901 mono_ckfinite (double d)
1903 if (isinf (d) || isnan (d))
1904 mono_set_pending_exception (mono_get_exception_arithmetic ());
1909 * mono_interruption_checkpoint_from_trampoline:
1911 * Check whenever the thread has a pending exception, and throw it
1913 * Architectures should move away from calling this function and
1914 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1915 * rewrind to the parent frame, and throw the exception normally.
1918 mono_interruption_checkpoint_from_trampoline (void)
1922 ex = mono_thread_force_interruption_checkpoint_noraise ();
1924 mono_raise_exception (ex);
1928 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1930 char *caller_name = mono_method_get_reflection_name (caller);
1931 char *callee_name = mono_method_get_reflection_name (callee);
1934 error_init (&error);
1935 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1936 mono_error_set_pending_exception (&error);
1937 g_free (callee_name);
1938 g_free (caller_name);
1942 mono_dummy_jit_icall (void)