Merge pull request #3100 from lambdageek/dev/monoerror-exns
[mono-project.git] / mono / mini / jit-icalls.c
blob8651aa25ec497c574a6d492e6ae6e9b324be8e14
1 /*
2 * jit-icalls.c: internal calls used by the JIT
4 * Author:
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.
13 #include <config.h>
14 #include <math.h>
15 #include <limits.h>
16 #ifdef HAVE_ALLOCA_H
17 #include <alloca.h>
18 #endif
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>
26 #ifdef ENABLE_LLVM
27 #include "mini-llvm-cpp.h"
28 #endif
30 void*
31 mono_ldftn (MonoMethod *method)
33 gpointer addr;
34 MonoError error;
36 if (mono_llvm_only) {
37 // FIXME: No error handling
39 addr = mono_compile_method_checked (method, &error);
40 mono_error_assert_ok (&error);
41 g_assert (addr);
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);
48 return addr;
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);
54 return NULL;
56 return mono_create_ftnptr (mono_domain_get (), addr);
59 static void*
60 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
62 MonoError error;
63 MonoMethod *res;
65 if (obj == NULL) {
66 mono_set_pending_exception (mono_get_exception_null_reference ());
67 return NULL;
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);
84 return NULL;
88 /* An rgctx wrapper is added by the trampolines no need to do it here */
90 return mono_ldftn (res);
93 void*
94 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
96 return ldvirtfn_internal (obj, method, FALSE);
99 void*
100 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
102 return ldvirtfn_internal (obj, method, TRUE);
105 void
106 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
108 MonoError error;
109 if (!array) {
110 mono_set_pending_exception (mono_get_exception_null_reference ());
111 return;
113 if (val && !mono_object_isinst_checked (val, array->obj.vtable->klass->element_class, &error)) {
114 if (mono_error_set_pending_exception (&error))
115 return;
116 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
117 return;
121 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
123 gint64
124 mono_llmult (gint64 a, gint64 b)
126 return a * b;
129 guint64
130 mono_llmult_ovf_un (guint64 a, guint64 b)
132 guint32 al = a;
133 guint32 ah = a >> 32;
134 guint32 bl = b;
135 guint32 bh = b >> 32;
136 guint64 res, t1;
138 // fixme: this is incredible slow
140 if (ah && bh)
141 goto raise_exception;
143 res = (guint64)al * (guint64)bl;
145 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
147 if (t1 > 0xffffffff)
148 goto raise_exception;
150 res += ((guint64)t1) << 32;
152 return res;
154 raise_exception:
155 mono_set_pending_exception (mono_get_exception_overflow ());
156 return 0;
159 guint64
160 mono_llmult_ovf (gint64 a, gint64 b)
162 guint32 al = a;
163 gint32 ah = a >> 32;
164 guint32 bl = b;
165 gint32 bh = b >> 32;
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
182 gint64 res, t1;
183 gint32 sign;
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
189 sign = ah ^ bh;
190 if (ah < 0) {
191 if (((guint32)ah == 0x80000000) && (al == 0)) {
192 /* This has no two's complement */
193 if (b == 0)
194 return 0;
195 else if (b == 1)
196 return a;
197 else
198 goto raise_exception;
201 /* flip the bits and add 1 */
202 ah ^= ~0;
203 if (al == 0)
204 ah += 1;
205 else {
206 al ^= ~0;
207 al +=1;
211 if (bh < 0) {
212 if (((guint32)bh == 0x80000000) && (bl == 0)) {
213 /* This has no two's complement */
214 if (a == 0)
215 return 0;
216 else if (a == 1)
217 return b;
218 else
219 goto raise_exception;
222 /* flip the bits and add 1 */
223 bh ^= ~0;
224 if (bl == 0)
225 bh += 1;
226 else {
227 bl ^= ~0;
228 bl +=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 */
236 if (ah && bh)
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;
244 res = t1;
246 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
247 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
248 /* check for overflow */
249 t1 <<= 32;
250 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
251 goto raise_exception;
253 res += t1;
255 if (res < 0)
256 goto raise_exception;
258 if (sign < 0)
259 return -res;
260 else
261 return res;
263 raise_exception:
264 mono_set_pending_exception (mono_get_exception_overflow ());
265 return 0;
268 gint64
269 mono_lldiv (gint64 a, gint64 b)
271 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 if (!b) {
273 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
274 return 0;
276 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
277 mono_set_pending_exception (mono_get_exception_arithmetic ());
278 return 0;
280 #endif
281 return a / b;
284 gint64
285 mono_llrem (gint64 a, gint64 b)
287 #ifdef MONO_ARCH_NEED_DIV_CHECK
288 if (!b) {
289 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
290 return 0;
292 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
293 mono_set_pending_exception (mono_get_exception_arithmetic ());
294 return 0;
296 #endif
297 return a % b;
300 guint64
301 mono_lldiv_un (guint64 a, guint64 b)
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
304 if (!b) {
305 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
306 return 0;
308 #endif
309 return a / b;
312 guint64
313 mono_llrem_un (guint64 a, guint64 b)
315 #ifdef MONO_ARCH_NEED_DIV_CHECK
316 if (!b) {
317 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
318 return 0;
320 #endif
321 return a % b;
324 #endif
326 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
328 guint64
329 mono_lshl (guint64 a, gint32 shamt)
331 guint64 res;
333 res = a << (shamt & 0x7f);
335 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
337 return res;
340 guint64
341 mono_lshr_un (guint64 a, gint32 shamt)
343 guint64 res;
345 res = a >> (shamt & 0x7f);
347 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
349 return res;
352 gint64
353 mono_lshr (gint64 a, gint32 shamt)
355 gint64 res;
357 res = a >> (shamt & 0x7f);
359 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
361 return res;
364 #endif
366 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
368 gint32
369 mono_idiv (gint32 a, gint32 b)
371 #ifdef MONO_ARCH_NEED_DIV_CHECK
372 if (!b) {
373 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
374 return 0;
376 else if (b == -1 && a == (0x80000000)) {
377 mono_set_pending_exception (mono_get_exception_overflow ());
378 return 0;
380 #endif
381 return a / b;
384 guint32
385 mono_idiv_un (guint32 a, guint32 b)
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
388 if (!b) {
389 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
390 return 0;
392 #endif
393 return a / b;
396 gint32
397 mono_irem (gint32 a, gint32 b)
399 #ifdef MONO_ARCH_NEED_DIV_CHECK
400 if (!b) {
401 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
402 return 0;
404 else if (b == -1 && a == (0x80000000)) {
405 mono_set_pending_exception (mono_get_exception_overflow ());
406 return 0;
408 #endif
409 return a % b;
412 guint32
413 mono_irem_un (guint32 a, guint32 b)
415 #ifdef MONO_ARCH_NEED_DIV_CHECK
416 if (!b) {
417 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
418 return 0;
420 #endif
421 return a % b;
424 #endif
426 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
428 gint32
429 mono_imul (gint32 a, gint32 b)
431 return a * b;
434 gint32
435 mono_imul_ovf (gint32 a, gint32 b)
437 gint64 res;
439 res = (gint64)a * (gint64)b;
441 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
442 mono_set_pending_exception (mono_get_exception_overflow ());
443 return 0;
446 return res;
449 gint32
450 mono_imul_ovf_un (guint32 a, guint32 b)
452 guint64 res;
454 res = (guint64)a * (guint64)b;
456 if (res >> 32) {
457 mono_set_pending_exception (mono_get_exception_overflow ());
458 return 0;
461 return res;
463 #endif
465 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
466 double
467 mono_fdiv (double a, double b)
469 return a / b;
471 #endif
473 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
475 double
476 mono_fsub (double a, double b)
478 return a - b;
481 double
482 mono_fadd (double a, double b)
484 return a + b;
487 double
488 mono_fmul (double a, double b)
490 return a * b;
493 double
494 mono_fneg (double a)
496 return -a;
499 double
500 mono_fconv_r4 (double a)
502 return (float)a;
505 double
506 mono_conv_to_r8 (int a)
508 return (double)a;
511 double
512 mono_conv_to_r4 (int a)
514 return (double)(float)a;
517 gint8
518 mono_fconv_i1 (double a)
520 return (gint8)a;
523 gint16
524 mono_fconv_i2 (double a)
526 return (gint16)a;
529 gint32
530 mono_fconv_i4 (double a)
532 return (gint32)a;
535 guint8
536 mono_fconv_u1 (double a)
538 return (guint8)a;
541 guint16
542 mono_fconv_u2 (double a)
544 return (guint16)a;
547 gboolean
548 mono_fcmp_eq (double a, double b)
550 return a == b;
553 gboolean
554 mono_fcmp_ge (double a, double b)
556 return a >= b;
559 gboolean
560 mono_fcmp_gt (double a, double b)
562 return a > b;
565 gboolean
566 mono_fcmp_le (double a, double b)
568 return a <= b;
571 gboolean
572 mono_fcmp_lt (double a, double b)
574 return a < b;
577 gboolean
578 mono_fcmp_ne_un (double a, double b)
580 return isunordered (a, b) || a != b;
583 gboolean
584 mono_fcmp_ge_un (double a, double b)
586 return isunordered (a, b) || a >= b;
589 gboolean
590 mono_fcmp_gt_un (double a, double b)
592 return isunordered (a, b) || a > b;
595 gboolean
596 mono_fcmp_le_un (double a, double b)
598 return isunordered (a, b) || a <= b;
601 gboolean
602 mono_fcmp_lt_un (double a, double b)
604 return isunordered (a, b) || a < b;
607 gboolean
608 mono_fceq (double a, double b)
610 return a == b;
613 gboolean
614 mono_fcgt (double a, double b)
616 return a > b;
619 gboolean
620 mono_fcgt_un (double a, double b)
622 return isunordered (a, b) || a > b;
625 gboolean
626 mono_fclt (double a, double b)
628 return a < b;
631 gboolean
632 mono_fclt_un (double a, double b)
634 return isunordered (a, b) || a < b;
637 gboolean
638 mono_isfinite (double a)
640 #ifdef HAVE_ISFINITE
641 return isfinite (a);
642 #else
643 g_assert_not_reached ();
644 return TRUE;
645 #endif
648 double
649 mono_fload_r4 (float *ptr)
651 return *ptr;
654 void
655 mono_fstore_r4 (double val, float *ptr)
657 *ptr = (float)val;
660 /* returns the integer bitpattern that is passed in the regs or stack */
661 guint32
662 mono_fload_r4_arg (double val)
664 float v = (float)val;
665 return *(guint32*)&v;
668 #endif
670 MonoArray *
671 mono_array_new_va (MonoMethod *cm, ...)
673 MonoError error;
674 MonoArray *arr;
675 MonoDomain *domain = mono_domain_get ();
676 va_list ap;
677 uintptr_t *lengths;
678 intptr_t *lower_bounds;
679 int pcount;
680 int rank;
681 int i, d;
683 pcount = mono_method_signature (cm)->param_count;
684 rank = cm->klass->rank;
686 va_start (ap, cm);
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);
697 } else {
698 lower_bounds = NULL;
700 } else {
701 g_assert (pcount == (rank * 2));
702 /* lower bounds are first. */
703 lower_bounds = (intptr_t*)lengths;
704 lengths += rank;
706 va_end(ap);
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);
712 return NULL;
715 return arr;
718 /* Specialized version of mono_array_new_va () which avoids varargs */
719 MonoArray *
720 mono_array_new_1 (MonoMethod *cm, guint32 length)
722 MonoError error;
723 MonoArray *arr;
724 MonoDomain *domain = mono_domain_get ();
725 uintptr_t lengths [1];
726 intptr_t *lower_bounds;
727 int pcount;
728 int rank;
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);
740 } else {
741 lower_bounds = NULL;
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);
748 return NULL;
751 return arr;
754 MonoArray *
755 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
757 MonoError error;
758 MonoArray *arr;
759 MonoDomain *domain = mono_domain_get ();
760 uintptr_t lengths [2];
761 intptr_t *lower_bounds;
762 int pcount;
763 int rank;
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);
776 } else {
777 lower_bounds = NULL;
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);
784 return NULL;
787 return arr;
790 MonoArray *
791 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
793 MonoError error;
794 MonoArray *arr;
795 MonoDomain *domain = mono_domain_get ();
796 uintptr_t lengths [3];
797 intptr_t *lower_bounds;
798 int pcount;
799 int rank;
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);
813 } else {
814 lower_bounds = NULL;
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);
821 return NULL;
824 return arr;
827 MonoArray *
828 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
830 MonoError error;
831 MonoArray *arr;
832 MonoDomain *domain = mono_domain_get ();
833 uintptr_t lengths [4];
834 intptr_t *lower_bounds;
835 int pcount;
836 int rank;
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);
851 } else {
852 lower_bounds = NULL;
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);
859 return NULL;
862 return arr;
865 gpointer
866 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
868 MonoError error;
869 MonoVTable *vtable;
870 gpointer addr;
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);
879 return NULL;
881 if (!vtable->initialized) {
882 if (!mono_runtime_class_init_full (vtable, &error)) {
883 mono_error_set_pending_exception (&error);
884 return NULL;
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));
892 else
893 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
895 return addr;
898 gpointer
899 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
901 MonoError error;
902 MonoClass *handle_class;
903 gpointer res;
905 res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
906 if (!mono_error_ok (&error)) {
907 mono_error_set_pending_exception (&error);
908 return NULL;
910 mono_class_init (handle_class);
912 return res;
915 gpointer
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);
923 } else {
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);
932 guint64
933 mono_fconv_u8 (double v)
935 return (guint64)v;
938 guint64
939 mono_rconv_u8 (float v)
941 return (guint64)v;
944 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
945 gint64
946 mono_fconv_i8 (double v)
948 return (gint64)v;
950 #endif
952 guint32
953 mono_fconv_u4 (double v)
955 /* MS.NET behaves like this for some reason */
956 #ifdef HAVE_ISINF
957 if (isinf (v) || isnan (v))
958 return 0;
959 #endif
961 return (guint32)v;
964 #ifndef HAVE_TRUNC
965 /* Solaris doesn't have trunc */
966 #ifdef HAVE_AINTL
967 extern long double aintl (long double);
968 #define trunc aintl
969 #else
970 /* FIXME: This means we will never throw overflow exceptions */
971 #define trunc(v) res
972 #endif
973 #endif /* HAVE_TRUNC */
975 gint64
976 mono_fconv_ovf_i8 (double v)
978 gint64 res;
980 res = (gint64)v;
982 if (isnan(v) || trunc (v) != res) {
983 mono_set_pending_exception (mono_get_exception_overflow ());
984 return 0;
986 return res;
989 guint64
990 mono_fconv_ovf_u8 (double v)
992 guint64 res;
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
997 * as a double.
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 ());
1006 return 0;
1008 res = (guint64)v;
1009 #else
1010 res = (guint64)v;
1011 if (isnan(v) || trunc (v) != res) {
1012 mono_set_pending_exception (mono_get_exception_overflow ());
1013 return 0;
1015 #endif
1016 return res;
1019 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1020 gint64
1021 mono_rconv_i8 (float v)
1023 return (gint64)v;
1025 #endif
1027 gint64
1028 mono_rconv_ovf_i8 (float v)
1030 gint64 res;
1032 res = (gint64)v;
1034 if (isnan(v) || trunc (v) != res) {
1035 mono_set_pending_exception (mono_get_exception_overflow ());
1036 return 0;
1038 return res;
1041 guint64
1042 mono_rconv_ovf_u8 (float v)
1044 guint64 res;
1046 res = (guint64)v;
1047 if (isnan(v) || trunc (v) != res) {
1048 mono_set_pending_exception (mono_get_exception_overflow ());
1049 return 0;
1051 return res;
1054 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1055 double
1056 mono_lconv_to_r8 (gint64 a)
1058 return (double)a;
1060 #endif
1062 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1063 float
1064 mono_lconv_to_r4 (gint64 a)
1066 return (float)a;
1068 #endif
1070 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1071 double
1072 mono_conv_to_r8_un (guint32 a)
1074 return (double)a;
1076 #endif
1078 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1079 double
1080 mono_lconv_to_r8_un (guint64 a)
1082 return (double)a;
1084 #endif
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*/
1089 double
1090 mono_fmod(double a, double b)
1092 return fmod(a, b);
1094 #endif
1096 gpointer
1097 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1099 MonoError error;
1100 MonoMethod *vmethod;
1101 gpointer addr;
1102 MonoGenericContext *context = mono_method_get_context (method);
1104 mono_jit_stats.generic_virtual_invocations++;
1106 if (obj == NULL) {
1107 mono_set_pending_exception (mono_get_exception_null_reference ());
1108 return NULL;
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))
1117 return NULL;
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);
1124 else
1125 *this_arg = obj;
1127 return addr;
1130 MonoString*
1131 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1133 MonoError error;
1134 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
1135 mono_error_set_pending_exception (&error);
1136 return result;
1139 MonoString*
1140 mono_helper_ldstr (MonoImage *image, guint32 idx)
1142 MonoError error;
1143 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, &error);
1144 mono_error_set_pending_exception (&error);
1145 return result;
1148 MonoString*
1149 mono_helper_ldstr_mscorlib (guint32 idx)
1151 MonoError error;
1152 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, &error);
1153 mono_error_set_pending_exception (&error);
1154 return result;
1157 MonoObject*
1158 mono_helper_newobj_mscorlib (guint32 idx)
1160 MonoError error;
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);
1165 return NULL;
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);
1171 return obj;
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
1177 * breakpoint here.
1179 void
1180 mono_break (void)
1184 MonoException *
1185 mono_create_corlib_exception_0 (guint32 token)
1187 return mono_exception_from_token (mono_defaults.corlib, token);
1190 MonoException *
1191 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1193 MonoError error;
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);
1197 return ret;
1200 MonoException *
1201 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1203 MonoError error;
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);
1207 return ret;
1210 MonoObject*
1211 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1213 MonoError error;
1214 MonoJitTlsData *jit_tls = NULL;
1215 MonoClass *oklass;
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;
1222 if (!obj)
1223 return NULL;
1225 oklass = obj->vtable->klass;
1226 if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1227 return obj;
1228 if (mono_object_isinst_checked (obj, klass, &error))
1229 return obj;
1230 if (mono_error_set_pending_exception (&error))
1231 return NULL;
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"));
1241 return NULL;
1244 MonoObject*
1245 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1247 MonoError error;
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;
1256 if (!obj)
1257 return NULL;
1259 cached_vtable = *cache;
1260 obj_vtable = obj->vtable;
1262 if (cached_vtable == obj_vtable)
1263 return obj;
1265 if (mono_object_isinst_checked (obj, klass, &error)) {
1266 *cache = obj_vtable;
1267 return obj;
1269 if (mono_error_set_pending_exception (&error))
1270 return NULL;
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"));
1280 return NULL;
1283 MonoObject*
1284 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1286 MonoError error;
1287 size_t cached_vtable, obj_vtable;
1289 if (!obj)
1290 return NULL;
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;
1301 return obj;
1302 } else {
1303 if (mono_error_set_pending_exception (&error))
1304 return NULL;
1305 /*negative cache*/
1306 *cache = (gpointer)(obj_vtable | 0x1);
1307 return NULL;
1311 gpointer
1312 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1314 MonoError error;
1315 MonoMarshalSpec **mspecs;
1316 MonoMethodPInvoke piinfo;
1317 MonoMethod *m;
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;
1329 static MonoMethod*
1330 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1332 MonoMethod *m;
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);
1350 } else {
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
1374 *this_arg = mp;
1375 else
1377 * Calling a non-vtype method
1379 *this_arg = *(gpointer*)mp;
1380 return m;
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 ().
1389 MonoObject*
1390 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1392 MonoError error;
1393 MonoObject *o;
1394 MonoMethod *m;
1395 gpointer this_arg;
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);
1401 return NULL;
1404 if (!m)
1405 return NULL;
1406 if (args && deref_arg) {
1407 new_args [0] = *(gpointer*)args [0];
1408 args = new_args;
1410 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1411 /* Object.GetType () */
1412 args = new_args;
1413 args [0] = this_arg;
1414 this_arg = NULL;
1417 o = mono_runtime_invoke_checked (m, this_arg, args, &error);
1418 if (!mono_error_ok (&error)) {
1419 mono_error_set_pending_exception (&error);
1420 return NULL;
1423 return o;
1426 void
1427 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1429 if (klass->valuetype)
1430 mono_value_copy (dest, src, klass);
1431 else
1432 mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1435 void
1436 ves_icall_runtime_class_init (MonoVTable *vtable)
1438 MONO_REQ_GC_UNSAFE_MODE;
1439 MonoError error;
1441 mono_runtime_class_init_full (vtable, &error);
1442 mono_error_set_pending_exception (&error);
1446 void
1447 mono_generic_class_init (MonoVTable *vtable)
1449 MonoError error;
1450 mono_runtime_class_init_full (vtable, &error);
1451 mono_error_set_pending_exception (&error);
1454 void
1455 ves_icall_mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
1457 MonoError error;
1458 mono_delegate_ctor (this_obj, target, addr, &error);
1459 mono_error_set_pending_exception (&error);
1462 gpointer
1463 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1465 MonoError error;
1466 gpointer res;
1468 res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1469 if (!mono_error_ok (&error)) {
1470 mono_error_set_pending_exception (&error);
1471 return NULL;
1473 return res;
1476 gpointer
1477 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1479 MonoError error;
1480 gpointer res;
1482 res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1483 if (!mono_error_ok (&error)) {
1484 mono_error_set_pending_exception (&error);
1485 return NULL;
1487 return res;
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
1496 * out parameter.
1498 static gpointer
1499 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt, MonoError *error)
1501 MonoVTable *vt;
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);
1508 if (!this_obj)
1509 /* The caller will handle it */
1510 return NULL;
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);
1521 g_assert (addr);
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;
1529 } else {
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 (),
1540 vt, imt + imt_slot,
1541 target, addr);
1544 return addr;
1547 gpointer
1548 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1550 MonoError error;
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);
1556 return res;
1559 static gboolean
1560 is_generic_method_definition (MonoMethod *m)
1562 MonoGenericContext *context;
1563 if (m->is_generic)
1564 return TRUE;
1565 if (!m->is_inflated)
1566 return FALSE;
1568 context = mono_method_get_context (m);
1569 if (!context->method_inst)
1570 return FALSE;
1571 if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1572 return TRUE;
1573 return FALSE;
1577 * resolve_vcall:
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
1582 * out parameter.
1584 static gpointer
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;
1606 if (m->is_inflated)
1607 declaring = mono_method_get_declaring_generic_method (m);
1608 else
1609 declaring = m;
1611 if (m->klass->generic_class)
1612 context.class_inst = m->klass->generic_class->context.class_inst;
1613 else
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;
1628 } else {
1629 if (m->klass->valuetype)
1630 need_unbox_tramp = TRUE;
1633 // FIXME: This can throw exceptions
1634 addr = compiled_method = mono_compile_method_checked (m, error);
1635 mono_error_assert_ok (error);
1636 g_assert (addr);
1638 addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1640 if (!gsharedvt && generic_virtual) {
1641 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1642 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1644 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1645 vt, vt->vtable + slot,
1646 generic_virtual, ftndesc);
1649 return addr;
1652 gpointer
1653 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1655 g_assert (this_obj);
1657 MonoError error;
1658 gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, &error);
1659 if (!is_ok (&error)) {
1660 MonoException *ex = mono_error_convert_to_exception (&error);
1661 mono_llvm_throw_exception ((MonoObject*)ex);
1663 return result;
1667 * mono_resolve_generic_virtual_call:
1669 * Resolve a generic virtual call.
1670 * This function is called on a slowpath, so it doesn't need to be fast.
1672 MonoFtnDesc*
1673 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1675 MonoMethod *m;
1676 gpointer addr, compiled_method;
1677 gboolean need_unbox_tramp = FALSE;
1678 MonoError error;
1679 MonoGenericContext context = { NULL, NULL };
1680 MonoMethod *declaring;
1681 gpointer arg = NULL;
1683 m = mono_class_get_vtable_entry (vt->klass, slot);
1685 g_assert (is_generic_method_definition (m));
1687 if (m->is_inflated)
1688 declaring = mono_method_get_declaring_generic_method (m);
1689 else
1690 declaring = m;
1692 if (m->klass->generic_class)
1693 context.class_inst = m->klass->generic_class->context.class_inst;
1694 else
1695 g_assert (!m->klass->generic_container);
1697 g_assert (generic_virtual->is_inflated);
1698 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1700 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1701 g_assert (mono_error_ok (&error));
1703 if (vt->klass->valuetype)
1704 need_unbox_tramp = TRUE;
1706 // FIXME: This can throw exceptions
1707 addr = compiled_method = mono_compile_method_checked (m, &error);
1708 mono_error_assert_ok (&error);
1709 g_assert (addr);
1711 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1714 * This wastes memory but the memory usage is bounded since
1715 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1716 * this vtable slot so we are not called any more for this instantiation.
1718 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1720 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1721 vt, vt->vtable + slot,
1722 generic_virtual, ftndesc);
1723 return ftndesc;
1727 * mono_resolve_generic_virtual_call:
1729 * Resolve a generic virtual/variant iface call on interfaces.
1730 * This function is called on a slowpath, so it doesn't need to be fast.
1732 MonoFtnDesc*
1733 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1735 MonoError error;
1736 MonoMethod *m, *variant_iface;
1737 gpointer addr, aot_addr, compiled_method;
1738 gboolean need_unbox_tramp = FALSE;
1739 gboolean need_rgctx_tramp;
1740 gpointer arg = NULL;
1741 gpointer *imt;
1743 imt = (gpointer*)vt - MONO_IMT_SIZE;
1745 mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, &error);
1746 if (!is_ok (&error)) {
1747 MonoException *ex = mono_error_convert_to_exception (&error);
1748 mono_llvm_throw_exception ((MonoObject*)ex);
1751 if (vt->klass->valuetype)
1752 need_unbox_tramp = TRUE;
1754 // FIXME: This can throw exceptions
1755 addr = compiled_method = mono_compile_method_checked (m, &error);
1756 mono_error_assert_ok (&error);
1757 g_assert (addr);
1759 addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1762 * This wastes memory but the memory usage is bounded since
1763 * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1764 * this vtable slot so we are not called any more for this instantiation.
1766 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1768 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1769 vt, imt + imt_slot,
1770 variant_iface ? variant_iface : generic_virtual, ftndesc);
1771 return ftndesc;
1775 * mono_init_vtable_slot:
1777 * Initialize slot SLOT of VTABLE.
1778 * Return the contents of the vtable slot.
1780 gpointer
1781 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1783 MonoError error;
1784 gpointer arg = NULL;
1785 gpointer addr;
1786 gpointer *ftnptr;
1788 addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE, &error);
1789 if (mono_error_set_pending_exception (&error))
1790 return NULL;
1791 ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1792 ftnptr [0] = addr;
1793 ftnptr [1] = arg;
1794 mono_memory_barrier ();
1796 vtable->vtable [slot] = ftnptr;
1798 return ftnptr;
1802 * mono_llvmonly_init_delegate:
1804 * Initialize a MonoDelegate object.
1805 * Similar to mono_delegate_ctor ().
1807 void
1808 mono_llvmonly_init_delegate (MonoDelegate *del)
1810 MonoError error;
1811 MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1814 * We store a MonoFtnDesc in del->method_code.
1815 * It would be better to store an ftndesc in del->method_ptr too,
1816 * but we don't have a a structure which could own its memory.
1818 if (G_UNLIKELY (!ftndesc)) {
1819 gpointer addr = mono_compile_method_checked (del->method, &error);
1820 if (mono_error_set_pending_exception (&error))
1821 return;
1823 if (del->method->klass->valuetype && mono_method_signature (del->method)->hasthis)
1824 addr = mono_aot_get_unbox_trampoline (del->method);
1826 gpointer arg = mini_get_delegate_arg (del->method, addr);
1828 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1829 mono_memory_barrier ();
1830 *del->method_code = (gpointer)ftndesc;
1832 del->method_ptr = ftndesc->addr;
1833 del->extra_arg = ftndesc->arg;
1836 void
1837 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1839 MonoError error;
1841 g_assert (target);
1843 method = mono_object_get_virtual_method (target, method);
1845 del->method = method;
1846 del->method_ptr = mono_compile_method_checked (method, &error);
1847 if (mono_error_set_pending_exception (&error))
1848 return;
1849 if (method->klass->valuetype)
1850 del->method_ptr = mono_aot_get_unbox_trampoline (method);
1851 del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1854 MonoObject*
1855 mono_get_assembly_object (MonoImage *image)
1857 MonoError error;
1858 MonoObject *result;
1859 result = (MonoObject*)mono_assembly_get_object_checked (mono_domain_get (), image->assembly, &error);
1860 if (!result)
1861 mono_error_set_pending_exception (&error);
1862 return result;
1865 MonoObject*
1866 mono_get_method_object (MonoMethod *method)
1868 MonoError error;
1869 MonoObject * result;
1870 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, &error);
1871 mono_error_set_pending_exception (&error);
1872 return result;
1875 double
1876 mono_ckfinite (double d)
1878 if (isinf (d) || isnan (d))
1879 mono_set_pending_exception (mono_get_exception_arithmetic ());
1880 return d;
1884 * mono_interruption_checkpoint_from_trampoline:
1886 * Check whenever the thread has a pending exception, and throw it
1887 * if needed.
1888 * Architectures should move away from calling this function and
1889 * instead call mono_thread_force_interruption_checkpoint_noraise (),
1890 * rewrind to the parent frame, and throw the exception normally.
1892 void
1893 mono_interruption_checkpoint_from_trampoline (void)
1895 MonoException *ex;
1897 ex = mono_thread_force_interruption_checkpoint_noraise ();
1898 if (ex)
1899 mono_raise_exception (ex);
1902 void
1903 mono_throw_method_access (MonoMethod *callee, MonoMethod *caller)
1905 char *callee_name = mono_method_full_name (callee, 1);
1906 char *caller_name = mono_method_full_name (caller, 1);
1907 MonoError error;
1909 mono_error_init (&error);
1910 mono_error_set_generic_error (&error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'\n", callee_name, caller_name);
1911 mono_error_set_pending_exception (&error);
1912 g_free (callee_name);
1913 g_free (caller_name);