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/threads-types.h>
23 #include <mono/metadata/reflection-internals.h>
26 #include "mini-llvm-cpp.h"
30 mono_ldftn (MonoMethod *method)
36 // FIXME: No error handling
38 addr = mono_compile_method (method);
41 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
42 /* The caller doesn't pass it */
43 g_assert_not_reached ();
45 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
49 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, &error);
50 if (!mono_error_ok (&error)) {
51 mono_error_set_pending_exception (&error);
54 return mono_create_ftnptr (mono_domain_get (), addr);
58 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
64 mono_set_pending_exception (mono_get_exception_null_reference ());
68 res = mono_object_get_virtual_method (obj, method);
70 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
71 MonoGenericContext context = { NULL, NULL };
73 if (res->klass->generic_class)
74 context.class_inst = res->klass->generic_class->context.class_inst;
75 else if (res->klass->generic_container)
76 context.class_inst = res->klass->generic_container->context.class_inst;
77 context.method_inst = mono_method_get_context (method)->method_inst;
79 res = mono_class_inflate_generic_method_checked (res, &context, &error);
80 if (!mono_error_ok (&error)) {
81 mono_error_set_pending_exception (&error);
86 /* An rgctx wrapper is added by the trampolines no need to do it here */
88 return mono_ldftn (res);
92 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
94 return ldvirtfn_internal (obj, method, FALSE);
98 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
100 return ldvirtfn_internal (obj, method, TRUE);
104 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
108 mono_set_pending_exception (mono_get_exception_null_reference ());
111 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
112 if (mono_error_set_pending_exception (&error))
114 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
119 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
122 mono_llmult (gint64 a, gint64 b)
128 mono_llmult_ovf_un (guint64 a, guint64 b)
131 guint32 ah = a >> 32;
133 guint32 bh = b >> 32;
136 // fixme: this is incredible slow
139 goto raise_exception;
141 res = (guint64)al * (guint64)bl;
143 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
146 goto raise_exception;
148 res += ((guint64)t1) << 32;
153 mono_set_pending_exception (mono_get_exception_overflow ());
158 mono_llmult_ovf (gint64 a, gint64 b)
165 Use Karatsuba algorithm where:
166 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
167 where Ah is the "high half" (most significant 32 bits) of a and
168 where Al is the "low half" (least significant 32 bits) of a and
169 where Bh is the "high half" of b and Bl is the "low half" and
170 where R is the Radix or "size of the half" (in our case 32 bits)
172 Note, for the product of two 64 bit numbers to fit into a 64
173 result, ah and/or bh must be 0. This will save us from doing
174 the AhBh term at all.
176 Also note that we refactor so that we don't overflow 64 bits with
177 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
183 /* need to work with absoulte values, so find out what the
184 resulting sign will be and convert any negative numbers
185 from two's complement
189 if (((guint32)ah == 0x80000000) && (al == 0)) {
190 /* This has no two's complement */
196 goto raise_exception;
199 /* flip the bits and add 1 */
210 if (((guint32)bh == 0x80000000) && (bl == 0)) {
211 /* This has no two's complement */
217 goto raise_exception;
220 /* flip the bits and add 1 */
230 /* we overflow for sure if both upper halves are greater
231 than zero because we would need to shift their
232 product 64 bits to the left and that will not fit
233 in a 64 bit result */
235 goto raise_exception;
236 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
237 goto raise_exception;
239 /* do the AlBl term first */
240 t1 = (gint64)al * (gint64)bl;
244 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
245 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
246 /* check for overflow */
248 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
249 goto raise_exception;
254 goto raise_exception;
262 mono_set_pending_exception (mono_get_exception_overflow ());
267 mono_lldiv (gint64 a, gint64 b)
269 #ifdef MONO_ARCH_NEED_DIV_CHECK
271 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
274 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
275 mono_set_pending_exception (mono_get_exception_arithmetic ());
283 mono_llrem (gint64 a, gint64 b)
285 #ifdef MONO_ARCH_NEED_DIV_CHECK
287 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
290 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
291 mono_set_pending_exception (mono_get_exception_arithmetic ());
299 mono_lldiv_un (guint64 a, guint64 b)
301 #ifdef MONO_ARCH_NEED_DIV_CHECK
303 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
311 mono_llrem_un (guint64 a, guint64 b)
313 #ifdef MONO_ARCH_NEED_DIV_CHECK
315 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
324 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
327 mono_lshl (guint64 a, gint32 shamt)
331 res = a << (shamt & 0x7f);
333 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
339 mono_lshr_un (guint64 a, gint32 shamt)
343 res = a >> (shamt & 0x7f);
345 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
351 mono_lshr (gint64 a, gint32 shamt)
355 res = a >> (shamt & 0x7f);
357 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
364 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
367 mono_idiv (gint32 a, gint32 b)
369 #ifdef MONO_ARCH_NEED_DIV_CHECK
371 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
374 else if (b == -1 && a == (0x80000000)) {
375 mono_set_pending_exception (mono_get_exception_overflow ());
383 mono_idiv_un (guint32 a, guint32 b)
385 #ifdef MONO_ARCH_NEED_DIV_CHECK
387 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
395 mono_irem (gint32 a, gint32 b)
397 #ifdef MONO_ARCH_NEED_DIV_CHECK
399 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
402 else if (b == -1 && a == (0x80000000)) {
403 mono_set_pending_exception (mono_get_exception_overflow ());
411 mono_irem_un (guint32 a, guint32 b)
413 #ifdef MONO_ARCH_NEED_DIV_CHECK
415 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
424 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
427 mono_imul (gint32 a, gint32 b)
433 mono_imul_ovf (gint32 a, gint32 b)
437 res = (gint64)a * (gint64)b;
439 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
440 mono_set_pending_exception (mono_get_exception_overflow ());
448 mono_imul_ovf_un (guint32 a, guint32 b)
452 res = (guint64)a * (guint64)b;
455 mono_set_pending_exception (mono_get_exception_overflow ());
463 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
465 mono_fdiv (double a, double b)
471 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
474 mono_fsub (double a, double b)
480 mono_fadd (double a, double b)
486 mono_fmul (double a, double b)
498 mono_fconv_r4 (double a)
504 mono_conv_to_r8 (int a)
510 mono_conv_to_r4 (int a)
512 return (double)(float)a;
516 mono_fconv_i1 (double a)
522 mono_fconv_i2 (double a)
528 mono_fconv_i4 (double a)
534 mono_fconv_u1 (double a)
540 mono_fconv_u2 (double a)
546 mono_fcmp_eq (double a, double b)
552 mono_fcmp_ge (double a, double b)
558 mono_fcmp_gt (double a, double b)
564 mono_fcmp_le (double a, double b)
570 mono_fcmp_lt (double a, double b)
576 mono_fcmp_ne_un (double a, double b)
578 return isunordered (a, b) || a != b;
582 mono_fcmp_ge_un (double a, double b)
584 return isunordered (a, b) || a >= b;
588 mono_fcmp_gt_un (double a, double b)
590 return isunordered (a, b) || a > b;
594 mono_fcmp_le_un (double a, double b)
596 return isunordered (a, b) || a <= b;
600 mono_fcmp_lt_un (double a, double b)
602 return isunordered (a, b) || a < b;
606 mono_fceq (double a, double b)
612 mono_fcgt (double a, double b)
618 mono_fcgt_un (double a, double b)
620 return isunordered (a, b) || a > b;
624 mono_fclt (double a, double b)
630 mono_fclt_un (double a, double b)
632 return isunordered (a, b) || a < b;
636 mono_isfinite (double a)
641 g_assert_not_reached ();
647 mono_fload_r4 (float *ptr)
653 mono_fstore_r4 (double val, float *ptr)
658 /* returns the integer bitpattern that is passed in the regs or stack */
660 mono_fload_r4_arg (double val)
662 float v = (float)val;
663 return *(guint32*)&v;
669 mono_array_new_va (MonoMethod *cm, ...)
673 MonoDomain *domain = mono_domain_get ();
676 intptr_t *lower_bounds;
681 pcount = mono_method_signature (cm)->param_count;
682 rank = cm->klass->rank;
686 lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
687 for (i = 0; i < pcount; ++i)
688 lengths [i] = d = va_arg(ap, int);
690 if (rank == pcount) {
691 /* Only lengths provided. */
692 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
693 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
694 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
699 g_assert (pcount == (rank * 2));
700 /* lower bounds are first. */
701 lower_bounds = (intptr_t*)lengths;
706 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
708 if (!mono_error_ok (&error)) {
709 mono_error_set_pending_exception (&error);
716 /* Specialized version of mono_array_new_va () which avoids varargs */
718 mono_array_new_1 (MonoMethod *cm, guint32 length)
722 MonoDomain *domain = mono_domain_get ();
723 uintptr_t lengths [1];
724 intptr_t *lower_bounds;
728 pcount = mono_method_signature (cm)->param_count;
729 rank = cm->klass->rank;
731 lengths [0] = length;
733 g_assert (rank == pcount);
735 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
736 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
737 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
742 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
744 if (!mono_error_ok (&error)) {
745 mono_error_set_pending_exception (&error);
753 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
757 MonoDomain *domain = mono_domain_get ();
758 uintptr_t lengths [2];
759 intptr_t *lower_bounds;
763 pcount = mono_method_signature (cm)->param_count;
764 rank = cm->klass->rank;
766 lengths [0] = length1;
767 lengths [1] = length2;
769 g_assert (rank == pcount);
771 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
772 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
773 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
778 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
780 if (!mono_error_ok (&error)) {
781 mono_error_set_pending_exception (&error);
789 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
793 MonoDomain *domain = mono_domain_get ();
794 uintptr_t lengths [3];
795 intptr_t *lower_bounds;
799 pcount = mono_method_signature (cm)->param_count;
800 rank = cm->klass->rank;
802 lengths [0] = length1;
803 lengths [1] = length2;
804 lengths [2] = length3;
806 g_assert (rank == pcount);
808 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
809 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
810 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
815 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
817 if (!mono_error_ok (&error)) {
818 mono_error_set_pending_exception (&error);
826 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
830 MonoDomain *domain = mono_domain_get ();
831 uintptr_t lengths [4];
832 intptr_t *lower_bounds;
836 pcount = mono_method_signature (cm)->param_count;
837 rank = cm->klass->rank;
839 lengths [0] = length1;
840 lengths [1] = length2;
841 lengths [2] = length3;
842 lengths [3] = length4;
844 g_assert (rank == pcount);
846 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
847 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
848 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
853 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, &error);
855 if (!mono_error_ok (&error)) {
856 mono_error_set_pending_exception (&error);
864 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
870 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
872 mono_class_init (field->parent);
874 vtable = mono_class_vtable_full (domain, field->parent, &error);
875 if (!is_ok (&error)) {
876 mono_error_set_pending_exception (&error);
879 if (!vtable->initialized) {
880 if (!mono_runtime_class_init_full (vtable, &error)) {
881 mono_error_set_pending_exception (&error);
886 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
888 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
889 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
891 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
897 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
900 MonoClass *handle_class;
903 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
904 if (!mono_error_ok (&error)) {
905 mono_error_set_pending_exception (&error);
908 mono_class_init (handle_class);
914 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
916 MonoMethodSignature *sig = mono_method_signature (method);
917 MonoGenericContext *generic_context;
919 if (sig->is_inflated) {
920 generic_context = mono_method_get_context (method);
922 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
923 g_assert (generic_container);
924 generic_context = &generic_container->context;
927 return mono_ldtoken_wrapper (image, token, generic_context);
931 mono_fconv_u8 (double v)
937 mono_rconv_u8 (float v)
942 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
944 mono_fconv_i8 (double v)
951 mono_fconv_u4 (double v)
953 /* MS.NET behaves like this for some reason */
955 if (isinf (v) || isnan (v))
963 /* Solaris doesn't have trunc */
965 extern long double aintl (long double);
968 /* FIXME: This means we will never throw overflow exceptions */
971 #endif /* HAVE_TRUNC */
974 mono_fconv_ovf_i8 (double v)
980 if (isnan(v) || trunc (v) != res) {
981 mono_set_pending_exception (mono_get_exception_overflow ());
988 mono_fconv_ovf_u8 (double v)
993 * The soft-float implementation of some ARM devices have a buggy guin64 to double
994 * conversion that it looses precision even when the integer if fully representable
997 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
999 * To work around this issue we test for value boundaries instead.
1001 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1002 if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1003 mono_set_pending_exception (mono_get_exception_overflow ());
1009 if (isnan(v) || trunc (v) != res) {
1010 mono_set_pending_exception (mono_get_exception_overflow ());
1017 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1019 mono_rconv_i8 (float v)
1026 mono_rconv_ovf_i8 (float v)
1032 if (isnan(v) || trunc (v) != res) {
1033 mono_set_pending_exception (mono_get_exception_overflow ());
1040 mono_rconv_ovf_u8 (float v)
1045 if (isnan(v) || trunc (v) != res) {
1046 mono_set_pending_exception (mono_get_exception_overflow ());
1052 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1054 mono_lconv_to_r8 (gint64 a)
1060 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1062 mono_lconv_to_r4 (gint64 a)
1068 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1070 mono_conv_to_r8_un (guint32 a)
1076 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1078 mono_lconv_to_r8_un (guint64 a)
1084 #if defined(__native_client_codegen__) || defined(__native_client__)
1085 /* When we cross-compile to Native Client we can't directly embed calls */
1086 /* to the math library on the host. This will use the fmod on the target*/
1088 mono_fmod(double a, double b)
1095 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1097 MonoMethod *vmethod;
1099 MonoGenericContext *context = mono_method_get_context (method);
1101 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 (!vmethod->klass->generic_container);
1109 g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1110 g_assert (!context->method_inst || !context->method_inst->is_open);
1112 addr = mono_compile_method (vmethod);
1114 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1116 /* Since this is a virtual call, have to unbox vtypes */
1117 if (obj->vtable->klass->valuetype)
1118 *this_arg = mono_object_unbox (obj);
1126 mono_helper_ldstr (MonoImage *image, guint32 idx)
1128 return mono_ldstr (mono_domain_get (), image, idx);
1132 mono_helper_ldstr_mscorlib (guint32 idx)
1134 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1138 mono_helper_newobj_mscorlib (guint32 idx)
1141 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1143 if (!mono_error_ok (&error)) {
1144 mono_error_set_pending_exception (&error);
1148 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, &error);
1149 if (!mono_error_ok (&error))
1150 mono_error_set_pending_exception (&error);
1155 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1156 * in generated code. So instead we emit a call to this function and place a gdb
1165 mono_create_corlib_exception_0 (guint32 token)
1167 return mono_exception_from_token (mono_defaults.corlib, token);
1171 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1173 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1177 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1179 return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1183 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1186 MonoJitTlsData *jit_tls = NULL;
1189 if (mini_get_debug_options ()->better_cast_details) {
1190 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1191 jit_tls->class_cast_from = NULL;
1197 oklass = obj->vtable->klass;
1198 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1200 if (mono_object_isinst_checked (obj, klass, &error))
1202 if (mono_error_set_pending_exception (&error))
1205 if (mini_get_debug_options ()->better_cast_details) {
1206 jit_tls->class_cast_from = oklass;
1207 jit_tls->class_cast_to = klass;
1210 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1211 "System", "InvalidCastException"));
1217 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1220 MonoJitTlsData *jit_tls = NULL;
1221 gpointer cached_vtable, obj_vtable;
1223 if (mini_get_debug_options ()->better_cast_details) {
1224 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1225 jit_tls->class_cast_from = NULL;
1231 cached_vtable = *cache;
1232 obj_vtable = obj->vtable;
1234 if (cached_vtable == obj_vtable)
1237 if (mono_object_isinst_checked (obj, klass, &error)) {
1238 *cache = obj_vtable;
1241 if (mono_error_set_pending_exception (&error))
1244 if (mini_get_debug_options ()->better_cast_details) {
1245 jit_tls->class_cast_from = obj->vtable->klass;
1246 jit_tls->class_cast_to = klass;
1249 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1250 "System", "InvalidCastException"));
1256 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1259 size_t cached_vtable, obj_vtable;
1264 cached_vtable = (size_t)*cache;
1265 obj_vtable = (size_t)obj->vtable;
1267 if ((cached_vtable & ~0x1) == obj_vtable) {
1268 return (cached_vtable & 0x1) ? NULL : obj;
1271 if (mono_object_isinst_checked (obj, klass, &error)) {
1272 *cache = (gpointer)obj_vtable;
1275 if (mono_error_set_pending_exception (&error))
1278 *cache = (gpointer)(obj_vtable | 0x1);
1284 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1286 MonoMarshalSpec **mspecs;
1287 MonoMethodPInvoke piinfo;
1290 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1291 memset (&piinfo, 0, sizeof (piinfo));
1293 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1295 return mono_compile_method (m);
1299 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1302 int vt_slot, iface_offset;
1304 mono_error_init (error);
1306 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1307 MonoObject *this_obj;
1309 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1310 this_obj = *(MonoObject**)mp;
1311 g_assert (this_obj);
1313 klass = this_obj->vtable->klass;
1316 if (mono_method_signature (cmethod)->pinvoke) {
1317 /* Object.GetType () */
1318 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1320 /* Lookup the virtual method */
1321 mono_class_setup_vtable (klass);
1322 g_assert (klass->vtable);
1323 vt_slot = mono_method_get_vtable_slot (cmethod);
1324 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1325 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1326 g_assert (iface_offset != -1);
1327 vt_slot += iface_offset;
1329 m = klass->vtable [vt_slot];
1330 if (cmethod->is_inflated)
1331 m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1334 if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1336 * Calling a non-vtype method with a vtype receiver, has to box.
1338 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1339 else if (klass->valuetype)
1341 * Calling a vtype method with a vtype receiver
1346 * Calling a non-vtype method
1348 *this_arg = *(gpointer*)mp;
1353 * mono_gsharedvt_constrained_call:
1355 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1356 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1359 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1365 gpointer new_args [16];
1367 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1368 if (!mono_error_ok (&error)) {
1369 mono_error_set_pending_exception (&error);
1375 if (args && deref_arg) {
1376 new_args [0] = *(gpointer*)args [0];
1379 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1380 /* Object.GetType () */
1382 args [0] = this_arg;
1386 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1387 if (!mono_error_ok (&error)) {
1388 mono_error_set_pending_exception (&error);
1396 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1398 if (klass->valuetype)
1399 mono_value_copy (dest, src, klass);
1401 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1405 ves_icall_runtime_class_init (MonoVTable *vtable)
1407 MONO_REQ_GC_UNSAFE_MODE;
1410 mono_runtime_class_init_full (vtable, &error);
1411 mono_error_set_pending_exception (&error);
1416 mono_generic_class_init (MonoVTable *vtable)
1419 mono_runtime_class_init_full (vtable, &error);
1420 mono_error_set_pending_exception (&error);
1424 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1429 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1430 if (!mono_error_ok (&error)) {
1431 mono_error_set_pending_exception (&error);
1438 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1443 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1444 if (!mono_error_ok (&error)) {
1445 mono_error_set_pending_exception (&error);
1452 * resolve_iface_call:
1454 * Return the executable code for the iface method IMT_METHOD called on THIS.
1455 * This function is called on a slowpath, so it doesn't need to be fast.
1456 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1460 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1463 gpointer *imt, *vtable_slot;
1464 MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1465 gpointer addr, compiled_method, aot_addr;
1466 gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1469 /* The caller will handle it */
1472 vt = this_obj->vtable;
1473 imt = (gpointer*)vt - MONO_IMT_SIZE;
1475 vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1477 // FIXME: This can throw exceptions
1478 addr = compiled_method = mono_compile_method (impl_method);
1481 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1482 generic_virtual = imt_method;
1484 if (generic_virtual || variant_iface) {
1485 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1486 need_unbox_tramp = TRUE;
1488 if (impl_method->klass->valuetype)
1489 need_unbox_tramp = TRUE;
1492 addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1494 if (generic_virtual || variant_iface) {
1495 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1497 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1506 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1508 return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1512 is_generic_method_definition (MonoMethod *m)
1514 MonoGenericContext *context;
1517 if (!m->is_inflated)
1520 context = mono_method_get_context (m);
1521 if (!context->method_inst)
1523 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1531 * Return the executable code for calling vt->vtable [slot].
1532 * This function is called on a slowpath, so it doesn't need to be fast.
1533 * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1537 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1539 MonoMethod *m, *generic_virtual = NULL;
1540 gpointer addr, compiled_method;
1541 gboolean need_unbox_tramp = FALSE;
1543 /* Same as in common_call_trampoline () */
1545 /* Avoid loading metadata or creating a generic vtable if possible */
1546 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1547 if (addr && !vt->klass->valuetype)
1548 return mono_create_ftnptr (mono_domain_get (), addr);
1550 m = mono_class_get_vtable_entry (vt->klass, slot);
1552 if (is_generic_method_definition (m)) {
1554 MonoGenericContext context = { NULL, NULL };
1555 MonoMethod *declaring;
1558 declaring = mono_method_get_declaring_generic_method (m);
1562 if (m->klass->generic_class)
1563 context.class_inst = m->klass->generic_class->context.class_inst;
1565 g_assert (!m->klass->generic_container);
1567 generic_virtual = imt_method;
1568 g_assert (generic_virtual);
1569 g_assert (generic_virtual->is_inflated);
1570 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1572 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1573 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1576 if (generic_virtual) {
1577 if (vt->klass->valuetype)
1578 need_unbox_tramp = TRUE;
1580 if (m->klass->valuetype)
1581 need_unbox_tramp = TRUE;
1584 // FIXME: This can throw exceptions
1585 addr = compiled_method = mono_compile_method (m);
1588 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1590 if (!gsharedvt && generic_virtual) {
1591 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1592 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1594 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1595 vt, vt->vtable + slot,
1596 generic_virtual, ftndesc);
1603 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1605 g_assert (this_obj);
1607 return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1611 * mono_resolve_generic_virtual_call:
1613 * Resolve a generic virtual call.
1614 * This function is called on a slowpath, so it doesn't need to be fast.
1617 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1620 gpointer addr, compiled_method;
1621 gboolean need_unbox_tramp = FALSE;
1623 MonoGenericContext context = { NULL, NULL };
1624 MonoMethod *declaring;
1625 gpointer arg = NULL;
1627 m = mono_class_get_vtable_entry (vt->klass, slot);
1629 g_assert (is_generic_method_definition (m));
1632 declaring = mono_method_get_declaring_generic_method (m);
1636 if (m->klass->generic_class)
1637 context.class_inst = m->klass->generic_class->context.class_inst;
1639 g_assert (!m->klass->generic_container);
1641 g_assert (generic_virtual->is_inflated);
1642 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1644 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1645 g_assert (mono_error_ok (&error));
1647 if (vt->klass->valuetype)
1648 need_unbox_tramp = TRUE;
1650 // FIXME: This can throw exceptions
1651 addr = compiled_method = mono_compile_method (m);
1654 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1657 * This wastes memory but the memory usage is bounded since
1658 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1659 * this vtable slot so we are not called any more for this instantiation.
1661 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1663 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1664 vt, vt->vtable + slot,
1665 generic_virtual, ftndesc);
1670 * mono_resolve_generic_virtual_call:
1672 * Resolve a generic virtual/variant iface call on interfaces.
1673 * This function is called on a slowpath, so it doesn't need to be fast.
1676 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1678 MonoMethod *m, *variant_iface;
1679 gpointer addr, aot_addr, compiled_method;
1680 gboolean need_unbox_tramp = FALSE;
1681 gboolean need_rgctx_tramp;
1682 gpointer arg = NULL;
1685 imt = (gpointer*)vt - MONO_IMT_SIZE;
1687 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1689 if (vt->klass->valuetype)
1690 need_unbox_tramp = TRUE;
1692 // FIXME: This can throw exceptions
1693 addr = compiled_method = mono_compile_method (m);
1696 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1699 * This wastes memory but the memory usage is bounded since
1700 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1701 * this vtable slot so we are not called any more for this instantiation.
1703 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1705 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1707 variant_iface ? variant_iface : generic_virtual, ftndesc);
1712 * mono_init_vtable_slot:
1714 * Initialize slot SLOT of VTABLE.
1715 * Return the contents of the vtable slot.
1718 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1720 gpointer arg = NULL;
1724 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1725 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1728 mono_memory_barrier ();
1730 vtable->vtable [slot] = ftnptr;
1736 * mono_llvmonly_init_delegate:
1738 * Initialize a MonoDelegate object.
1739 * Similar to mono_delegate_ctor ().
1742 mono_llvmonly_init_delegate (MonoDelegate *del)
1744 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1747 * We store a MonoFtnDesc in del->method_code.
1748 * It would be better to store an ftndesc in del->method_ptr too,
1749 * but we don't have a a structure which could own its memory.
1751 if (G_UNLIKELY (!ftndesc)) {
1752 gpointer addr = mono_compile_method (del->method);
1754 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1755 addr = mono_aot_get_unbox_trampoline (del->method);
1757 gpointer arg = mini_get_delegate_arg (del->method, addr);
1759 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1760 mono_memory_barrier ();
1761 *del->method_code = (gpointer)ftndesc;
1763 del->method_ptr = ftndesc->addr;
1764 del->extra_arg = ftndesc->arg;
1768 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1772 method = mono_object_get_virtual_method (target, method);
1774 del->method = method;
1775 del->method_ptr = mono_compile_method (method);
1776 if (method->klass->valuetype)
1777 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1778 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1782 mono_get_assembly_object (MonoImage *image)
1786 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1788 mono_error_set_pending_exception (&error);
1793 mono_get_method_object (MonoMethod *method)
1796 MonoObject * result;
1797 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1798 mono_error_set_pending_exception (&error);
1803 mono_ckfinite (double d)
1805 if (isinf (d) || isnan (d))
1806 mono_set_pending_exception (mono_get_exception_arithmetic ());
1811 * mono_interruption_checkpoint_from_trampoline:
1813 * Check whenever the thread has a pending exception, and throw it
1815 * Architectures should move away from calling this function and
1816 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1817 * rewrind to the parent frame, and throw the exception normally.
1820 mono_interruption_checkpoint_from_trampoline (void)
1824 ex = mono_thread_force_interruption_checkpoint_noraise ();
1826 mono_raise_exception (ex);