[interp] Remove varargs from InterpFrame and recompute it instead (#16598)
[mono-project.git] / mono / mini / jit-icalls.c
blobeb22ca795b27f3b8c20e390f8dca56f8ec05c1ff
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 (!is_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 (!is_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 static MonoArray *
728 mono_array_new_n (MonoMethod *cm, int n, uintptr_t lengths [], intptr_t lower_bounds [])
730 ERROR_DECL (error);
731 intptr_t *plower_bounds = NULL;
732 const int pcount = mono_method_signature_internal (cm)->param_count;
733 const int rank = m_class_get_rank (cm->klass);
735 g_assert (rank == pcount);
736 g_assert (rank == n);
738 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY)
739 plower_bounds = lower_bounds;
741 MonoArray *arr = mono_array_new_full_checked (mono_domain_get (),
742 cm->klass, lengths, plower_bounds, error);
744 return mono_error_set_pending_exception (error) ? NULL : arr;
747 /* Specialized version of mono_array_new_va () which avoids varargs */
748 MonoArray *
749 mono_array_new_1 (MonoMethod *cm, guint32 length)
751 uintptr_t lengths [ ] = {length};
752 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
753 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
756 MonoArray *
757 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
759 uintptr_t lengths [ ] = {length1, length2};
760 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
761 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
764 MonoArray *
765 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
767 uintptr_t lengths [ ] = {length1, length2, length3};
768 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
769 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
772 MonoArray *
773 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
775 uintptr_t lengths [ ] = {length1, length2, length3, length4};
776 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
777 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
780 gpointer
781 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
783 ERROR_DECL (error);
784 MonoVTable *vtable;
785 gpointer addr;
787 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
789 mono_class_init_internal (field->parent);
791 vtable = mono_class_vtable_checked (domain, field->parent, error);
792 if (!is_ok (error)) {
793 mono_error_set_pending_exception (error);
794 return NULL;
796 if (!vtable->initialized) {
797 if (!mono_runtime_class_init_full (vtable, error)) {
798 mono_error_set_pending_exception (error);
799 return NULL;
803 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
805 if (field->offset == -1) {
806 /* Special static */
807 g_assert (domain->special_static_fields);
808 mono_domain_lock (domain);
809 addr = g_hash_table_lookup (domain->special_static_fields, field);
810 mono_domain_unlock (domain);
811 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
812 } else {
813 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
815 return addr;
818 gpointer
819 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
821 ERROR_DECL (error);
822 MonoClass *handle_class;
823 gpointer res;
825 res = mono_ldtoken_checked (image, token, &handle_class, context, error);
826 if (!is_ok (error)) {
827 mono_error_set_pending_exception (error);
828 return NULL;
830 mono_class_init_internal (handle_class);
832 return res;
835 gpointer
836 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
838 MonoMethodSignature *sig = mono_method_signature_internal (method);
839 MonoGenericContext *generic_context;
841 if (sig->is_inflated) {
842 generic_context = mono_method_get_context (method);
843 } else {
844 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
845 g_assert (generic_container);
846 generic_context = &generic_container->context;
849 return mono_ldtoken_wrapper (image, token, generic_context);
852 guint64
853 mono_fconv_u8 (double v)
855 #if defined(TARGET_X86) || defined(TARGET_AMD64)
856 const double two63 = 2147483648.0 * 4294967296.0;
857 if (v < two63) {
858 return (gint64)v;
859 } else {
860 return (gint64)(v - two63) + ((guint64)1 << 63);
862 #else
863 if (mono_isinf (v) || mono_isnan (v))
864 return 0;
865 return (guint64)v;
866 #endif
869 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
870 guint64
871 mono_fconv_u8_2 (double v)
873 // Separate from mono_fconv_u8 to avoid duplicate JIT icall.
875 // When there are duplicates, there is single instancing
876 // against function address that breaks stuff. For example,
877 // wrappers are only produced for one of them, breaking FullAOT.
878 return mono_fconv_u8 (v);
881 guint64
882 mono_rconv_u8 (float v)
884 #if defined(TARGET_X86) || defined(TARGET_AMD64)
885 const float two63 = 2147483648.0 * 4294967296.0;
886 if (v < two63) {
887 return (gint64)v;
888 } else {
889 return (gint64)(v - two63) + ((guint64)1 << 63);
891 #else
892 if (mono_isinf (v) || mono_isnan (v))
893 return 0;
894 return (guint64)v;
895 #endif
897 #endif
899 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
900 gint64
901 mono_fconv_i8 (double v)
903 return (gint64)v;
905 #endif
907 guint32
908 mono_fconv_u4 (double v)
910 /* MS.NET behaves like this for some reason */
911 if (mono_isinf (v) || mono_isnan (v))
912 return 0;
913 return (guint32)v;
916 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
917 guint32
918 mono_fconv_u4_2 (double v)
920 // Separate from mono_fconv_u4 to avoid duplicate JIT icall.
922 // When there are duplicates, there is single instancing
923 // against function address that breaks stuff. For example,
924 // wrappers are only produced for one of them, breaking FullAOT.
925 return mono_fconv_u4 (v);
928 guint32
929 mono_rconv_u4 (float v)
931 if (mono_isinf (v) || mono_isnan (v))
932 return 0;
933 return (guint32) v;
935 #endif
937 gint64
938 mono_fconv_ovf_i8 (double v)
940 const gint64 res = (gint64)v;
942 if (mono_isnan (v) || mono_trunc (v) != res) {
943 ERROR_DECL (error);
944 mono_error_set_overflow (error);
945 mono_error_set_pending_exception (error);
946 return 0;
948 return res;
951 guint64
952 mono_fconv_ovf_u8 (double v)
954 guint64 res;
957 * The soft-float implementation of some ARM devices have a buggy guin64 to double
958 * conversion that it looses precision even when the integer if fully representable
959 * as a double.
961 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
963 * To work around this issue we test for value boundaries instead.
965 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
966 if (mono_isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
967 ERROR_DECL (error);
968 mono_error_set_overflow (error);
969 mono_error_set_pending_exception (error);
970 return 0;
972 res = (guint64)v;
973 #else
974 res = (guint64)v;
975 if (mono_isnan (v) || mono_trunc (v) != res) {
976 ERROR_DECL (error);
977 mono_error_set_overflow (error);
978 mono_error_set_pending_exception (error);
979 return 0;
981 #endif
982 return res;
985 guint64
986 mono_fconv_ovf_u8_un (double v)
988 return mono_fconv_ovf_u8 (v);
991 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
992 gint64
993 mono_rconv_i8 (float v)
995 return (gint64)v;
997 #endif
999 gint64
1000 mono_rconv_ovf_i8 (float v)
1002 const gint64 res = (gint64)v;
1004 if (mono_isnan (v) || mono_trunc (v) != res) {
1005 ERROR_DECL (error);
1006 mono_error_set_overflow (error);
1007 mono_error_set_pending_exception (error);
1008 return 0;
1010 return res;
1013 guint64
1014 mono_rconv_ovf_u8 (float v)
1016 guint64 res;
1018 res = (guint64)v;
1019 if (mono_isnan (v) || mono_trunc (v) != res) {
1020 ERROR_DECL (error);
1021 mono_error_set_overflow (error);
1022 mono_error_set_pending_exception (error);
1023 return 0;
1025 return res;
1028 guint64
1029 mono_rconv_ovf_u8_un (float v)
1031 return mono_rconv_ovf_u8 (v);
1034 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1035 double
1036 mono_lconv_to_r8 (gint64 a)
1038 return (double)a;
1040 #endif
1042 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1043 float
1044 mono_lconv_to_r4 (gint64 a)
1046 return (float)a;
1048 #endif
1050 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1051 double
1052 mono_conv_to_r8_un (guint32 a)
1054 return (double)a;
1056 #endif
1058 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1059 double
1060 mono_lconv_to_r8_un (guint64 a)
1062 return (double)a;
1064 #endif
1066 #ifdef MONO_ARCH_EMULATE_FREM
1067 // Wrapper to avoid taking address of overloaded function.
1068 double
1069 mono_fmod (double a, double b)
1071 return fmod (a, b);
1073 #endif
1075 gpointer
1076 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1078 ERROR_DECL (error);
1079 MonoMethod *vmethod;
1080 gpointer addr;
1081 MonoGenericContext *context = mono_method_get_context (method);
1083 UnlockedIncrement (&mono_jit_stats.generic_virtual_invocations);
1085 if (obj == NULL) {
1086 mono_error_set_null_reference (error);
1087 mono_error_set_pending_exception (error);
1088 return NULL;
1090 vmethod = mono_object_get_virtual_method_internal (obj, method);
1091 g_assert (!mono_class_is_gtd (vmethod->klass));
1092 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1093 g_assert (!context->method_inst || !context->method_inst->is_open);
1095 addr = mono_compile_method_checked (vmethod, error);
1096 if (mono_error_set_pending_exception (error))
1097 return NULL;
1098 g_assert (addr);
1100 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1102 /* Since this is a virtual call, have to unbox vtypes */
1103 if (m_class_is_valuetype (obj->vtable->klass))
1104 *this_arg = mono_object_unbox_internal (obj);
1105 else
1106 *this_arg = obj;
1108 return addr;
1111 MonoString*
1112 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1114 ERROR_DECL (error);
1115 MonoString *result = mono_ldstr_checked (domain, image, idx, error);
1116 mono_error_set_pending_exception (error);
1117 return result;
1120 MonoString*
1121 mono_helper_ldstr (MonoImage *image, guint32 idx)
1123 ERROR_DECL (error);
1124 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, error);
1125 mono_error_set_pending_exception (error);
1126 return result;
1129 MonoString*
1130 mono_helper_ldstr_mscorlib (guint32 idx)
1132 ERROR_DECL (error);
1133 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, error);
1134 mono_error_set_pending_exception (error);
1135 return result;
1138 MonoObject*
1139 mono_helper_newobj_mscorlib (guint32 idx)
1141 ERROR_DECL (error);
1142 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, error);
1144 if (!is_ok (error)) {
1145 mono_error_set_pending_exception (error);
1146 return NULL;
1149 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, error);
1150 if (!is_ok (error))
1151 mono_error_set_pending_exception (error);
1152 return obj;
1156 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1157 * in generated code. So instead we emit a call to this function and place a gdb
1158 * breakpoint here.
1160 void
1161 mono_break (void)
1165 MonoException *
1166 mono_create_corlib_exception_0 (guint32 token)
1168 return mono_exception_from_token (mono_defaults.corlib, token);
1171 MonoException *
1172 mono_create_corlib_exception_1 (guint32 token, MonoString *arg_raw)
1174 HANDLE_FUNCTION_ENTER ();
1175 ERROR_DECL (error);
1176 MONO_HANDLE_DCL (MonoString, arg);
1177 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1178 mono_defaults.corlib, token, arg, NULL_HANDLE_STRING, error);
1179 mono_error_set_pending_exception (error);
1180 HANDLE_FUNCTION_RETURN_OBJ (ret);
1183 MonoException *
1184 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1_raw, MonoString *arg2_raw)
1186 HANDLE_FUNCTION_ENTER ();
1187 ERROR_DECL (error);
1188 MONO_HANDLE_DCL (MonoString, arg1);
1189 MONO_HANDLE_DCL (MonoString, arg2);
1190 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1191 mono_defaults.corlib, token, arg1, arg2, error);
1192 mono_error_set_pending_exception (error);
1193 HANDLE_FUNCTION_RETURN_OBJ (ret);
1196 MonoObject*
1197 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1199 ERROR_DECL (error);
1200 MonoJitTlsData *jit_tls = NULL;
1201 MonoClass *oklass;
1203 if (mini_debug_options.better_cast_details) {
1204 jit_tls = mono_tls_get_jit_tls ();
1205 jit_tls->class_cast_from = NULL;
1208 if (!obj)
1209 return NULL;
1211 oklass = obj->vtable->klass;
1212 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)))
1213 return obj;
1214 if (mono_object_isinst_checked (obj, klass, error))
1215 return obj;
1216 if (mono_error_set_pending_exception (error))
1217 return NULL;
1219 if (mini_debug_options.better_cast_details) {
1220 jit_tls->class_cast_from = oklass;
1221 jit_tls->class_cast_to = klass;
1224 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1225 "System", "InvalidCastException"));
1227 return NULL;
1230 MonoObject*
1231 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1233 ERROR_DECL (error);
1234 MonoJitTlsData *jit_tls = NULL;
1235 gpointer cached_vtable, obj_vtable;
1237 if (mini_debug_options.better_cast_details) {
1238 jit_tls = mono_tls_get_jit_tls ();
1239 jit_tls->class_cast_from = NULL;
1242 if (!obj)
1243 return NULL;
1245 cached_vtable = *cache;
1246 obj_vtable = obj->vtable;
1248 if (cached_vtable == obj_vtable)
1249 return obj;
1251 if (mono_object_isinst_checked (obj, klass, error)) {
1252 *cache = obj_vtable;
1253 return obj;
1255 if (mono_error_set_pending_exception (error))
1256 return NULL;
1258 if (mini_debug_options.better_cast_details) {
1259 jit_tls->class_cast_from = obj->vtable->klass;
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_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1272 ERROR_DECL (error);
1273 size_t cached_vtable, obj_vtable;
1275 if (!obj)
1276 return NULL;
1278 cached_vtable = (size_t)*cache;
1279 obj_vtable = (size_t)obj->vtable;
1281 if ((cached_vtable & ~0x1) == obj_vtable) {
1282 return (cached_vtable & 0x1) ? NULL : obj;
1285 if (mono_object_isinst_checked (obj, klass, error)) {
1286 *cache = (gpointer)obj_vtable;
1287 return obj;
1288 } else {
1289 if (mono_error_set_pending_exception (error))
1290 return NULL;
1291 /*negative cache*/
1292 *cache = (gpointer)(obj_vtable | 0x1);
1293 return NULL;
1297 gpointer
1298 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1300 ERROR_DECL (error);
1301 MonoMarshalSpec **mspecs;
1302 MonoMethodPInvoke piinfo;
1303 MonoMethod *m;
1305 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1306 memset (&piinfo, 0, sizeof (piinfo));
1308 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1310 for (int i = sig->param_count; i >= 0; i--)
1311 if (mspecs [i])
1312 mono_metadata_free_marshal_spec (mspecs [i]);
1313 g_free (mspecs);
1315 gpointer compiled_ptr = mono_compile_method_checked (m, error);
1316 mono_error_set_pending_exception (error);
1317 g_assert (compiled_ptr);
1319 return compiled_ptr;
1322 static MonoMethod*
1323 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1325 MonoMethod *m;
1326 int vt_slot, iface_offset;
1327 gboolean is_iface = FALSE;
1329 error_init (error);
1331 if (mono_class_is_interface (klass)) {
1332 MonoObject *this_obj;
1334 is_iface = TRUE;
1336 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1337 this_obj = *(MonoObject**)mp;
1338 g_assert (this_obj);
1340 klass = this_obj->vtable->klass;
1343 if (mono_method_signature_internal (cmethod)->pinvoke) {
1344 /* Object.GetType () */
1345 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1346 } else {
1347 /* Lookup the virtual method */
1348 mono_class_setup_vtable (klass);
1349 g_assert (m_class_get_vtable (klass));
1350 vt_slot = mono_method_get_vtable_slot (cmethod);
1351 if (mono_class_is_interface (cmethod->klass)) {
1352 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1353 g_assert (iface_offset != -1);
1354 vt_slot += iface_offset;
1356 m = m_class_get_vtable (klass) [vt_slot];
1357 if (cmethod->is_inflated) {
1358 m = mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
1359 return_val_if_nok (error, NULL);
1363 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)) {
1365 * Calling a non-vtype method with a vtype receiver, has to box.
1367 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1368 } else if (m_class_is_valuetype (klass)) {
1369 if (is_iface) {
1371 * The original type is an interface, so the receiver is a ref,
1372 the called method is a vtype method, need to unbox.
1374 MonoObject *this_obj = *(MonoObject**)mp;
1376 *this_arg = mono_object_unbox_internal (this_obj);
1377 } else {
1379 * Calling a vtype method with a vtype receiver
1381 *this_arg = mp;
1383 } else {
1385 * Calling a non-vtype method
1387 *this_arg = *(gpointer*)mp;
1390 return m;
1394 * mono_gsharedvt_constrained_call:
1396 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1397 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1399 MonoObject*
1400 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1402 ERROR_DECL (error);
1403 MonoObject *o;
1404 MonoMethod *m;
1405 gpointer this_arg;
1406 gpointer new_args [16];
1408 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, error);
1409 if (!is_ok (error)) {
1410 mono_error_set_pending_exception (error);
1411 return NULL;
1414 if (!m)
1415 return NULL;
1416 if (args && deref_arg) {
1417 new_args [0] = *(gpointer*)args [0];
1418 args = new_args;
1420 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1421 /* Object.GetType () */
1422 args = new_args;
1423 args [0] = this_arg;
1424 this_arg = NULL;
1427 o = mono_runtime_invoke_checked (m, this_arg, args, error);
1428 if (!is_ok (error)) {
1429 mono_error_set_pending_exception (error);
1430 return NULL;
1433 return o;
1436 void
1437 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1439 if (m_class_is_valuetype (klass))
1440 mono_value_copy_internal (dest, src, klass);
1441 else
1442 mono_gc_wbarrier_generic_store_internal (dest, *(MonoObject**)src);
1445 void
1446 ves_icall_runtime_class_init (MonoVTable *vtable)
1448 MONO_REQ_GC_UNSAFE_MODE;
1449 ERROR_DECL (error);
1451 mono_runtime_class_init_full (vtable, error);
1452 mono_error_set_pending_exception (error);
1456 void
1457 mono_generic_class_init (MonoVTable *vtable)
1459 ERROR_DECL (error);
1460 mono_runtime_class_init_full (vtable, error);
1461 mono_error_set_pending_exception (error);
1464 void
1465 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1467 HANDLE_FUNCTION_ENTER ();
1468 ERROR_DECL (error);
1469 MONO_HANDLE_DCL (MonoObject, this_obj);
1470 MONO_HANDLE_DCL (MonoObject, target);
1472 if (!addr) {
1473 mono_error_set_argument_null (error, "method", "");
1474 mono_error_set_pending_exception (error);
1475 goto leave;
1477 mono_delegate_ctor (this_obj, target, addr, error);
1478 mono_error_set_pending_exception (error);
1480 leave:
1481 HANDLE_FUNCTION_RETURN ();
1484 void
1485 ves_icall_mono_delegate_ctor_interp (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1487 HANDLE_FUNCTION_ENTER ();
1488 ERROR_DECL (error);
1489 MONO_HANDLE_DCL (MonoObject, this_obj);
1490 MONO_HANDLE_DCL (MonoObject, target);
1492 if (!addr) {
1493 mono_error_set_argument_null (error, "method", "");
1494 mono_error_set_pending_exception (error);
1495 goto leave;
1497 mini_get_interp_callbacks ()->delegate_ctor (this_obj, target, addr, error);
1498 mono_error_set_pending_exception (error);
1500 leave:
1501 HANDLE_FUNCTION_RETURN ();
1504 gpointer
1505 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1507 ERROR_DECL (error);
1508 gpointer res;
1510 res = mono_class_fill_runtime_generic_context (vtable, index, error);
1511 if (!is_ok (error)) {
1512 mono_error_set_pending_exception (error);
1513 return NULL;
1515 return res;
1518 gpointer
1519 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1521 ERROR_DECL (error);
1522 gpointer res;
1524 res = mono_method_fill_runtime_generic_context (mrgctx, index, error);
1525 if (!is_ok (error)) {
1526 mono_error_set_pending_exception (error);
1527 return NULL;
1529 return res;
1532 MonoObject*
1533 mono_get_assembly_object (MonoImage *image)
1535 ICALL_ENTRY();
1536 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, error));
1537 ICALL_RETURN_OBJ (result);
1540 MonoObject*
1541 mono_get_method_object (MonoMethod *method)
1543 ERROR_DECL (error);
1544 MonoObject * result;
1545 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, error);
1546 mono_error_set_pending_exception (error);
1547 return result;
1550 double
1551 mono_ckfinite (double d)
1553 if (mono_isinf (d) || mono_isnan (d))
1554 mono_set_pending_exception (mono_get_exception_arithmetic ());
1555 return d;
1558 void
1559 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1561 char *caller_name = mono_method_get_reflection_name (caller);
1562 char *callee_name = mono_method_get_reflection_name (callee);
1563 ERROR_DECL (error);
1565 mono_error_set_generic_error (error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1566 mono_error_set_pending_exception (error);
1567 g_free (callee_name);
1568 g_free (caller_name);
1571 void
1572 mono_throw_bad_image ()
1574 ERROR_DECL (error);
1575 mono_error_set_generic_error (error, "System", "BadImageFormatException", "Bad IL format.");
1576 mono_error_set_pending_exception (error);
1579 void
1580 mono_dummy_jit_icall (void)