2 * jit-icalls.c: internal calls used by the JIT
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2002 Ximian, Inc.
9 * Copyright 2003-2011 Novell Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "jit-icalls.h"
21 #include <mono/utils/mono-error-internals.h>
22 #include <mono/metadata/exception-internals.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/reflection-internals.h>
27 #include "mini-llvm-cpp.h"
31 mono_ldftn (MonoMethod *method)
37 // FIXME: No error handling
39 addr = mono_compile_method_checked (method, &error);
40 mono_error_assert_ok (&error);
43 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
44 /* The caller doesn't pass it */
45 g_assert_not_reached ();
47 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
51 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
52 if (!mono_error_ok (&error)) {
53 mono_error_set_pending_exception (&error);
56 return mono_create_ftnptr (mono_domain_get (), addr);
60 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
66 mono_set_pending_exception (mono_get_exception_null_reference ());
70 res = mono_object_get_virtual_method (obj, method);
72 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
73 MonoGenericContext context = { NULL, NULL };
75 if (res->klass->generic_class)
76 context.class_inst = res->klass->generic_class->context.class_inst;
77 else if (res->klass->generic_container)
78 context.class_inst = res->klass->generic_container->context.class_inst;
79 context.method_inst = mono_method_get_context (method)->method_inst;
81 res = mono_class_inflate_generic_method_checked (res, &context, &error);
82 if (!mono_error_ok (&error)) {
83 mono_error_set_pending_exception (&error);
88 /* An rgctx wrapper is added by the trampolines no need to do it here */
90 return mono_ldftn (res);
94 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
96 return ldvirtfn_internal (obj, method, FALSE);
100 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
102 return ldvirtfn_internal (obj, method, TRUE);
106 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
110 mono_set_pending_exception (mono_get_exception_null_reference ());
113 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
114 if (mono_error_set_pending_exception (&error))
116 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
121 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
124 mono_llmult (gint64 a, gint64 b)
130 mono_llmult_ovf_un (guint64 a, guint64 b)
133 guint32 ah = a >> 32;
135 guint32 bh = b >> 32;
138 // fixme: this is incredible slow
141 goto raise_exception;
143 res = (guint64)al * (guint64)bl;
145 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
148 goto raise_exception;
150 res += ((guint64)t1) << 32;
155 mono_set_pending_exception (mono_get_exception_overflow ());
160 mono_llmult_ovf (gint64 a, gint64 b)
167 Use Karatsuba algorithm where:
168 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
169 where Ah is the "high half" (most significant 32 bits) of a and
170 where Al is the "low half" (least significant 32 bits) of a and
171 where Bh is the "high half" of b and Bl is the "low half" and
172 where R is the Radix or "size of the half" (in our case 32 bits)
174 Note, for the product of two 64 bit numbers to fit into a 64
175 result, ah and/or bh must be 0. This will save us from doing
176 the AhBh term at all.
178 Also note that we refactor so that we don't overflow 64 bits with
179 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
185 /* need to work with absoulte values, so find out what the
186 resulting sign will be and convert any negative numbers
187 from two's complement
191 if (((guint32)ah == 0x80000000) && (al == 0)) {
192 /* This has no two's complement */
198 goto raise_exception;
201 /* flip the bits and add 1 */
212 if (((guint32)bh == 0x80000000) && (bl == 0)) {
213 /* This has no two's complement */
219 goto raise_exception;
222 /* flip the bits and add 1 */
232 /* we overflow for sure if both upper halves are greater
233 than zero because we would need to shift their
234 product 64 bits to the left and that will not fit
235 in a 64 bit result */
237 goto raise_exception;
238 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
239 goto raise_exception;
241 /* do the AlBl term first */
242 t1 = (gint64)al * (gint64)bl;
246 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
247 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
248 /* check for overflow */
250 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
251 goto raise_exception;
256 goto raise_exception;
264 mono_set_pending_exception (mono_get_exception_overflow ());
269 mono_lldiv (gint64 a, gint64 b)
271 #ifdef MONO_ARCH_NEED_DIV_CHECK
273 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
276 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
277 mono_set_pending_exception (mono_get_exception_arithmetic ());
285 mono_llrem (gint64 a, gint64 b)
287 #ifdef MONO_ARCH_NEED_DIV_CHECK
289 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
292 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
293 mono_set_pending_exception (mono_get_exception_arithmetic ());
301 mono_lldiv_un (guint64 a, guint64 b)
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
305 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
313 mono_llrem_un (guint64 a, guint64 b)
315 #ifdef MONO_ARCH_NEED_DIV_CHECK
317 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
326 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
329 mono_lshl (guint64 a, gint32 shamt)
333 res = a << (shamt & 0x7f);
335 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
341 mono_lshr_un (guint64 a, gint32 shamt)
345 res = a >> (shamt & 0x7f);
347 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
353 mono_lshr (gint64 a, gint32 shamt)
357 res = a >> (shamt & 0x7f);
359 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
366 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
369 mono_idiv (gint32 a, gint32 b)
371 #ifdef MONO_ARCH_NEED_DIV_CHECK
373 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
376 else if (b == -1 && a == (0x80000000)) {
377 mono_set_pending_exception (mono_get_exception_overflow ());
385 mono_idiv_un (guint32 a, guint32 b)
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
389 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
397 mono_irem (gint32 a, gint32 b)
399 #ifdef MONO_ARCH_NEED_DIV_CHECK
401 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
404 else if (b == -1 && a == (0x80000000)) {
405 mono_set_pending_exception (mono_get_exception_overflow ());
413 mono_irem_un (guint32 a, guint32 b)
415 #ifdef MONO_ARCH_NEED_DIV_CHECK
417 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
426 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
429 mono_imul (gint32 a, gint32 b)
435 mono_imul_ovf (gint32 a, gint32 b)
439 res = (gint64)a * (gint64)b;
441 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
442 mono_set_pending_exception (mono_get_exception_overflow ());
450 mono_imul_ovf_un (guint32 a, guint32 b)
454 res = (guint64)a * (guint64)b;
457 mono_set_pending_exception (mono_get_exception_overflow ());
465 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
467 mono_fdiv (double a, double b)
473 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
476 mono_fsub (double a, double b)
482 mono_fadd (double a, double b)
488 mono_fmul (double a, double b)
500 mono_fconv_r4 (double a)
506 mono_conv_to_r8 (int a)
512 mono_conv_to_r4 (int a)
514 return (double)(float)a;
518 mono_fconv_i1 (double a)
524 mono_fconv_i2 (double a)
530 mono_fconv_i4 (double a)
536 mono_fconv_u1 (double a)
542 mono_fconv_u2 (double a)
548 mono_fcmp_eq (double a, double b)
554 mono_fcmp_ge (double a, double b)
560 mono_fcmp_gt (double a, double b)
566 mono_fcmp_le (double a, double b)
572 mono_fcmp_lt (double a, double b)
578 mono_fcmp_ne_un (double a, double b)
580 return isunordered (a, b) || a != b;
584 mono_fcmp_ge_un (double a, double b)
586 return isunordered (a, b) || a >= b;
590 mono_fcmp_gt_un (double a, double b)
592 return isunordered (a, b) || a > b;
596 mono_fcmp_le_un (double a, double b)
598 return isunordered (a, b) || a <= b;
602 mono_fcmp_lt_un (double a, double b)
604 return isunordered (a, b) || a < b;
608 mono_fceq (double a, double b)
614 mono_fcgt (double a, double b)
620 mono_fcgt_un (double a, double b)
622 return isunordered (a, b) || a > b;
626 mono_fclt (double a, double b)
632 mono_fclt_un (double a, double b)
634 return isunordered (a, b) || a < b;
638 mono_isfinite (double a)
643 g_assert_not_reached ();
649 mono_fload_r4 (float *ptr)
655 mono_fstore_r4 (double val, float *ptr)
660 /* returns the integer bitpattern that is passed in the regs or stack */
662 mono_fload_r4_arg (double val)
664 float v = (float)val;
665 return *(guint32*)&v;
671 mono_array_new_va (MonoMethod *cm, ...)
675 MonoDomain *domain = mono_domain_get ();
678 intptr_t *lower_bounds;
683 pcount = mono_method_signature (cm)->param_count;
684 rank = cm->klass->rank;
688 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
689 for (i = 0; i < pcount; ++i)
690 lengths [i] = d = va_arg(ap, int);
692 if (rank == pcount) {
693 /* Only lengths provided. */
694 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
695 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
696 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
701 g_assert (pcount == (rank * 2));
702 /* lower bounds are first. */
703 lower_bounds = (intptr_t*)lengths;
708 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
710 if (!mono_error_ok (&error)) {
711 mono_error_set_pending_exception (&error);
718 /* Specialized version of mono_array_new_va () which avoids varargs */
720 mono_array_new_1 (MonoMethod *cm, guint32 length)
724 MonoDomain *domain = mono_domain_get ();
725 uintptr_t lengths [1];
726 intptr_t *lower_bounds;
730 pcount = mono_method_signature (cm)->param_count;
731 rank = cm->klass->rank;
733 lengths [0] = length;
735 g_assert (rank == pcount);
737 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
738 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
739 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
744 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
746 if (!mono_error_ok (&error)) {
747 mono_error_set_pending_exception (&error);
755 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
759 MonoDomain *domain = mono_domain_get ();
760 uintptr_t lengths [2];
761 intptr_t *lower_bounds;
765 pcount = mono_method_signature (cm)->param_count;
766 rank = cm->klass->rank;
768 lengths [0] = length1;
769 lengths [1] = length2;
771 g_assert (rank == pcount);
773 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
774 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
775 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
780 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
782 if (!mono_error_ok (&error)) {
783 mono_error_set_pending_exception (&error);
791 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
795 MonoDomain *domain = mono_domain_get ();
796 uintptr_t lengths [3];
797 intptr_t *lower_bounds;
801 pcount = mono_method_signature (cm)->param_count;
802 rank = cm->klass->rank;
804 lengths [0] = length1;
805 lengths [1] = length2;
806 lengths [2] = length3;
808 g_assert (rank == pcount);
810 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
811 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
812 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
817 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
819 if (!mono_error_ok (&error)) {
820 mono_error_set_pending_exception (&error);
828 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
832 MonoDomain *domain = mono_domain_get ();
833 uintptr_t lengths [4];
834 intptr_t *lower_bounds;
838 pcount = mono_method_signature (cm)->param_count;
839 rank = cm->klass->rank;
841 lengths [0] = length1;
842 lengths [1] = length2;
843 lengths [2] = length3;
844 lengths [3] = length4;
846 g_assert (rank == pcount);
848 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
849 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
850 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
855 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
857 if (!mono_error_ok (&error)) {
858 mono_error_set_pending_exception (&error);
866 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
872 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
874 mono_class_init (field->parent);
876 vtable = mono_class_vtable_full (domain, field->parent, &error);
877 if (!is_ok (&error)) {
878 mono_error_set_pending_exception (&error);
881 if (!vtable->initialized) {
882 if (!mono_runtime_class_init_full (vtable, &error)) {
883 mono_error_set_pending_exception (&error);
888 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
890 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
891 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
893 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
899 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
902 MonoClass *handle_class;
905 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
906 if (!mono_error_ok (&error)) {
907 mono_error_set_pending_exception (&error);
910 mono_class_init (handle_class);
916 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
918 MonoMethodSignature *sig = mono_method_signature (method);
919 MonoGenericContext *generic_context;
921 if (sig->is_inflated) {
922 generic_context = mono_method_get_context (method);
924 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
925 g_assert (generic_container);
926 generic_context = &generic_container->context;
929 return mono_ldtoken_wrapper (image, token, generic_context);
933 mono_fconv_u8 (double v)
939 mono_rconv_u8 (float v)
944 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
946 mono_fconv_i8 (double v)
953 mono_fconv_u4 (double v)
955 /* MS.NET behaves like this for some reason */
957 if (isinf (v) || isnan (v))
965 /* Solaris doesn't have trunc */
967 extern long double aintl (long double);
970 /* FIXME: This means we will never throw overflow exceptions */
973 #endif /* HAVE_TRUNC */
976 mono_fconv_ovf_i8 (double v)
982 if (isnan(v) || trunc (v) != res) {
983 mono_set_pending_exception (mono_get_exception_overflow ());
990 mono_fconv_ovf_u8 (double v)
995 * The soft-float implementation of some ARM devices have a buggy guin64 to double
996 * conversion that it looses precision even when the integer if fully representable
999 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1001 * To work around this issue we test for value boundaries instead.
1003 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1004 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1005 mono_set_pending_exception (mono_get_exception_overflow ());
1011 if (isnan(v) || trunc (v) != res) {
1012 mono_set_pending_exception (mono_get_exception_overflow ());
1019 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1021 mono_rconv_i8 (float v)
1028 mono_rconv_ovf_i8 (float v)
1034 if (isnan(v) || trunc (v) != res) {
1035 mono_set_pending_exception (mono_get_exception_overflow ());
1042 mono_rconv_ovf_u8 (float v)
1047 if (isnan(v) || trunc (v) != res) {
1048 mono_set_pending_exception (mono_get_exception_overflow ());
1054 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1056 mono_lconv_to_r8 (gint64 a)
1062 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1064 mono_lconv_to_r4 (gint64 a)
1070 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1072 mono_conv_to_r8_un (guint32 a)
1078 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1080 mono_lconv_to_r8_un (guint64 a)
1086 #if defined(__native_client_codegen__) || defined(__native_client__)
1087 /* When we cross-compile to Native Client we can't directly embed calls */
1088 /* to the math library on the host. This will use the fmod on the target*/
1090 mono_fmod(double a, double b)
1097 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1100 MonoMethod *vmethod;
1102 MonoGenericContext *context = mono_method_get_context (method);
1104 mono_jit_stats.generic_virtual_invocations++;
1107 mono_set_pending_exception (mono_get_exception_null_reference ());
1110 vmethod = mono_object_get_virtual_method (obj, method);
1111 g_assert (!vmethod->klass->generic_container);
1112 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1113 g_assert (!context->method_inst || !context->method_inst->is_open);
1115 addr = mono_compile_method_checked (vmethod, &error);
1116 if (mono_error_set_pending_exception (&error))
1119 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1121 /* Since this is a virtual call, have to unbox vtypes */
1122 if (obj->vtable->klass->valuetype)
1123 *this_arg = mono_object_unbox (obj);
1131 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1134 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1135 mono_error_set_pending_exception (&error);
1140 mono_helper_ldstr (MonoImage *image, guint32 idx)
1143 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1144 mono_error_set_pending_exception (&error);
1149 mono_helper_ldstr_mscorlib (guint32 idx)
1152 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1153 mono_error_set_pending_exception (&error);
1158 mono_helper_newobj_mscorlib (guint32 idx)
1161 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1163 if (!mono_error_ok (&error)) {
1164 mono_error_set_pending_exception (&error);
1168 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1169 if (!mono_error_ok (&error))
1170 mono_error_set_pending_exception (&error);
1175 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1176 * in generated code. So instead we emit a call to this function and place a gdb
1185 mono_create_corlib_exception_0 (guint32 token)
1187 return mono_exception_from_token (mono_defaults.corlib, token);
1191 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1194 MonoException *ret = mono_exception_from_token_two_strings_checked (
1195 mono_defaults.corlib, token, arg, NULL, &error);
1196 mono_error_set_pending_exception (&error);
1201 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1204 MonoException *ret = mono_exception_from_token_two_strings_checked (
1205 mono_defaults.corlib, token, arg1, arg2, &error);
1206 mono_error_set_pending_exception (&error);
1211 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1214 MonoJitTlsData *jit_tls = NULL;
1217 if (mini_get_debug_options ()->better_cast_details) {
1218 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1219 jit_tls->class_cast_from = NULL;
1225 oklass = obj->vtable->klass;
1226 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1228 if (mono_object_isinst_checked (obj, klass, &error))
1230 if (mono_error_set_pending_exception (&error))
1233 if (mini_get_debug_options ()->better_cast_details) {
1234 jit_tls->class_cast_from = oklass;
1235 jit_tls->class_cast_to = klass;
1238 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1239 "System", "InvalidCastException"));
1245 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1248 MonoJitTlsData *jit_tls = NULL;
1249 gpointer cached_vtable, obj_vtable;
1251 if (mini_get_debug_options ()->better_cast_details) {
1252 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1253 jit_tls->class_cast_from = NULL;
1259 cached_vtable = *cache;
1260 obj_vtable = obj->vtable;
1262 if (cached_vtable == obj_vtable)
1265 if (mono_object_isinst_checked (obj, klass, &error)) {
1266 *cache = obj_vtable;
1269 if (mono_error_set_pending_exception (&error))
1272 if (mini_get_debug_options ()->better_cast_details) {
1273 jit_tls->class_cast_from = obj->vtable->klass;
1274 jit_tls->class_cast_to = klass;
1277 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1278 "System", "InvalidCastException"));
1284 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1287 size_t cached_vtable, obj_vtable;
1292 cached_vtable = (size_t)*cache;
1293 obj_vtable = (size_t)obj->vtable;
1295 if ((cached_vtable & ~0x1) == obj_vtable) {
1296 return (cached_vtable & 0x1) ? NULL : obj;
1299 if (mono_object_isinst_checked (obj, klass, &error)) {
1300 *cache = (gpointer)obj_vtable;
1303 if (mono_error_set_pending_exception (&error))
1306 *cache = (gpointer)(obj_vtable | 0x1);
1312 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1315 MonoMarshalSpec **mspecs;
1316 MonoMethodPInvoke piinfo;
1319 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1320 memset (&piinfo, 0, sizeof (piinfo));
1322 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1324 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1325 mono_error_set_pending_exception (&error);
1326 return compiled_ptr;
1330 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1333 int vt_slot, iface_offset;
1335 mono_error_init (error);
1337 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1338 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 (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
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)
1372 * Calling a vtype method with a vtype receiver
1377 * Calling a non-vtype method
1379 *this_arg = *(gpointer*)mp;
1384 * mono_gsharedvt_constrained_call:
1386 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1387 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1390 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1396 gpointer new_args [16];
1398 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1399 if (!mono_error_ok (&error)) {
1400 mono_error_set_pending_exception (&error);
1406 if (args && deref_arg) {
1407 new_args [0] = *(gpointer*)args [0];
1410 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1411 /* Object.GetType () */
1413 args [0] = this_arg;
1417 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1418 if (!mono_error_ok (&error)) {
1419 mono_error_set_pending_exception (&error);
1427 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1429 if (klass->valuetype)
1430 mono_value_copy (dest, src, klass);
1432 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1436 ves_icall_runtime_class_init (MonoVTable *vtable)
1438 MONO_REQ_GC_UNSAFE_MODE;
1441 mono_runtime_class_init_full (vtable, &error);
1442 mono_error_set_pending_exception (&error);
1447 mono_generic_class_init (MonoVTable *vtable)
1450 mono_runtime_class_init_full (vtable, &error);
1451 mono_error_set_pending_exception (&error);
1455 ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
1458 mono_delegate_ctor (this_obj, target, addr, &error);
1459 mono_error_set_pending_exception (&error);
1463 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1468 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1469 if (!mono_error_ok (&error)) {
1470 mono_error_set_pending_exception (&error);
1477 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1482 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1483 if (!mono_error_ok (&error)) {
1484 mono_error_set_pending_exception (&error);
1491 * resolve_iface_call:
1493 * Return the executable code for the iface method IMT_METHOD called on THIS.
1494 * This function is called on a slowpath, so it doesn't need to be fast.
1495 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1499 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1502 gpointer *imt, *vtable_slot;
1503 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1504 gpointer addr, compiled_method, aot_addr;
1505 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1507 mono_error_init (error);
1509 /* The caller will handle it */
1512 vt = this_obj->vtable;
1513 imt = (gpointer*)vt - MONO_IMT_SIZE;
1515 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
1516 return_val_if_nok (error, NULL);
1518 // FIXME: This can throw exceptions
1519 addr = compiled_method = mono_compile_method_checked (impl_method, error);
1520 mono_error_assert_ok (error);
1523 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1524 generic_virtual = imt_method;
1526 if (generic_virtual || variant_iface) {
1527 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1528 need_unbox_tramp = TRUE;
1530 if (impl_method->klass->valuetype)
1531 need_unbox_tramp = TRUE;
1534 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1536 if (generic_virtual || variant_iface) {
1537 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1539 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1548 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1551 gpointer res = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, &error);
1552 if (!is_ok (&error)) {
1553 MonoException *ex = mono_error_convert_to_exception (&error);
1554 mono_llvm_throw_exception ((MonoObject*)ex);
1560 is_generic_method_definition (MonoMethod *m)
1562 MonoGenericContext *context;
1565 if (!m->is_inflated)
1568 context = mono_method_get_context (m);
1569 if (!context->method_inst)
1571 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1579 * Return the executable code for calling vt->vtable [slot].
1580 * This function is called on a slowpath, so it doesn't need to be fast.
1581 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1585 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt, MonoError *error)
1587 MonoMethod *m, *generic_virtual = NULL;
1588 gpointer addr, compiled_method;
1589 gboolean need_unbox_tramp = FALSE;
1591 mono_error_init (error);
1592 /* Same as in common_call_trampoline () */
1594 /* Avoid loading metadata or creating a generic vtable if possible */
1595 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot, error);
1596 return_val_if_nok (error, NULL);
1597 if (addr && !vt->klass->valuetype)
1598 return mono_create_ftnptr (mono_domain_get (), addr);
1600 m = mono_class_get_vtable_entry (vt->klass, slot);
1602 if (is_generic_method_definition (m)) {
1603 MonoGenericContext context = { NULL, NULL };
1604 MonoMethod *declaring;
1607 declaring = mono_method_get_declaring_generic_method (m);
1611 if (m->klass->generic_class)
1612 context.class_inst = m->klass->generic_class->context.class_inst;
1614 g_assert (!m->klass->generic_container);
1616 generic_virtual = imt_method;
1617 g_assert (generic_virtual);
1618 g_assert (generic_virtual->is_inflated);
1619 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1621 m = mono_class_inflate_generic_method_checked (declaring, &context, error);
1622 mono_error_assert_ok (error); /* FIXME don't swallow the error */
1625 if (generic_virtual) {
1626 if (vt->klass->valuetype)
1627 need_unbox_tramp = TRUE;
1629 if (m->klass->valuetype)
1630 need_unbox_tramp = TRUE;
1633 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1634 m = mono_marshal_get_synchronized_wrapper (m);
1636 // FIXME: This can throw exceptions
1637 addr = compiled_method = mono_compile_method_checked (m, error);
1638 mono_error_assert_ok (error);
1641 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1643 if (!gsharedvt && generic_virtual) {
1644 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1645 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1647 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1648 vt, vt->vtable + slot,
1649 generic_virtual, ftndesc);
1656 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1658 g_assert (this_obj);
1661 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1662 if (!is_ok (&error)) {
1663 MonoException *ex = mono_error_convert_to_exception (&error);
1664 mono_llvm_throw_exception ((MonoObject*)ex);
1670 * mono_resolve_generic_virtual_call:
1672 * Resolve a generic virtual call.
1673 * This function is called on a slowpath, so it doesn't need to be fast.
1676 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1679 gpointer addr, compiled_method;
1680 gboolean need_unbox_tramp = FALSE;
1682 MonoGenericContext context = { NULL, NULL };
1683 MonoMethod *declaring;
1684 gpointer arg = NULL;
1686 m = mono_class_get_vtable_entry (vt->klass, slot);
1688 g_assert (is_generic_method_definition (m));
1691 declaring = mono_method_get_declaring_generic_method (m);
1695 if (m->klass->generic_class)
1696 context.class_inst = m->klass->generic_class->context.class_inst;
1698 g_assert (!m->klass->generic_container);
1700 g_assert (generic_virtual->is_inflated);
1701 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1703 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1704 g_assert (mono_error_ok (&error));
1706 if (vt->klass->valuetype)
1707 need_unbox_tramp = TRUE;
1709 // FIXME: This can throw exceptions
1710 addr = compiled_method = mono_compile_method_checked (m, &error);
1711 mono_error_assert_ok (&error);
1714 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1717 * This wastes memory but the memory usage is bounded since
1718 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1719 * this vtable slot so we are not called any more for this instantiation.
1721 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1723 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1724 vt, vt->vtable + slot,
1725 generic_virtual, ftndesc);
1730 * mono_resolve_generic_virtual_call:
1732 * Resolve a generic virtual/variant iface call on interfaces.
1733 * This function is called on a slowpath, so it doesn't need to be fast.
1736 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1739 MonoMethod *m, *variant_iface;
1740 gpointer addr, aot_addr, compiled_method;
1741 gboolean need_unbox_tramp = FALSE;
1742 gboolean need_rgctx_tramp;
1743 gpointer arg = NULL;
1746 imt = (gpointer*)vt - MONO_IMT_SIZE;
1748 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1749 if (!is_ok (&error)) {
1750 MonoException *ex = mono_error_convert_to_exception (&error);
1751 mono_llvm_throw_exception ((MonoObject*)ex);
1754 if (vt->klass->valuetype)
1755 need_unbox_tramp = TRUE;
1757 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1758 m = mono_marshal_get_synchronized_wrapper (m);
1760 addr = compiled_method = mono_compile_method_checked (m, &error);
1761 mono_error_raise_exception (&error);
1764 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1767 * This wastes memory but the memory usage is bounded since
1768 * mono_method_add_generic_virtual_invocation () eventually builds an imt trampoline for
1769 * this vtable slot so we are not called any more for this instantiation.
1771 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1773 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1775 variant_iface ? variant_iface : generic_virtual, ftndesc);
1780 * mono_init_vtable_slot:
1782 * Initialize slot SLOT of VTABLE.
1783 * Return the contents of the vtable slot.
1786 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1789 gpointer arg = NULL;
1793 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1794 if (mono_error_set_pending_exception (&error))
1796 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1799 mono_memory_barrier ();
1801 vtable->vtable [slot] = ftnptr;
1807 * mono_llvmonly_init_delegate:
1809 * Initialize a MonoDelegate object.
1810 * Similar to mono_delegate_ctor ().
1813 mono_llvmonly_init_delegate (MonoDelegate *del)
1816 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1819 * We store a MonoFtnDesc in del->method_code.
1820 * It would be better to store an ftndesc in del->method_ptr too,
1821 * but we don't have a a structure which could own its memory.
1823 if (G_UNLIKELY (!ftndesc)) {
1824 MonoMethod *m = del->method;
1825 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1826 m = mono_marshal_get_synchronized_wrapper (m);
1828 gpointer addr = mono_compile_method_checked (m, &error);
1829 if (mono_error_set_pending_exception (&error))
1832 if (m->klass->valuetype && mono_method_signature (m)->hasthis)
1833 addr = mono_aot_get_unbox_trampoline (m);
1835 gpointer arg = mini_get_delegate_arg (del->method, addr);
1837 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1838 mono_memory_barrier ();
1839 *del->method_code = (gpointer)ftndesc;
1841 del->method_ptr = ftndesc->addr;
1842 del->extra_arg = ftndesc->arg;
1846 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1852 method = mono_object_get_virtual_method (target, method);
1854 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1855 method = mono_marshal_get_synchronized_wrapper (method);
1857 del->method = method;
1858 del->method_ptr = mono_compile_method_checked (method, &error);
1859 if (mono_error_set_pending_exception (&error))
1861 if (method->klass->valuetype)
1862 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1863 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1867 mono_get_assembly_object (MonoImage *image)
1871 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1873 mono_error_set_pending_exception (&error);
1878 mono_get_method_object (MonoMethod *method)
1881 MonoObject * result;
1882 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1883 mono_error_set_pending_exception (&error);
1888 mono_ckfinite (double d)
1890 if (isinf (d) || isnan (d))
1891 mono_set_pending_exception (mono_get_exception_arithmetic ());
1896 * mono_interruption_checkpoint_from_trampoline:
1898 * Check whenever the thread has a pending exception, and throw it
1900 * Architectures should move away from calling this function and
1901 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1902 * rewrind to the parent frame, and throw the exception normally.
1905 mono_interruption_checkpoint_from_trampoline (void)
1909 ex = mono_thread_force_interruption_checkpoint_noraise ();
1911 mono_raise_exception (ex);
1915 mono_throw_method_access (MonoMethod *callee, MonoMethod *caller)
1917 char *callee_name = mono_method_full_name (callee, 1);
1918 char *caller_name = mono_method_full_name (caller, 1);
1921 mono_error_init (&error);
1922 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", callee_name, caller_name);
1923 mono_error_set_pending_exception (&error);
1924 g_free (callee_name);
1925 g_free (caller_name);
1929 mono_dummy_jit_icall (void)