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;
1334 if (mono_class_is_interface (klass)) {
1335 MonoObject *this_obj;
1337 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1338 this_obj = *(MonoObject**)mp;
1339 g_assert (this_obj);
1341 klass = this_obj->vtable->klass;
1344 if (mono_method_signature (cmethod)->pinvoke) {
1345 /* Object.GetType () */
1346 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1348 /* Lookup the virtual method */
1349 mono_class_setup_vtable (klass);
1350 g_assert (klass->vtable);
1351 vt_slot = mono_method_get_vtable_slot (cmethod);
1352 if (mono_class_is_interface (cmethod->klass)) {
1353 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1354 g_assert (iface_offset != -1);
1355 vt_slot += iface_offset;
1357 m = klass->vtable [vt_slot];
1358 if (cmethod->is_inflated)
1359 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1362 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1364 * Calling a non-vtype method with a vtype receiver, has to box.
1366 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1367 else if (klass->valuetype)
1369 * Calling a vtype method with a vtype receiver
1374 * Calling a non-vtype method
1376 *this_arg = *(gpointer*)mp;
1381 * mono_gsharedvt_constrained_call:
1383 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1384 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1387 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1393 gpointer new_args [16];
1395 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1396 if (!mono_error_ok (&error)) {
1397 mono_error_set_pending_exception (&error);
1403 if (args && deref_arg) {
1404 new_args [0] = *(gpointer*)args [0];
1407 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1408 /* Object.GetType () */
1410 args [0] = this_arg;
1414 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1415 if (!mono_error_ok (&error)) {
1416 mono_error_set_pending_exception (&error);
1424 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1426 if (klass->valuetype)
1427 mono_value_copy (dest, src, klass);
1429 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1433 ves_icall_runtime_class_init (MonoVTable *vtable)
1435 MONO_REQ_GC_UNSAFE_MODE;
1438 mono_runtime_class_init_full (vtable, &error);
1439 mono_error_set_pending_exception (&error);
1444 mono_generic_class_init (MonoVTable *vtable)
1447 mono_runtime_class_init_full (vtable, &error);
1448 mono_error_set_pending_exception (&error);
1452 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1454 HANDLE_FUNCTION_ENTER ();
1456 MONO_HANDLE_DCL (MonoObject, this_obj);
1457 MONO_HANDLE_DCL (MonoObject, target);
1458 mono_delegate_ctor (this_obj, target, addr, &error);
1459 mono_error_set_pending_exception (&error);
1460 HANDLE_FUNCTION_RETURN ();
1464 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1469 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1470 if (!mono_error_ok (&error)) {
1471 mono_error_set_pending_exception (&error);
1478 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1483 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1484 if (!mono_error_ok (&error)) {
1485 mono_error_set_pending_exception (&error);
1492 * resolve_iface_call:
1494 * Return the executable code for the iface method IMT_METHOD called on THIS.
1495 * This function is called on a slowpath, so it doesn't need to be fast.
1496 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1500 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1503 gpointer *imt, *vtable_slot;
1504 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1505 gpointer addr, compiled_method, aot_addr;
1506 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1510 /* The caller will handle it */
1513 vt = this_obj->vtable;
1514 imt = (gpointer*)vt - MONO_IMT_SIZE;
1516 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1517 return_val_if_nok (error, NULL);
1519 // FIXME: This can throw exceptions
1520 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1521 mono_error_assert_ok (error);
1524 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1525 generic_virtual = imt_method;
1527 if (generic_virtual || variant_iface) {
1528 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1529 need_unbox_tramp = TRUE;
1531 if (impl_method->klass->valuetype)
1532 need_unbox_tramp = TRUE;
1535 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1537 if (generic_virtual || variant_iface) {
1538 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1540 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1549 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1552 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1553 if (!is_ok (&error)) {
1554 MonoException *ex = mono_error_convert_to_exception (&error);
1555 mono_llvm_throw_exception ((MonoObject*)ex);
1561 is_generic_method_definition (MonoMethod *m)
1563 MonoGenericContext *context;
1566 if (!m->is_inflated)
1569 context = mono_method_get_context (m);
1570 if (!context->method_inst)
1572 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1580 * Return the executable code for calling vt->vtable [slot].
1581 * This function is called on a slowpath, so it doesn't need to be fast.
1582 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1586 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1588 MonoMethod *m, *generic_virtual = NULL;
1589 gpointer addr, compiled_method;
1590 gboolean need_unbox_tramp = FALSE;
1593 /* Same as in common_call_trampoline () */
1595 /* Avoid loading metadata or creating a generic vtable if possible */
1596 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1597 return_val_if_nok (error, NULL);
1598 if (addr && !vt->klass->valuetype)
1599 return mono_create_ftnptr (mono_domain_get (), addr);
1601 m = mono_class_get_vtable_entry (vt->klass, slot);
1603 if (is_generic_method_definition (m)) {
1604 MonoGenericContext context = { NULL, NULL };
1605 MonoMethod *declaring;
1608 declaring = mono_method_get_declaring_generic_method (m);
1612 if (mono_class_is_ginst (m->klass))
1613 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1615 g_assert (!mono_class_is_gtd (m->klass));
1617 generic_virtual = imt_method;
1618 g_assert (generic_virtual);
1619 g_assert (generic_virtual->is_inflated);
1620 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1622 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1623 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1626 if (generic_virtual) {
1627 if (vt->klass->valuetype)
1628 need_unbox_tramp = TRUE;
1630 if (m->klass->valuetype)
1631 need_unbox_tramp = TRUE;
1634 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1635 m = mono_marshal_get_synchronized_wrapper (m);
1637 // FIXME: This can throw exceptions
1638 addr = compiled_method = mono_compile_method_checked (m, error);
1639 mono_error_assert_ok (error);
1642 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1644 if (!gsharedvt && generic_virtual) {
1645 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1646 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1648 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1649 vt, vt->vtable + slot,
1650 generic_virtual, ftndesc);
1657 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1659 g_assert (this_obj);
1662 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1663 if (!is_ok (&error)) {
1664 MonoException *ex = mono_error_convert_to_exception (&error);
1665 mono_llvm_throw_exception ((MonoObject*)ex);
1671 * mono_resolve_generic_virtual_call:
1673 * Resolve a generic virtual call.
1674 * This function is called on a slowpath, so it doesn't need to be fast.
1677 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1680 gpointer addr, compiled_method;
1681 gboolean need_unbox_tramp = FALSE;
1683 MonoGenericContext context = { NULL, NULL };
1684 MonoMethod *declaring;
1685 gpointer arg = NULL;
1687 m = mono_class_get_vtable_entry (vt->klass, slot);
1689 g_assert (is_generic_method_definition (m));
1692 declaring = mono_method_get_declaring_generic_method (m);
1696 if (mono_class_is_ginst (m->klass))
1697 context.class_inst = mono_class_get_generic_class (m->klass)->context.class_inst;
1699 g_assert (!mono_class_is_gtd (m->klass));
1701 g_assert (generic_virtual->is_inflated);
1702 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1704 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1705 g_assert (mono_error_ok (&error));
1707 if (vt->klass->valuetype)
1708 need_unbox_tramp = TRUE;
1710 // FIXME: This can throw exceptions
1711 addr = compiled_method = mono_compile_method_checked (m, &error);
1712 mono_error_assert_ok (&error);
1715 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1718 * This wastes memory but the memory usage is bounded since
1719 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1720 * this vtable slot so we are not called any more for this instantiation.
1722 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1724 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1725 vt, vt->vtable + slot,
1726 generic_virtual, ftndesc);
1731 * mono_resolve_generic_virtual_call:
1733 * Resolve a generic virtual/variant iface call on interfaces.
1734 * This function is called on a slowpath, so it doesn't need to be fast.
1737 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1740 MonoMethod *m, *variant_iface;
1741 gpointer addr, aot_addr, compiled_method;
1742 gboolean need_unbox_tramp = FALSE;
1743 gboolean need_rgctx_tramp;
1744 gpointer arg = NULL;
1747 imt = (gpointer*)vt - MONO_IMT_SIZE;
1749 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1750 if (!is_ok (&error)) {
1751 MonoException *ex = mono_error_convert_to_exception (&error);
1752 mono_llvm_throw_exception ((MonoObject*)ex);
1755 if (vt->klass->valuetype)
1756 need_unbox_tramp = TRUE;
1758 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1759 m = mono_marshal_get_synchronized_wrapper (m);
1761 addr = compiled_method = mono_compile_method_checked (m, &error);
1762 mono_error_raise_exception (&error);
1765 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1768 * This wastes memory but the memory usage is bounded since
1769 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1770 * this vtable slot so we are not called any more for this instantiation.
1772 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1774 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1776 variant_iface ? variant_iface : generic_virtual, ftndesc);
1781 * mono_init_vtable_slot:
1783 * Initialize slot SLOT of VTABLE.
1784 * Return the contents of the vtable slot.
1787 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1790 gpointer arg = NULL;
1794 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1795 if (mono_error_set_pending_exception (&error))
1797 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1800 mono_memory_barrier ();
1802 vtable->vtable [slot] = ftnptr;
1808 * mono_llvmonly_init_delegate:
1810 * Initialize a MonoDelegate object.
1811 * Similar to mono_delegate_ctor ().
1814 mono_llvmonly_init_delegate (MonoDelegate *del)
1817 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1820 * We store a MonoFtnDesc in del->method_code.
1821 * It would be better to store an ftndesc in del->method_ptr too,
1822 * but we don't have a a structure which could own its memory.
1824 if (G_UNLIKELY (!ftndesc)) {
1825 MonoMethod *m = del->method;
1826 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1827 m = mono_marshal_get_synchronized_wrapper (m);
1829 gpointer addr = mono_compile_method_checked (m, &error);
1830 if (mono_error_set_pending_exception (&error))
1833 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1834 addr = mono_aot_get_unbox_trampoline (m);
1836 gpointer arg = mini_get_delegate_arg (del->method, addr);
1838 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1839 mono_memory_barrier ();
1840 *del->method_code = (gpointer)ftndesc;
1842 del->method_ptr = ftndesc->addr;
1843 del->extra_arg = ftndesc->arg;
1847 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1853 method = mono_object_get_virtual_method (target, method);
1855 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1856 method = mono_marshal_get_synchronized_wrapper (method);
1858 del->method = method;
1859 del->method_ptr = mono_compile_method_checked (method, &error);
1860 if (mono_error_set_pending_exception (&error))
1862 if (method->klass->valuetype)
1863 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1864 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1868 mono_get_assembly_object (MonoImage *image)
1871 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, &error));
1872 ICALL_RETURN_OBJ (result);
1876 mono_get_method_object (MonoMethod *method)
1879 MonoObject * result;
1880 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1881 mono_error_set_pending_exception (&error);
1886 mono_ckfinite (double d)
1888 if (isinf (d) || isnan (d))
1889 mono_set_pending_exception (mono_get_exception_arithmetic ());
1894 * mono_interruption_checkpoint_from_trampoline:
1896 * Check whenever the thread has a pending exception, and throw it
1898 * Architectures should move away from calling this function and
1899 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1900 * rewrind to the parent frame, and throw the exception normally.
1903 mono_interruption_checkpoint_from_trampoline (void)
1907 ex = mono_thread_force_interruption_checkpoint_noraise ();
1909 mono_raise_exception (ex);
1913 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1915 char *caller_name = mono_method_get_reflection_name (caller);
1916 char *callee_name = mono_method_get_reflection_name (callee);
1919 error_init (&error);
1920 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1921 mono_error_set_pending_exception (&error);
1922 g_free (callee_name);
1923 g_free (caller_name);
1927 mono_dummy_jit_icall (void)