[jit] Constant folding for some Math operations on doubles (#9281)
[mono-project.git] / mono / mini / jit-icalls.c
blob63a5ba76dbe74b4f5999c1e4cb75d71a5f9c6c48
1 /**
2 * \file
3 * internal calls used by the JIT
5 * Author:
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.
14 #include <config.h>
15 #include <math.h>
16 #include <limits.h>
17 #ifdef HAVE_ALLOCA_H
18 #include <alloca.h>
19 #endif
21 #include "jit-icalls.h"
22 #include "aot-runtime.h"
23 #include "mini-runtime.h"
24 #include <mono/utils/mono-error-internals.h>
25 #include <mono/metadata/exception-internals.h>
26 #include <mono/metadata/threads-types.h>
27 #include <mono/metadata/reflection-internals.h>
28 #include <mono/utils/unlocked.h>
29 #include <mono/utils/mono-math.h>
31 #ifdef ENABLE_LLVM
32 #include "mini-llvm-cpp.h"
33 #endif
35 void*
36 mono_ldftn (MonoMethod *method)
38 gpointer addr;
39 ERROR_DECL (error);
41 if (mono_llvm_only) {
42 // FIXME: No error handling
44 addr = mono_compile_method_checked (method, error);
45 mono_error_assert_ok (error);
46 g_assert (addr);
48 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
49 /* The caller doesn't pass it */
50 g_assert_not_reached ();
52 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
53 return addr;
56 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error);
57 if (!mono_error_ok (error)) {
58 mono_error_set_pending_exception (error);
59 return NULL;
61 return mono_create_ftnptr (mono_domain_get (), addr);
64 static void*
65 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
67 ERROR_DECL (error);
68 MonoMethod *res;
70 if (obj == NULL) {
71 mono_error_set_null_reference (error);
72 mono_error_set_pending_exception (error);
73 return NULL;
76 res = mono_object_get_virtual_method_internal (obj, method);
78 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
79 MonoGenericContext context = { NULL, NULL };
81 if (mono_class_is_ginst (res->klass))
82 context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
83 else if (mono_class_is_gtd (res->klass))
84 context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
85 context.method_inst = mono_method_get_context (method)->method_inst;
87 res = mono_class_inflate_generic_method_checked (res, &context, error);
88 if (!mono_error_ok (error)) {
89 mono_error_set_pending_exception (error);
90 return NULL;
94 /* An rgctx wrapper is added by the trampolines no need to do it here */
96 return mono_ldftn (res);
99 void*
100 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
102 return ldvirtfn_internal (obj, method, FALSE);
105 void*
106 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
108 return ldvirtfn_internal (obj, method, TRUE);
111 void
112 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
114 ERROR_DECL (error);
115 if (!array) {
116 mono_error_set_null_reference (error);
117 mono_error_set_pending_exception (error);
118 return;
120 if (val && !mono_object_isinst_checked (val, m_class_get_element_class (mono_object_class (array)), error)) {
121 if (mono_error_set_pending_exception (error))
122 return;
123 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
124 return;
128 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
130 gint64
131 mono_llmult (gint64 a, gint64 b)
133 return a * b;
136 guint64
137 mono_llmult_ovf_un (guint64 a, guint64 b)
139 guint32 al = a;
140 guint32 ah = a >> 32;
141 guint32 bl = b;
142 guint32 bh = b >> 32;
143 guint64 res, t1;
145 // fixme: this is incredible slow
147 if (ah && bh)
148 goto raise_exception;
150 res = (guint64)al * (guint64)bl;
152 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
154 if (t1 > 0xffffffff)
155 goto raise_exception;
157 res += ((guint64)t1) << 32;
159 return res;
161 raise_exception:
163 ERROR_DECL (error);
164 mono_error_set_overflow (error);
165 mono_error_set_pending_exception (error);
167 return 0;
170 guint64
171 mono_llmult_ovf (gint64 a, gint64 b)
173 guint32 al = a;
174 gint32 ah = a >> 32;
175 guint32 bl = b;
176 gint32 bh = b >> 32;
178 Use Karatsuba algorithm where:
179 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
180 where Ah is the "high half" (most significant 32 bits) of a and
181 where Al is the "low half" (least significant 32 bits) of a and
182 where Bh is the "high half" of b and Bl is the "low half" and
183 where R is the Radix or "size of the half" (in our case 32 bits)
185 Note, for the product of two 64 bit numbers to fit into a 64
186 result, ah and/or bh must be 0. This will save us from doing
187 the AhBh term at all.
189 Also note that we refactor so that we don't overflow 64 bits with
190 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
193 gint64 res, t1;
194 gint32 sign;
196 /* need to work with absoulte values, so find out what the
197 resulting sign will be and convert any negative numbers
198 from two's complement
200 sign = ah ^ bh;
201 if (ah < 0) {
202 if (((guint32)ah == 0x80000000) && (al == 0)) {
203 /* This has no two's complement */
204 if (b == 0)
205 return 0;
206 else if (b == 1)
207 return a;
208 else
209 goto raise_exception;
212 /* flip the bits and add 1 */
213 ah ^= ~0;
214 if (al == 0)
215 ah += 1;
216 else {
217 al ^= ~0;
218 al +=1;
222 if (bh < 0) {
223 if (((guint32)bh == 0x80000000) && (bl == 0)) {
224 /* This has no two's complement */
225 if (a == 0)
226 return 0;
227 else if (a == 1)
228 return b;
229 else
230 goto raise_exception;
233 /* flip the bits and add 1 */
234 bh ^= ~0;
235 if (bl == 0)
236 bh += 1;
237 else {
238 bl ^= ~0;
239 bl +=1;
243 /* we overflow for sure if both upper halves are greater
244 than zero because we would need to shift their
245 product 64 bits to the left and that will not fit
246 in a 64 bit result */
247 if (ah && bh)
248 goto raise_exception;
249 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
250 goto raise_exception;
252 /* do the AlBl term first */
253 t1 = (gint64)al * (gint64)bl;
255 res = t1;
257 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
258 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
259 /* check for overflow */
260 t1 <<= 32;
261 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
262 goto raise_exception;
264 res += t1;
266 if (res < 0)
267 goto raise_exception;
269 if (sign < 0)
270 return -res;
271 else
272 return res;
274 raise_exception:
276 ERROR_DECL (error);
277 mono_error_set_overflow (error);
278 mono_error_set_pending_exception (error);
280 return 0;
283 gint64
284 mono_lldiv (gint64 a, gint64 b)
286 #ifdef MONO_ARCH_NEED_DIV_CHECK
287 if (!b) {
288 ERROR_DECL (error);
289 mono_error_set_divide_by_zero (error);
290 mono_error_set_pending_exception (error);
291 return 0;
293 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
294 ERROR_DECL (error);
295 mono_error_set_overflow (error);
296 mono_error_set_pending_exception (error);
297 return 0;
299 #endif
300 return a / b;
303 gint64
304 mono_llrem (gint64 a, gint64 b)
306 #ifdef MONO_ARCH_NEED_DIV_CHECK
307 if (!b) {
308 ERROR_DECL (error);
309 mono_error_set_divide_by_zero (error);
310 mono_error_set_pending_exception (error);
311 return 0;
313 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
314 ERROR_DECL (error);
315 mono_error_set_overflow (error);
316 mono_error_set_pending_exception (error);
317 return 0;
319 #endif
320 return a % b;
323 guint64
324 mono_lldiv_un (guint64 a, guint64 b)
326 #ifdef MONO_ARCH_NEED_DIV_CHECK
327 if (!b) {
328 ERROR_DECL (error);
329 mono_error_set_divide_by_zero (error);
330 mono_error_set_pending_exception (error);
331 return 0;
333 #endif
334 return a / b;
337 guint64
338 mono_llrem_un (guint64 a, guint64 b)
340 #ifdef MONO_ARCH_NEED_DIV_CHECK
341 if (!b) {
342 ERROR_DECL (error);
343 mono_error_set_divide_by_zero (error);
344 mono_error_set_pending_exception (error);
345 return 0;
347 #endif
348 return a % b;
351 #endif
353 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
355 guint64
356 mono_lshl (guint64 a, gint32 shamt)
358 const guint64 res = a << (shamt & 0x7f);
360 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
362 return res;
365 guint64
366 mono_lshr_un (guint64 a, gint32 shamt)
368 const guint64 res = a >> (shamt & 0x7f);
370 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
372 return res;
375 gint64
376 mono_lshr (gint64 a, gint32 shamt)
378 const gint64 res = a >> (shamt & 0x7f);
380 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
382 return res;
385 #endif
387 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
389 gint32
390 mono_idiv (gint32 a, gint32 b)
392 #ifdef MONO_ARCH_NEED_DIV_CHECK
393 if (!b) {
394 ERROR_DECL (error);
395 mono_error_set_divide_by_zero (error);
396 mono_error_set_pending_exception (error);
397 return 0;
399 else if (b == -1 && a == (0x80000000)) {
400 ERROR_DECL (error);
401 mono_error_set_overflow (error);
402 mono_error_set_pending_exception (error);
403 return 0;
405 #endif
406 return a / b;
409 guint32
410 mono_idiv_un (guint32 a, guint32 b)
412 #ifdef MONO_ARCH_NEED_DIV_CHECK
413 if (!b) {
414 ERROR_DECL (error);
415 mono_error_set_divide_by_zero (error);
416 mono_error_set_pending_exception (error);
417 return 0;
419 #endif
420 return a / b;
423 gint32
424 mono_irem (gint32 a, gint32 b)
426 #ifdef MONO_ARCH_NEED_DIV_CHECK
427 if (!b) {
428 ERROR_DECL (error);
429 mono_error_set_divide_by_zero (error);
430 mono_error_set_pending_exception (error);
431 return 0;
433 else if (b == -1 && a == (0x80000000)) {
434 ERROR_DECL (error);
435 mono_error_set_overflow (error);
436 mono_error_set_pending_exception (error);
437 return 0;
439 #endif
440 return a % b;
443 guint32
444 mono_irem_un (guint32 a, guint32 b)
446 #ifdef MONO_ARCH_NEED_DIV_CHECK
447 if (!b) {
448 ERROR_DECL (error);
449 mono_error_set_divide_by_zero (error);
450 mono_error_set_pending_exception (error);
451 return 0;
453 #endif
454 return a % b;
457 #endif
459 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
461 gint32
462 mono_imul (gint32 a, gint32 b)
464 return a * b;
467 gint32
468 mono_imul_ovf (gint32 a, gint32 b)
470 const gint64 res = (gint64)a * (gint64)b;
472 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
473 ERROR_DECL (error);
474 mono_error_set_overflow (error);
475 mono_error_set_pending_exception (error);
476 return 0;
479 return res;
482 gint32
483 mono_imul_ovf_un (guint32 a, guint32 b)
485 const guint64 res = (guint64)a * (guint64)b;
487 if (res >> 32) {
488 ERROR_DECL (error);
489 mono_error_set_overflow (error);
490 mono_error_set_pending_exception (error);
491 return 0;
494 return res;
496 #endif
498 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
499 double
500 mono_fdiv (double a, double b)
502 return a / b;
504 #endif
506 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
508 double
509 mono_fsub (double a, double b)
511 return a - b;
514 double
515 mono_fadd (double a, double b)
517 return a + b;
520 double
521 mono_fmul (double a, double b)
523 return a * b;
526 double
527 mono_fneg (double a)
529 return -a;
532 double
533 mono_fconv_r4 (double a)
535 return (float)a;
538 double
539 mono_conv_to_r8 (int a)
541 return (double)a;
544 double
545 mono_conv_to_r4 (int a)
547 return (double)(float)a;
550 gint8
551 mono_fconv_i1 (double a)
553 return (gint8)a;
556 gint16
557 mono_fconv_i2 (double a)
559 return (gint16)a;
562 gint32
563 mono_fconv_i4 (double a)
565 return (gint32)a;
568 guint8
569 mono_fconv_u1 (double a)
571 return (guint8)a;
574 guint16
575 mono_fconv_u2 (double a)
577 return (guint16)a;
580 gboolean
581 mono_fcmp_eq (double a, double b)
583 return a == b;
586 gboolean
587 mono_fcmp_ge (double a, double b)
589 return a >= b;
592 gboolean
593 mono_fcmp_gt (double a, double b)
595 return a > b;
598 gboolean
599 mono_fcmp_le (double a, double b)
601 return a <= b;
604 gboolean
605 mono_fcmp_lt (double a, double b)
607 return a < b;
610 gboolean
611 mono_fcmp_ne_un (double a, double b)
613 return isunordered (a, b) || a != b;
616 gboolean
617 mono_fcmp_ge_un (double a, double b)
619 return isunordered (a, b) || a >= b;
622 gboolean
623 mono_fcmp_gt_un (double a, double b)
625 return isunordered (a, b) || a > b;
628 gboolean
629 mono_fcmp_le_un (double a, double b)
631 return isunordered (a, b) || a <= b;
634 gboolean
635 mono_fcmp_lt_un (double a, double b)
637 return isunordered (a, b) || a < b;
640 gboolean
641 mono_fceq (double a, double b)
643 return a == b;
646 gboolean
647 mono_fcgt (double a, double b)
649 return a > b;
652 gboolean
653 mono_fcgt_un (double a, double b)
655 return isunordered (a, b) || a > b;
658 gboolean
659 mono_fclt (double a, double b)
661 return a < b;
664 gboolean
665 mono_fclt_un (double a, double b)
667 return isunordered (a, b) || a < b;
670 double
671 mono_fload_r4 (float *ptr)
673 return *ptr;
676 void
677 mono_fstore_r4 (double val, float *ptr)
679 *ptr = (float)val;
682 /* returns the integer bitpattern that is passed in the regs or stack */
683 guint32
684 mono_fload_r4_arg (double val)
686 float v = (float)val;
687 return *(guint32*)&v;
690 #endif
692 MonoArray *
693 mono_array_new_n_icall (MonoMethod *cm, gint32 pcount, intptr_t *params)
695 ERROR_DECL (error);
696 g_assert (cm);
697 g_assert (pcount);
698 g_assert (params);
699 intptr_t *lower_bounds = NULL;
701 const int pcount_sig = mono_method_signature_internal (cm)->param_count;
702 const int rank = m_class_get_rank (cm->klass);
703 g_assert (pcount == pcount_sig);
704 g_assert (rank == pcount || rank * 2 == pcount);
706 uintptr_t *lengths = (uintptr_t*)params;
708 if (rank == pcount) {
709 /* Only lengths provided. */
710 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
711 lower_bounds = g_newa (intptr_t, rank);
712 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
714 } else {
715 g_assert (pcount == (rank * 2));
716 /* lower bounds are first. */
717 lower_bounds = params;
718 lengths += rank;
721 MonoArray *arr = mono_array_new_full_checked (mono_domain_get (),
722 cm->klass, lengths, lower_bounds, error);
724 return mono_error_set_pending_exception (error) ? NULL : arr;
727 /* Specialized version of mono_array_new_va () which avoids varargs */
728 MonoArray *
729 mono_array_new_1 (MonoMethod *cm, guint32 length)
731 ERROR_DECL (error);
732 MonoArray *arr;
733 MonoDomain *domain = mono_domain_get ();
734 uintptr_t lengths [1];
735 intptr_t *lower_bounds;
736 int pcount;
737 int rank;
739 pcount = mono_method_signature_internal (cm)->param_count;
740 rank = m_class_get_rank (cm->klass);
742 lengths [0] = length;
744 g_assert (rank == pcount);
746 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
747 lower_bounds = g_newa (intptr_t, rank);
748 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
749 } else {
750 lower_bounds = NULL;
753 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, error);
755 if (!mono_error_ok (error)) {
756 mono_error_set_pending_exception (error);
757 return NULL;
760 return arr;
763 MonoArray *
764 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
766 ERROR_DECL (error);
767 MonoArray *arr;
768 MonoDomain *domain = mono_domain_get ();
769 uintptr_t lengths [2];
770 intptr_t *lower_bounds;
771 int pcount;
772 int rank;
774 pcount = mono_method_signature_internal (cm)->param_count;
775 rank = m_class_get_rank (cm->klass);
777 lengths [0] = length1;
778 lengths [1] = length2;
780 g_assert (rank == pcount);
782 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
783 lower_bounds = g_newa (intptr_t, rank);
784 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
785 } else {
786 lower_bounds = NULL;
789 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, error);
791 if (!mono_error_ok (error)) {
792 mono_error_set_pending_exception (error);
793 return NULL;
796 return arr;
799 MonoArray *
800 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
802 ERROR_DECL (error);
803 MonoArray *arr;
804 MonoDomain *domain = mono_domain_get ();
805 uintptr_t lengths [3];
806 intptr_t *lower_bounds;
807 int pcount;
808 int rank;
810 pcount = mono_method_signature_internal (cm)->param_count;
811 rank = m_class_get_rank (cm->klass);
813 lengths [0] = length1;
814 lengths [1] = length2;
815 lengths [2] = length3;
817 g_assert (rank == pcount);
819 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
820 lower_bounds = g_newa (intptr_t, rank);
821 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
822 } else {
823 lower_bounds = NULL;
826 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, error);
828 if (!mono_error_ok (error)) {
829 mono_error_set_pending_exception (error);
830 return NULL;
833 return arr;
836 MonoArray *
837 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
839 ERROR_DECL (error);
840 MonoArray *arr;
841 MonoDomain *domain = mono_domain_get ();
842 uintptr_t lengths [4];
843 intptr_t *lower_bounds;
844 int pcount;
845 int rank;
847 pcount = mono_method_signature_internal (cm)->param_count;
848 rank = m_class_get_rank (cm->klass);
850 lengths [0] = length1;
851 lengths [1] = length2;
852 lengths [2] = length3;
853 lengths [3] = length4;
855 g_assert (rank == pcount);
857 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
858 lower_bounds = g_newa (intptr_t, rank);
859 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
860 } else {
861 lower_bounds = NULL;
864 arr = mono_array_new_full_checked (domain, cm->klass, lengths, lower_bounds, error);
866 if (!mono_error_ok (error)) {
867 mono_error_set_pending_exception (error);
868 return NULL;
871 return arr;
874 gpointer
875 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
877 ERROR_DECL (error);
878 MonoVTable *vtable;
879 gpointer addr;
881 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
883 mono_class_init_internal (field->parent);
885 vtable = mono_class_vtable_checked (domain, field->parent, error);
886 if (!is_ok (error)) {
887 mono_error_set_pending_exception (error);
888 return NULL;
890 if (!vtable->initialized) {
891 if (!mono_runtime_class_init_full (vtable, error)) {
892 mono_error_set_pending_exception (error);
893 return NULL;
897 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
899 if (field->offset == -1) {
900 /* Special static */
901 g_assert (domain->special_static_fields);
902 mono_domain_lock (domain);
903 addr = g_hash_table_lookup (domain->special_static_fields, field);
904 mono_domain_unlock (domain);
905 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
906 } else {
907 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
909 return addr;
912 gpointer
913 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
915 ERROR_DECL (error);
916 MonoClass *handle_class;
917 gpointer res;
919 res = mono_ldtoken_checked (image, token, &handle_class, context, error);
920 if (!mono_error_ok (error)) {
921 mono_error_set_pending_exception (error);
922 return NULL;
924 mono_class_init_internal (handle_class);
926 return res;
929 gpointer
930 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
932 MonoMethodSignature *sig = mono_method_signature_internal (method);
933 MonoGenericContext *generic_context;
935 if (sig->is_inflated) {
936 generic_context = mono_method_get_context (method);
937 } else {
938 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
939 g_assert (generic_container);
940 generic_context = &generic_container->context;
943 return mono_ldtoken_wrapper (image, token, generic_context);
946 guint64
947 mono_fconv_u8 (double v)
949 return (guint64)v;
952 guint64
953 mono_fconv_u8_2 (double v)
955 // Separate from mono_fconv_u8 to avoid duplicate JIT icall.
957 // When there are duplicates, there is single instancing
958 // against function address that breaks stuff. For example,
959 // wrappers are only produced for one of them, breaking FullAOT.
960 return mono_fconv_u8 (v);
963 guint64
964 mono_rconv_u8 (float v)
966 return (guint64)v;
969 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
970 gint64
971 mono_fconv_i8 (double v)
973 return (gint64)v;
975 #endif
977 guint32
978 mono_fconv_u4 (double v)
980 /* MS.NET behaves like this for some reason */
981 if (mono_isinf (v) || mono_isnan (v))
982 return 0;
983 return (guint32)v;
986 guint32
987 mono_fconv_u4_2 (double v)
989 // Separate from mono_fconv_u4 to avoid duplicate JIT icall.
991 // When there are duplicates, there is single instancing
992 // against function address that breaks stuff. For example,
993 // wrappers are only produced for one of them, breaking FullAOT.
994 return mono_fconv_u4 (v);
997 gint64
998 mono_fconv_ovf_i8 (double v)
1000 const gint64 res = (gint64)v;
1002 if (mono_isnan (v) || mono_trunc (v) != res) {
1003 ERROR_DECL (error);
1004 mono_error_set_overflow (error);
1005 mono_error_set_pending_exception (error);
1006 return 0;
1008 return res;
1011 guint64
1012 mono_fconv_ovf_u8 (double v)
1014 guint64 res;
1017 * The soft-float implementation of some ARM devices have a buggy guin64 to double
1018 * conversion that it looses precision even when the integer if fully representable
1019 * as a double.
1021 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
1023 * To work around this issue we test for value boundaries instead.
1025 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
1026 if (mono_isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
1027 ERROR_DECL (error);
1028 mono_error_set_overflow (error);
1029 mono_error_set_pending_exception (error);
1030 return 0;
1032 res = (guint64)v;
1033 #else
1034 res = (guint64)v;
1035 if (mono_isnan (v) || mono_trunc (v) != res) {
1036 ERROR_DECL (error);
1037 mono_error_set_overflow (error);
1038 mono_error_set_pending_exception (error);
1039 return 0;
1041 #endif
1042 return res;
1045 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1046 gint64
1047 mono_rconv_i8 (float v)
1049 return (gint64)v;
1051 #endif
1053 gint64
1054 mono_rconv_ovf_i8 (float v)
1056 const gint64 res = (gint64)v;
1058 if (mono_isnan (v) || mono_trunc (v) != res) {
1059 ERROR_DECL (error);
1060 mono_error_set_overflow (error);
1061 mono_error_set_pending_exception (error);
1062 return 0;
1064 return res;
1067 guint64
1068 mono_rconv_ovf_u8 (float v)
1070 guint64 res;
1072 res = (guint64)v;
1073 if (mono_isnan (v) || mono_trunc (v) != res) {
1074 ERROR_DECL (error);
1075 mono_error_set_overflow (error);
1076 mono_error_set_pending_exception (error);
1077 return 0;
1079 return res;
1082 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1083 double
1084 mono_lconv_to_r8 (gint64 a)
1086 return (double)a;
1088 #endif
1090 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1091 float
1092 mono_lconv_to_r4 (gint64 a)
1094 return (float)a;
1096 #endif
1098 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1099 double
1100 mono_conv_to_r8_un (guint32 a)
1102 return (double)a;
1104 #endif
1106 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1107 double
1108 mono_lconv_to_r8_un (guint64 a)
1110 return (double)a;
1112 #endif
1114 gpointer
1115 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1117 ERROR_DECL (error);
1118 MonoMethod *vmethod;
1119 gpointer addr;
1120 MonoGenericContext *context = mono_method_get_context (method);
1122 UnlockedIncrement (&mono_jit_stats.generic_virtual_invocations);
1124 if (obj == NULL) {
1125 mono_error_set_null_reference (error);
1126 mono_error_set_pending_exception (error);
1127 return NULL;
1129 vmethod = mono_object_get_virtual_method_internal (obj, method);
1130 g_assert (!mono_class_is_gtd (vmethod->klass));
1131 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1132 g_assert (!context->method_inst || !context->method_inst->is_open);
1134 addr = mono_compile_method_checked (vmethod, error);
1135 if (mono_error_set_pending_exception (error))
1136 return NULL;
1137 g_assert (addr);
1139 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1141 /* Since this is a virtual call, have to unbox vtypes */
1142 if (m_class_is_valuetype (obj->vtable->klass))
1143 *this_arg = mono_object_unbox_internal (obj);
1144 else
1145 *this_arg = obj;
1147 return addr;
1150 MonoString*
1151 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1153 ERROR_DECL (error);
1154 MonoString *result = mono_ldstr_checked (domain, image, idx, error);
1155 mono_error_set_pending_exception (error);
1156 return result;
1159 MonoString*
1160 mono_helper_ldstr (MonoImage *image, guint32 idx)
1162 ERROR_DECL (error);
1163 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, error);
1164 mono_error_set_pending_exception (error);
1165 return result;
1168 MonoString*
1169 mono_helper_ldstr_mscorlib (guint32 idx)
1171 ERROR_DECL (error);
1172 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, error);
1173 mono_error_set_pending_exception (error);
1174 return result;
1177 MonoObject*
1178 mono_helper_newobj_mscorlib (guint32 idx)
1180 ERROR_DECL (error);
1181 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, error);
1183 if (!mono_error_ok (error)) {
1184 mono_error_set_pending_exception (error);
1185 return NULL;
1188 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, error);
1189 if (!mono_error_ok (error))
1190 mono_error_set_pending_exception (error);
1191 return obj;
1195 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1196 * in generated code. So instead we emit a call to this function and place a gdb
1197 * breakpoint here.
1199 void
1200 mono_break (void)
1204 MonoException *
1205 mono_create_corlib_exception_0 (guint32 token)
1207 return mono_exception_from_token (mono_defaults.corlib, token);
1210 MonoException *
1211 mono_create_corlib_exception_1 (guint32 token, MonoString *arg_raw)
1213 HANDLE_FUNCTION_ENTER ();
1214 ERROR_DECL (error);
1215 MONO_HANDLE_DCL (MonoString, arg);
1216 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1217 mono_defaults.corlib, token, arg, NULL_HANDLE_STRING, error);
1218 mono_error_set_pending_exception (error);
1219 HANDLE_FUNCTION_RETURN_OBJ (ret);
1222 MonoException *
1223 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1_raw, MonoString *arg2_raw)
1225 HANDLE_FUNCTION_ENTER ();
1226 ERROR_DECL (error);
1227 MONO_HANDLE_DCL (MonoString, arg1);
1228 MONO_HANDLE_DCL (MonoString, arg2);
1229 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1230 mono_defaults.corlib, token, arg1, arg2, error);
1231 mono_error_set_pending_exception (error);
1232 HANDLE_FUNCTION_RETURN_OBJ (ret);
1235 MonoObject*
1236 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1238 ERROR_DECL (error);
1239 MonoJitTlsData *jit_tls = NULL;
1240 MonoClass *oklass;
1242 if (mini_get_debug_options ()->better_cast_details) {
1243 jit_tls = mono_tls_get_jit_tls ();
1244 jit_tls->class_cast_from = NULL;
1247 if (!obj)
1248 return NULL;
1250 oklass = obj->vtable->klass;
1251 if ((m_class_is_enumtype (klass) && oklass == m_class_get_element_class (klass)) || (m_class_is_enumtype (oklass) && klass == m_class_get_element_class (oklass)))
1252 return obj;
1253 if (mono_object_isinst_checked (obj, klass, error))
1254 return obj;
1255 if (mono_error_set_pending_exception (error))
1256 return NULL;
1258 if (mini_get_debug_options ()->better_cast_details) {
1259 jit_tls->class_cast_from = oklass;
1260 jit_tls->class_cast_to = klass;
1263 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1264 "System", "InvalidCastException"));
1266 return NULL;
1269 MonoObject*
1270 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1272 ERROR_DECL (error);
1273 MonoJitTlsData *jit_tls = NULL;
1274 gpointer cached_vtable, obj_vtable;
1276 if (mini_get_debug_options ()->better_cast_details) {
1277 jit_tls = mono_tls_get_jit_tls ();
1278 jit_tls->class_cast_from = NULL;
1281 if (!obj)
1282 return NULL;
1284 cached_vtable = *cache;
1285 obj_vtable = obj->vtable;
1287 if (cached_vtable == obj_vtable)
1288 return obj;
1290 if (mono_object_isinst_checked (obj, klass, error)) {
1291 *cache = obj_vtable;
1292 return obj;
1294 if (mono_error_set_pending_exception (error))
1295 return NULL;
1297 if (mini_get_debug_options ()->better_cast_details) {
1298 jit_tls->class_cast_from = obj->vtable->klass;
1299 jit_tls->class_cast_to = klass;
1302 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1303 "System", "InvalidCastException"));
1305 return NULL;
1308 MonoObject*
1309 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1311 ERROR_DECL (error);
1312 size_t cached_vtable, obj_vtable;
1314 if (!obj)
1315 return NULL;
1317 cached_vtable = (size_t)*cache;
1318 obj_vtable = (size_t)obj->vtable;
1320 if ((cached_vtable & ~0x1) == obj_vtable) {
1321 return (cached_vtable & 0x1) ? NULL : obj;
1324 if (mono_object_isinst_checked (obj, klass, error)) {
1325 *cache = (gpointer)obj_vtable;
1326 return obj;
1327 } else {
1328 if (mono_error_set_pending_exception (error))
1329 return NULL;
1330 /*negative cache*/
1331 *cache = (gpointer)(obj_vtable | 0x1);
1332 return NULL;
1336 gpointer
1337 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1339 ERROR_DECL (error);
1340 MonoMarshalSpec **mspecs;
1341 MonoMethodPInvoke piinfo;
1342 MonoMethod *m;
1344 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1345 memset (&piinfo, 0, sizeof (piinfo));
1347 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1349 for (int i = sig->param_count; i >= 0; i--)
1350 if (mspecs [i])
1351 mono_metadata_free_marshal_spec (mspecs [i]);
1352 g_free (mspecs);
1354 gpointer compiled_ptr = mono_compile_method_checked (m, error);
1355 mono_error_set_pending_exception (error);
1356 g_assert (compiled_ptr);
1358 return compiled_ptr;
1361 static MonoMethod*
1362 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1364 MonoMethod *m;
1365 int vt_slot, iface_offset;
1366 gboolean is_iface = FALSE;
1368 error_init (error);
1370 if (mono_class_is_interface (klass)) {
1371 MonoObject *this_obj;
1373 is_iface = TRUE;
1375 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1376 this_obj = *(MonoObject**)mp;
1377 g_assert (this_obj);
1379 klass = this_obj->vtable->klass;
1382 if (mono_method_signature_internal (cmethod)->pinvoke) {
1383 /* Object.GetType () */
1384 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1385 } else {
1386 /* Lookup the virtual method */
1387 mono_class_setup_vtable (klass);
1388 g_assert (m_class_get_vtable (klass));
1389 vt_slot = mono_method_get_vtable_slot (cmethod);
1390 if (mono_class_is_interface (cmethod->klass)) {
1391 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1392 g_assert (iface_offset != -1);
1393 vt_slot += iface_offset;
1395 m = m_class_get_vtable (klass) [vt_slot];
1396 if (cmethod->is_inflated) {
1397 m = mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
1398 return_val_if_nok (error, NULL);
1402 if (m_class_is_valuetype (klass) && (m->klass == mono_defaults.object_class || m->klass == m_class_get_parent (mono_defaults.enum_class) || m->klass == mono_defaults.enum_class)) {
1404 * Calling a non-vtype method with a vtype receiver, has to box.
1406 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1407 } else if (m_class_is_valuetype (klass)) {
1408 if (is_iface) {
1410 * The original type is an interface, so the receiver is a ref,
1411 the called method is a vtype method, need to unbox.
1413 MonoObject *this_obj = *(MonoObject**)mp;
1415 *this_arg = mono_object_unbox_internal (this_obj);
1416 } else {
1418 * Calling a vtype method with a vtype receiver
1420 *this_arg = mp;
1422 } else {
1424 * Calling a non-vtype method
1426 *this_arg = *(gpointer*)mp;
1429 return m;
1433 * mono_gsharedvt_constrained_call:
1435 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1436 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1438 MonoObject*
1439 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1441 ERROR_DECL (error);
1442 MonoObject *o;
1443 MonoMethod *m;
1444 gpointer this_arg;
1445 gpointer new_args [16];
1447 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, error);
1448 if (!mono_error_ok (error)) {
1449 mono_error_set_pending_exception (error);
1450 return NULL;
1453 if (!m)
1454 return NULL;
1455 if (args && deref_arg) {
1456 new_args [0] = *(gpointer*)args [0];
1457 args = new_args;
1459 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1460 /* Object.GetType () */
1461 args = new_args;
1462 args [0] = this_arg;
1463 this_arg = NULL;
1466 o = mono_runtime_invoke_checked (m, this_arg, args, error);
1467 if (!mono_error_ok (error)) {
1468 mono_error_set_pending_exception (error);
1469 return NULL;
1472 return o;
1475 void
1476 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1478 if (m_class_is_valuetype (klass))
1479 mono_value_copy_internal (dest, src, klass);
1480 else
1481 mono_gc_wbarrier_generic_store_internal (dest, *(MonoObject**)src);
1484 void
1485 ves_icall_runtime_class_init (MonoVTable *vtable)
1487 MONO_REQ_GC_UNSAFE_MODE;
1488 ERROR_DECL (error);
1490 mono_runtime_class_init_full (vtable, error);
1491 mono_error_set_pending_exception (error);
1495 void
1496 mono_generic_class_init (MonoVTable *vtable)
1498 ERROR_DECL (error);
1499 mono_runtime_class_init_full (vtable, error);
1500 mono_error_set_pending_exception (error);
1503 void
1504 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1506 HANDLE_FUNCTION_ENTER ();
1507 ERROR_DECL (error);
1508 MONO_HANDLE_DCL (MonoObject, this_obj);
1509 MONO_HANDLE_DCL (MonoObject, target);
1510 mono_delegate_ctor (this_obj, target, addr, error);
1511 mono_error_set_pending_exception (error);
1512 HANDLE_FUNCTION_RETURN ();
1515 void
1516 ves_icall_mono_delegate_ctor_interp (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1518 HANDLE_FUNCTION_ENTER ();
1519 ERROR_DECL (error);
1520 MONO_HANDLE_DCL (MonoObject, this_obj);
1521 MONO_HANDLE_DCL (MonoObject, target);
1523 mini_get_interp_callbacks ()->delegate_ctor (this_obj, target, addr, error);
1524 mono_error_set_pending_exception (error);
1525 HANDLE_FUNCTION_RETURN ();
1528 gpointer
1529 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1531 ERROR_DECL (error);
1532 gpointer res;
1534 res = mono_class_fill_runtime_generic_context (vtable, index, error);
1535 if (!mono_error_ok (error)) {
1536 mono_error_set_pending_exception (error);
1537 return NULL;
1539 return res;
1542 gpointer
1543 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1545 ERROR_DECL (error);
1546 gpointer res;
1548 res = mono_method_fill_runtime_generic_context (mrgctx, index, error);
1549 if (!mono_error_ok (error)) {
1550 mono_error_set_pending_exception (error);
1551 return NULL;
1553 return res;
1556 MonoObject*
1557 mono_get_assembly_object (MonoImage *image)
1559 ICALL_ENTRY();
1560 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, error));
1561 ICALL_RETURN_OBJ (result);
1564 MonoObject*
1565 mono_get_method_object (MonoMethod *method)
1567 ERROR_DECL (error);
1568 MonoObject * result;
1569 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, error);
1570 mono_error_set_pending_exception (error);
1571 return result;
1574 double
1575 mono_ckfinite (double d)
1577 if (mono_isinf (d) || mono_isnan (d))
1578 mono_set_pending_exception (mono_get_exception_arithmetic ());
1579 return d;
1582 void
1583 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1585 char *caller_name = mono_method_get_reflection_name (caller);
1586 char *callee_name = mono_method_get_reflection_name (callee);
1587 ERROR_DECL (error);
1589 mono_error_set_generic_error (error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1590 mono_error_set_pending_exception (error);
1591 g_free (callee_name);
1592 g_free (caller_name);
1595 void
1596 mono_dummy_jit_icall (void)