3 * internal calls used by the JIT
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2002 Ximian, Inc.
10 * Copyright 2003-2011 Novell Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include "jit-icalls.h"
22 #include <mono/utils/mono-error-internals.h>
23 #include <mono/metadata/exception-internals.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/reflection-internals.h>
28 #include "mini-llvm-cpp.h"
32 mono_ldftn (MonoMethod *method)
38 // FIXME: No error handling
40 addr = mono_compile_method_checked (method, &error);
41 mono_error_assert_ok (&error);
44 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
45 /* The caller doesn't pass it */
46 g_assert_not_reached ();
48 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
52 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
53 if (!mono_error_ok (&error)) {
54 mono_error_set_pending_exception (&error);
57 return mono_create_ftnptr (mono_domain_get (), addr);
61 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
67 mono_set_pending_exception (mono_get_exception_null_reference ());
71 res = mono_object_get_virtual_method (obj, method);
73 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
74 MonoGenericContext context = { NULL, NULL };
76 if (mono_class_is_ginst (res->klass))
77 context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
78 else if (mono_class_is_gtd (res->klass))
79 context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
80 context.method_inst = mono_method_get_context (method)->method_inst;
82 res = mono_class_inflate_generic_method_checked (res, &context, &error);
83 if (!mono_error_ok (&error)) {
84 mono_error_set_pending_exception (&error);
89 /* An rgctx wrapper is added by the trampolines no need to do it here */
91 return mono_ldftn (res);
95 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
97 return ldvirtfn_internal (obj, method, FALSE);
101 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
103 return ldvirtfn_internal (obj, method, TRUE);
107 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
111 mono_set_pending_exception (mono_get_exception_null_reference ());
114 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
115 if (mono_error_set_pending_exception (&error))
117 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
122 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
125 mono_llmult (gint64 a, gint64 b)
131 mono_llmult_ovf_un (guint64 a, guint64 b)
134 guint32 ah = a >> 32;
136 guint32 bh = b >> 32;
139 // fixme: this is incredible slow
142 goto raise_exception;
144 res = (guint64)al * (guint64)bl;
146 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
149 goto raise_exception;
151 res += ((guint64)t1) << 32;
156 mono_set_pending_exception (mono_get_exception_overflow ());
161 mono_llmult_ovf (gint64 a, gint64 b)
168 Use Karatsuba algorithm where:
169 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
170 where Ah is the "high half" (most significant 32 bits) of a and
171 where Al is the "low half" (least significant 32 bits) of a and
172 where Bh is the "high half" of b and Bl is the "low half" and
173 where R is the Radix or "size of the half" (in our case 32 bits)
175 Note, for the product of two 64 bit numbers to fit into a 64
176 result, ah and/or bh must be 0. This will save us from doing
177 the AhBh term at all.
179 Also note that we refactor so that we don't overflow 64 bits with
180 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
186 /* need to work with absoulte values, so find out what the
187 resulting sign will be and convert any negative numbers
188 from two's complement
192 if (((guint32)ah == 0x80000000) && (al == 0)) {
193 /* This has no two's complement */
199 goto raise_exception;
202 /* flip the bits and add 1 */
213 if (((guint32)bh == 0x80000000) && (bl == 0)) {
214 /* This has no two's complement */
220 goto raise_exception;
223 /* flip the bits and add 1 */
233 /* we overflow for sure if both upper halves are greater
234 than zero because we would need to shift their
235 product 64 bits to the left and that will not fit
236 in a 64 bit result */
238 goto raise_exception;
239 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
240 goto raise_exception;
242 /* do the AlBl term first */
243 t1 = (gint64)al * (gint64)bl;
247 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
248 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
249 /* check for overflow */
251 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
252 goto raise_exception;
257 goto raise_exception;
265 mono_set_pending_exception (mono_get_exception_overflow ());
270 mono_lldiv (gint64 a, gint64 b)
272 #ifdef MONO_ARCH_NEED_DIV_CHECK
274 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
277 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
278 mono_set_pending_exception (mono_get_exception_arithmetic ());
286 mono_llrem (gint64 a, gint64 b)
288 #ifdef MONO_ARCH_NEED_DIV_CHECK
290 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
293 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
294 mono_set_pending_exception (mono_get_exception_arithmetic ());
302 mono_lldiv_un (guint64 a, guint64 b)
304 #ifdef MONO_ARCH_NEED_DIV_CHECK
306 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
314 mono_llrem_un (guint64 a, guint64 b)
316 #ifdef MONO_ARCH_NEED_DIV_CHECK
318 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
327 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
330 mono_lshl (guint64 a, gint32 shamt)
334 res = a << (shamt & 0x7f);
336 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
342 mono_lshr_un (guint64 a, gint32 shamt)
346 res = a >> (shamt & 0x7f);
348 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
354 mono_lshr (gint64 a, gint32 shamt)
358 res = a >> (shamt & 0x7f);
360 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
367 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
370 mono_idiv (gint32 a, gint32 b)
372 #ifdef MONO_ARCH_NEED_DIV_CHECK
374 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
377 else if (b == -1 && a == (0x80000000)) {
378 mono_set_pending_exception (mono_get_exception_overflow ());
386 mono_idiv_un (guint32 a, guint32 b)
388 #ifdef MONO_ARCH_NEED_DIV_CHECK
390 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
398 mono_irem (gint32 a, gint32 b)
400 #ifdef MONO_ARCH_NEED_DIV_CHECK
402 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
405 else if (b == -1 && a == (0x80000000)) {
406 mono_set_pending_exception (mono_get_exception_overflow ());
414 mono_irem_un (guint32 a, guint32 b)
416 #ifdef MONO_ARCH_NEED_DIV_CHECK
418 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
427 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
430 mono_imul (gint32 a, gint32 b)
436 mono_imul_ovf (gint32 a, gint32 b)
440 res = (gint64)a * (gint64)b;
442 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
443 mono_set_pending_exception (mono_get_exception_overflow ());
451 mono_imul_ovf_un (guint32 a, guint32 b)
455 res = (guint64)a * (guint64)b;
458 mono_set_pending_exception (mono_get_exception_overflow ());
466 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
468 mono_fdiv (double a, double b)
474 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
477 mono_fsub (double a, double b)
483 mono_fadd (double a, double b)
489 mono_fmul (double a, double b)
501 mono_fconv_r4 (double a)
507 mono_conv_to_r8 (int a)
513 mono_conv_to_r4 (int a)
515 return (double)(float)a;
519 mono_fconv_i1 (double a)
525 mono_fconv_i2 (double a)
531 mono_fconv_i4 (double a)
537 mono_fconv_u1 (double a)
543 mono_fconv_u2 (double a)
549 mono_fcmp_eq (double a, double b)
555 mono_fcmp_ge (double a, double b)
561 mono_fcmp_gt (double a, double b)
567 mono_fcmp_le (double a, double b)
573 mono_fcmp_lt (double a, double b)
579 mono_fcmp_ne_un (double a, double b)
581 return isunordered (a, b) || a != b;
585 mono_fcmp_ge_un (double a, double b)
587 return isunordered (a, b) || a >= b;
591 mono_fcmp_gt_un (double a, double b)
593 return isunordered (a, b) || a > b;
597 mono_fcmp_le_un (double a, double b)
599 return isunordered (a, b) || a <= b;
603 mono_fcmp_lt_un (double a, double b)
605 return isunordered (a, b) || a < b;
609 mono_fceq (double a, double b)
615 mono_fcgt (double a, double b)
621 mono_fcgt_un (double a, double b)
623 return isunordered (a, b) || a > b;
627 mono_fclt (double a, double b)
633 mono_fclt_un (double a, double b)
635 return isunordered (a, b) || a < b;
639 mono_isfinite (double a)
644 g_assert_not_reached ();
650 mono_fload_r4 (float *ptr)
656 mono_fstore_r4 (double val, float *ptr)
661 /* returns the integer bitpattern that is passed in the regs or stack */
663 mono_fload_r4_arg (double val)
665 float v = (float)val;
666 return *(guint32*)&v;
672 mono_array_new_va (MonoMethod *cm, ...)
676 MonoDomain *domain = mono_domain_get ();
679 intptr_t *lower_bounds;
684 pcount = mono_method_signature (cm)->param_count;
685 rank = cm->klass->rank;
689 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
690 for (i = 0; i < pcount; ++i)
691 lengths [i] = d = va_arg(ap, int);
693 if (rank == pcount) {
694 /* Only lengths provided. */
695 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
696 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
697 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
702 g_assert (pcount == (rank * 2));
703 /* lower bounds are first. */
704 lower_bounds = (intptr_t*)lengths;
709 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
711 if (!mono_error_ok (&error)) {
712 mono_error_set_pending_exception (&error);
719 /* Specialized version of mono_array_new_va () which avoids varargs */
721 mono_array_new_1 (MonoMethod *cm, guint32 length)
725 MonoDomain *domain = mono_domain_get ();
726 uintptr_t lengths [1];
727 intptr_t *lower_bounds;
731 pcount = mono_method_signature (cm)->param_count;
732 rank = cm->klass->rank;
734 lengths [0] = length;
736 g_assert (rank == pcount);
738 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
739 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
740 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
745 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
747 if (!mono_error_ok (&error)) {
748 mono_error_set_pending_exception (&error);
756 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
760 MonoDomain *domain = mono_domain_get ();
761 uintptr_t lengths [2];
762 intptr_t *lower_bounds;
766 pcount = mono_method_signature (cm)->param_count;
767 rank = cm->klass->rank;
769 lengths [0] = length1;
770 lengths [1] = length2;
772 g_assert (rank == pcount);
774 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
775 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
776 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
781 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
783 if (!mono_error_ok (&error)) {
784 mono_error_set_pending_exception (&error);
792 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
796 MonoDomain *domain = mono_domain_get ();
797 uintptr_t lengths [3];
798 intptr_t *lower_bounds;
802 pcount = mono_method_signature (cm)->param_count;
803 rank = cm->klass->rank;
805 lengths [0] = length1;
806 lengths [1] = length2;
807 lengths [2] = length3;
809 g_assert (rank == pcount);
811 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
812 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
813 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
818 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
820 if (!mono_error_ok (&error)) {
821 mono_error_set_pending_exception (&error);
829 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
833 MonoDomain *domain = mono_domain_get ();
834 uintptr_t lengths [4];
835 intptr_t *lower_bounds;
839 pcount = mono_method_signature (cm)->param_count;
840 rank = cm->klass->rank;
842 lengths [0] = length1;
843 lengths [1] = length2;
844 lengths [2] = length3;
845 lengths [3] = length4;
847 g_assert (rank == pcount);
849 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
850 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
851 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
856 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
858 if (!mono_error_ok (&error)) {
859 mono_error_set_pending_exception (&error);
867 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
873 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
875 mono_class_init (field->parent);
877 vtable = mono_class_vtable_full (domain, field->parent, &error);
878 if (!is_ok (&error)) {
879 mono_error_set_pending_exception (&error);
882 if (!vtable->initialized) {
883 if (!mono_runtime_class_init_full (vtable, &error)) {
884 mono_error_set_pending_exception (&error);
889 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
891 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
892 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
894 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
900 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
903 MonoClass *handle_class;
906 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
907 if (!mono_error_ok (&error)) {
908 mono_error_set_pending_exception (&error);
911 mono_class_init (handle_class);
917 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
919 MonoMethodSignature *sig = mono_method_signature (method);
920 MonoGenericContext *generic_context;
922 if (sig->is_inflated) {
923 generic_context = mono_method_get_context (method);
925 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
926 g_assert (generic_container);
927 generic_context = &generic_container->context;
930 return mono_ldtoken_wrapper (image, token, generic_context);
934 mono_fconv_u8 (double v)
940 mono_rconv_u8 (float v)
945 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
947 mono_fconv_i8 (double v)
954 mono_fconv_u4 (double v)
956 /* MS.NET behaves like this for some reason */
958 if (isinf (v) || isnan (v))
966 /* Solaris doesn't have trunc */
968 extern long double aintl (long double);
971 /* FIXME: This means we will never throw overflow exceptions */
974 #endif /* HAVE_TRUNC */
977 mono_fconv_ovf_i8 (double v)
983 if (isnan(v) || trunc (v) != res) {
984 mono_set_pending_exception (mono_get_exception_overflow ());
991 mono_fconv_ovf_u8 (double v)
996 * The soft-float implementation of some ARM devices have a buggy guin64 to double
997 * conversion that it looses precision even when the integer if fully representable
1000 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1002 * To work around this issue we test for value boundaries instead.
1004 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1005 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1006 mono_set_pending_exception (mono_get_exception_overflow ());
1012 if (isnan(v) || trunc (v) != res) {
1013 mono_set_pending_exception (mono_get_exception_overflow ());
1020 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1022 mono_rconv_i8 (float v)
1029 mono_rconv_ovf_i8 (float v)
1035 if (isnan(v) || trunc (v) != res) {
1036 mono_set_pending_exception (mono_get_exception_overflow ());
1043 mono_rconv_ovf_u8 (float v)
1048 if (isnan(v) || trunc (v) != res) {
1049 mono_set_pending_exception (mono_get_exception_overflow ());
1055 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1057 mono_lconv_to_r8 (gint64 a)
1063 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1065 mono_lconv_to_r4 (gint64 a)
1071 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1073 mono_conv_to_r8_un (guint32 a)
1079 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1081 mono_lconv_to_r8_un (guint64 a)
1087 #if defined(__native_client_codegen__) || defined(__native_client__)
1088 /* When we cross-compile to Native Client we can't directly embed calls */
1089 /* to the math library on the host. This will use the fmod on the target*/
1091 mono_fmod(double a, double b)
1098 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1101 MonoMethod *vmethod;
1103 MonoGenericContext *context = mono_method_get_context (method);
1105 mono_jit_stats.generic_virtual_invocations++;
1108 mono_set_pending_exception (mono_get_exception_null_reference ());
1111 vmethod = mono_object_get_virtual_method (obj, method);
1112 g_assert (!mono_class_is_gtd (vmethod->klass));
1113 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1114 g_assert (!context->method_inst || !context->method_inst->is_open);
1116 addr = mono_compile_method_checked (vmethod, &error);
1117 if (mono_error_set_pending_exception (&error))
1120 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1122 /* Since this is a virtual call, have to unbox vtypes */
1123 if (obj->vtable->klass->valuetype)
1124 *this_arg = mono_object_unbox (obj);
1132 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1135 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1136 mono_error_set_pending_exception (&error);
1141 mono_helper_ldstr (MonoImage *image, guint32 idx)
1144 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1145 mono_error_set_pending_exception (&error);
1150 mono_helper_ldstr_mscorlib (guint32 idx)
1153 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1154 mono_error_set_pending_exception (&error);
1159 mono_helper_newobj_mscorlib (guint32 idx)
1162 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1164 if (!mono_error_ok (&error)) {
1165 mono_error_set_pending_exception (&error);
1169 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1170 if (!mono_error_ok (&error))
1171 mono_error_set_pending_exception (&error);
1176 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1177 * in generated code. So instead we emit a call to this function and place a gdb
1186 mono_create_corlib_exception_0 (guint32 token)
1188 return mono_exception_from_token (mono_defaults.corlib, token);
1192 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1195 MonoException *ret = mono_exception_from_token_two_strings_checked (
1196 mono_defaults.corlib, token, arg, NULL, &error);
1197 mono_error_set_pending_exception (&error);
1202 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1205 MonoException *ret = mono_exception_from_token_two_strings_checked (
1206 mono_defaults.corlib, token, arg1, arg2, &error);
1207 mono_error_set_pending_exception (&error);
1212 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1215 MonoJitTlsData *jit_tls = NULL;
1218 if (mini_get_debug_options ()->better_cast_details) {
1219 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1220 jit_tls->class_cast_from = NULL;
1226 oklass = obj->vtable->klass;
1227 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1229 if (mono_object_isinst_checked (obj, klass, &error))
1231 if (mono_error_set_pending_exception (&error))
1234 if (mini_get_debug_options ()->better_cast_details) {
1235 jit_tls->class_cast_from = oklass;
1236 jit_tls->class_cast_to = klass;
1239 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1240 "System", "InvalidCastException"));
1246 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1249 MonoJitTlsData *jit_tls = NULL;
1250 gpointer cached_vtable, obj_vtable;
1252 if (mini_get_debug_options ()->better_cast_details) {
1253 jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
1254 jit_tls->class_cast_from = NULL;
1260 cached_vtable = *cache;
1261 obj_vtable = obj->vtable;
1263 if (cached_vtable == obj_vtable)
1266 if (mono_object_isinst_checked (obj, klass, &error)) {
1267 *cache = obj_vtable;
1270 if (mono_error_set_pending_exception (&error))
1273 if (mini_get_debug_options ()->better_cast_details) {
1274 jit_tls->class_cast_from = obj->vtable->klass;
1275 jit_tls->class_cast_to = klass;
1278 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1279 "System", "InvalidCastException"));
1285 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1288 size_t cached_vtable, obj_vtable;
1293 cached_vtable = (size_t)*cache;
1294 obj_vtable = (size_t)obj->vtable;
1296 if ((cached_vtable & ~0x1) == obj_vtable) {
1297 return (cached_vtable & 0x1) ? NULL : obj;
1300 if (mono_object_isinst_checked (obj, klass, &error)) {
1301 *cache = (gpointer)obj_vtable;
1304 if (mono_error_set_pending_exception (&error))
1307 *cache = (gpointer)(obj_vtable | 0x1);
1313 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1316 MonoMarshalSpec **mspecs;
1317 MonoMethodPInvoke piinfo;
1320 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1321 memset (&piinfo, 0, sizeof (piinfo));
1323 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1325 gpointer compiled_ptr = mono_compile_method_checked (m, &error);
1326 mono_error_set_pending_exception (&error);
1327 return compiled_ptr;
1331 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1334 int vt_slot, iface_offset;
1338 if (mono_class_is_interface (klass)) {
1339 MonoObject *this_obj;
1341 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1342 this_obj = *(MonoObject**)mp;
1343 g_assert (this_obj);
1345 klass = this_obj->vtable->klass;
1348 if (mono_method_signature (cmethod)->pinvoke) {
1349 /* Object.GetType () */
1350 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1352 /* Lookup the virtual method */
1353 mono_class_setup_vtable (klass);
1354 g_assert (klass->vtable);
1355 vt_slot = mono_method_get_vtable_slot (cmethod);
1356 if (mono_class_is_interface (cmethod->klass)) {
1357 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1358 g_assert (iface_offset != -1);
1359 vt_slot += iface_offset;
1361 m = klass->vtable [vt_slot];
1362 if (cmethod->is_inflated)
1363 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1366 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1368 * Calling a non-vtype method with a vtype receiver, has to box.
1370 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1371 else if (klass->valuetype)
1373 * Calling a vtype method with a vtype receiver
1378 * Calling a non-vtype method
1380 *this_arg = *(gpointer*)mp;
1385 * mono_gsharedvt_constrained_call:
1387 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1388 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1391 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1397 gpointer new_args [16];
1399 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1400 if (!mono_error_ok (&error)) {
1401 mono_error_set_pending_exception (&error);
1407 if (args && deref_arg) {
1408 new_args [0] = *(gpointer*)args [0];
1411 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1412 /* Object.GetType () */
1414 args [0] = this_arg;
1418 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1419 if (!mono_error_ok (&error)) {
1420 mono_error_set_pending_exception (&error);
1428 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1430 if (klass->valuetype)
1431 mono_value_copy (dest, src, klass);
1433 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1437 ves_icall_runtime_class_init (MonoVTable *vtable)
1439 MONO_REQ_GC_UNSAFE_MODE;
1442 mono_runtime_class_init_full (vtable, &error);
1443 mono_error_set_pending_exception (&error);
1448 mono_generic_class_init (MonoVTable *vtable)
1451 mono_runtime_class_init_full (vtable, &error);
1452 mono_error_set_pending_exception (&error);
1456 ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
1459 mono_delegate_ctor (this_obj, target, addr, &error);
1460 mono_error_set_pending_exception (&error);
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_full_name (caller, 1);
1916 char *callee_name = mono_method_full_name (callee, 1);
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)