[runtime] Transition the trampoline code to use memory managers for memory allocation...
[mono-project.git] / mono / mini / jit-icalls.c
blobd4116aafa8a9a3cc58c04926372bc310753e6a8c
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>
30 #include "mono/utils/mono-tls-inline.h"
32 #ifdef ENABLE_LLVM
33 #include "mini-llvm-cpp.h"
34 #endif
36 void*
37 mono_ldftn (MonoMethod *method)
39 gpointer addr;
40 ERROR_DECL (error);
42 if (mono_llvm_only) {
43 // FIXME: No error handling
45 addr = mono_compile_method_checked (method, error);
46 mono_error_assert_ok (error);
47 g_assert (addr);
49 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
50 /* The caller doesn't pass it */
51 g_assert_not_reached ();
53 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
54 return addr;
57 /* if we need the address of a native-to-managed wrapper, just compile it now, trampoline needs thread local
58 * variables that won't be there if we run on a thread that's not attached yet. */
59 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
60 addr = mono_compile_method_checked (method, error);
61 else
62 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE, error);
63 if (!is_ok (error)) {
64 mono_error_set_pending_exception (error);
65 return NULL;
67 return mono_create_ftnptr (mono_domain_get (), addr);
70 static void*
71 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
73 ERROR_DECL (error);
74 MonoMethod *res;
75 gpointer addr;
77 if (obj == NULL) {
78 mono_error_set_null_reference (error);
79 mono_error_set_pending_exception (error);
80 return NULL;
83 res = mono_object_get_virtual_method_internal (obj, method);
85 if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
86 MonoGenericContext context = { NULL, NULL };
88 if (mono_class_is_ginst (res->klass))
89 context.class_inst = mono_class_get_generic_class (res->klass)->context.class_inst;
90 else if (mono_class_is_gtd (res->klass))
91 context.class_inst = mono_class_get_generic_container (res->klass)->context.class_inst;
92 context.method_inst = mono_method_get_context (method)->method_inst;
94 res = mono_class_inflate_generic_method_checked (res, &context, error);
95 if (!is_ok (error)) {
96 mono_error_set_pending_exception (error);
97 return NULL;
101 /* An rgctx wrapper is added by the trampolines no need to do it here */
102 gboolean need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (method->klass);
103 if (need_unbox) {
105 * We can't return a jump trampoline here, because the trampoline code
106 * can't determine whenever to add an unbox trampoline (ldvirtftn) or
107 * not (ldftn). So compile the method here.
109 addr = mono_compile_method_checked (res, error);
110 if (!is_ok (error)) {
111 mono_error_set_pending_exception (error);
112 return NULL;
115 if (mono_llvm_only && mono_method_needs_static_rgctx_invoke (res, FALSE))
116 // FIXME:
117 g_assert_not_reached ();
119 addr = mini_add_method_trampoline (res, addr, mono_method_needs_static_rgctx_invoke (res, FALSE), TRUE);
120 } else {
121 addr = mono_ldftn (res);
123 return addr;
126 void*
127 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
129 return ldvirtfn_internal (obj, method, FALSE);
132 void*
133 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
135 return ldvirtfn_internal (obj, method, TRUE);
138 void
139 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
141 ERROR_DECL (error);
142 if (!array) {
143 mono_error_set_null_reference (error);
144 mono_error_set_pending_exception (error);
145 return;
147 if (val && !mono_object_isinst_checked (val, m_class_get_element_class (mono_object_class (array)), error)) {
148 if (mono_error_set_pending_exception (error))
149 return;
150 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
151 return;
155 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
157 gint64
158 mono_llmult (gint64 a, gint64 b)
160 return a * b;
163 guint64
164 mono_llmult_ovf_un (guint64 a, guint64 b)
166 guint32 al = a;
167 guint32 ah = a >> 32;
168 guint32 bl = b;
169 guint32 bh = b >> 32;
170 guint64 res, t1;
172 // fixme: this is incredible slow
174 if (ah && bh)
175 goto raise_exception;
177 res = (guint64)al * (guint64)bl;
179 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
181 if (t1 > 0xffffffff)
182 goto raise_exception;
184 res += ((guint64)t1) << 32;
186 return res;
188 raise_exception:
190 ERROR_DECL (error);
191 mono_error_set_overflow (error);
192 mono_error_set_pending_exception (error);
194 return 0;
197 guint64
198 mono_llmult_ovf (gint64 a, gint64 b)
200 guint32 al = a;
201 gint32 ah = a >> 32;
202 guint32 bl = b;
203 gint32 bh = b >> 32;
205 Use Karatsuba algorithm where:
206 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
207 where Ah is the "high half" (most significant 32 bits) of a and
208 where Al is the "low half" (least significant 32 bits) of a and
209 where Bh is the "high half" of b and Bl is the "low half" and
210 where R is the Radix or "size of the half" (in our case 32 bits)
212 Note, for the product of two 64 bit numbers to fit into a 64
213 result, ah and/or bh must be 0. This will save us from doing
214 the AhBh term at all.
216 Also note that we refactor so that we don't overflow 64 bits with
217 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
220 gint64 res, t1;
221 gint32 sign;
223 /* need to work with absoulte values, so find out what the
224 resulting sign will be and convert any negative numbers
225 from two's complement
227 sign = ah ^ bh;
228 if (ah < 0) {
229 if (((guint32)ah == 0x80000000) && (al == 0)) {
230 /* This has no two's complement */
231 if (b == 0)
232 return 0;
233 else if (b == 1)
234 return a;
235 else
236 goto raise_exception;
239 /* flip the bits and add 1 */
240 ah ^= ~0;
241 if (al == 0)
242 ah += 1;
243 else {
244 al ^= ~0;
245 al +=1;
249 if (bh < 0) {
250 if (((guint32)bh == 0x80000000) && (bl == 0)) {
251 /* This has no two's complement */
252 if (a == 0)
253 return 0;
254 else if (a == 1)
255 return b;
256 else
257 goto raise_exception;
260 /* flip the bits and add 1 */
261 bh ^= ~0;
262 if (bl == 0)
263 bh += 1;
264 else {
265 bl ^= ~0;
266 bl +=1;
270 /* we overflow for sure if both upper halves are greater
271 than zero because we would need to shift their
272 product 64 bits to the left and that will not fit
273 in a 64 bit result */
274 if (ah && bh)
275 goto raise_exception;
276 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
277 goto raise_exception;
279 /* do the AlBl term first */
280 t1 = (gint64)al * (gint64)bl;
282 res = t1;
284 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
285 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
286 /* check for overflow */
287 t1 <<= 32;
288 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
289 goto raise_exception;
291 res += t1;
293 if (res < 0)
294 goto raise_exception;
296 if (sign < 0)
297 return -res;
298 else
299 return res;
301 raise_exception:
303 ERROR_DECL (error);
304 mono_error_set_overflow (error);
305 mono_error_set_pending_exception (error);
307 return 0;
310 gint64
311 mono_lldiv (gint64 a, gint64 b)
313 #ifdef MONO_ARCH_NEED_DIV_CHECK
314 if (!b) {
315 ERROR_DECL (error);
316 mono_error_set_divide_by_zero (error);
317 mono_error_set_pending_exception (error);
318 return 0;
320 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
321 ERROR_DECL (error);
322 mono_error_set_overflow (error);
323 mono_error_set_pending_exception (error);
324 return 0;
326 #endif
327 return a / b;
330 gint64
331 mono_llrem (gint64 a, gint64 b)
333 #ifdef MONO_ARCH_NEED_DIV_CHECK
334 if (!b) {
335 ERROR_DECL (error);
336 mono_error_set_divide_by_zero (error);
337 mono_error_set_pending_exception (error);
338 return 0;
340 else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
341 ERROR_DECL (error);
342 mono_error_set_overflow (error);
343 mono_error_set_pending_exception (error);
344 return 0;
346 #endif
347 return a % b;
350 guint64
351 mono_lldiv_un (guint64 a, guint64 b)
353 #ifdef MONO_ARCH_NEED_DIV_CHECK
354 if (!b) {
355 ERROR_DECL (error);
356 mono_error_set_divide_by_zero (error);
357 mono_error_set_pending_exception (error);
358 return 0;
360 #endif
361 return a / b;
364 guint64
365 mono_llrem_un (guint64 a, guint64 b)
367 #ifdef MONO_ARCH_NEED_DIV_CHECK
368 if (!b) {
369 ERROR_DECL (error);
370 mono_error_set_divide_by_zero (error);
371 mono_error_set_pending_exception (error);
372 return 0;
374 #endif
375 return a % b;
378 #endif
380 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
382 guint64
383 mono_lshl (guint64 a, gint32 shamt)
385 const guint64 res = a << (shamt & 0x7f);
387 /*printf ("TESTL %" PRId64 " << %d = %" PRId64 "\n", a, shamt, (guint64)res);*/
389 return res;
392 guint64
393 mono_lshr_un (guint64 a, gint32 shamt)
395 const guint64 res = a >> (shamt & 0x7f);
397 /*printf ("TESTR %" PRId64 " >> %d = %" PRId64 "\n", a, shamt, (guint64)res);*/
399 return res;
402 gint64
403 mono_lshr (gint64 a, gint32 shamt)
405 const gint64 res = a >> (shamt & 0x7f);
407 /*printf ("TESTR %" PRId64 " >> %d = %" PRId64 "\n", a, shamt, (guint64)res);*/
409 return res;
412 #endif
414 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
416 gint32
417 mono_idiv (gint32 a, gint32 b)
419 #ifdef MONO_ARCH_NEED_DIV_CHECK
420 if (!b) {
421 ERROR_DECL (error);
422 mono_error_set_divide_by_zero (error);
423 mono_error_set_pending_exception (error);
424 return 0;
426 else if (b == -1 && a == (0x80000000)) {
427 ERROR_DECL (error);
428 mono_error_set_overflow (error);
429 mono_error_set_pending_exception (error);
430 return 0;
432 #endif
433 return a / b;
436 guint32
437 mono_idiv_un (guint32 a, guint32 b)
439 #ifdef MONO_ARCH_NEED_DIV_CHECK
440 if (!b) {
441 ERROR_DECL (error);
442 mono_error_set_divide_by_zero (error);
443 mono_error_set_pending_exception (error);
444 return 0;
446 #endif
447 return a / b;
450 gint32
451 mono_irem (gint32 a, gint32 b)
453 #ifdef MONO_ARCH_NEED_DIV_CHECK
454 if (!b) {
455 ERROR_DECL (error);
456 mono_error_set_divide_by_zero (error);
457 mono_error_set_pending_exception (error);
458 return 0;
460 else if (b == -1 && a == (0x80000000)) {
461 ERROR_DECL (error);
462 mono_error_set_overflow (error);
463 mono_error_set_pending_exception (error);
464 return 0;
466 #endif
467 return a % b;
470 guint32
471 mono_irem_un (guint32 a, guint32 b)
473 #ifdef MONO_ARCH_NEED_DIV_CHECK
474 if (!b) {
475 ERROR_DECL (error);
476 mono_error_set_divide_by_zero (error);
477 mono_error_set_pending_exception (error);
478 return 0;
480 #endif
481 return a % b;
484 #endif
486 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
488 gint32
489 mono_imul (gint32 a, gint32 b)
491 return a * b;
494 gint32
495 mono_imul_ovf (gint32 a, gint32 b)
497 const gint64 res = (gint64)a * (gint64)b;
499 if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
500 ERROR_DECL (error);
501 mono_error_set_overflow (error);
502 mono_error_set_pending_exception (error);
503 return 0;
506 return res;
509 gint32
510 mono_imul_ovf_un (guint32 a, guint32 b)
512 const guint64 res = (guint64)a * (guint64)b;
514 if (res >> 32) {
515 ERROR_DECL (error);
516 mono_error_set_overflow (error);
517 mono_error_set_pending_exception (error);
518 return 0;
521 return res;
523 #endif
525 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
526 double
527 mono_fdiv (double a, double b)
529 return a / b;
531 #endif
533 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
535 double
536 mono_fsub (double a, double b)
538 return a - b;
541 double
542 mono_fadd (double a, double b)
544 return a + b;
547 double
548 mono_fmul (double a, double b)
550 return a * b;
553 double
554 mono_fneg (double a)
556 return -a;
559 double
560 mono_fconv_r4 (double a)
562 return (float)a;
565 double
566 mono_conv_to_r8 (int a)
568 return (double)a;
571 double
572 mono_conv_to_r4 (int a)
574 return (double)(float)a;
577 gint8
578 mono_fconv_i1 (double a)
580 return (gint8)a;
583 gint16
584 mono_fconv_i2 (double a)
586 return (gint16)a;
589 gint32
590 mono_fconv_i4 (double a)
592 return (gint32)a;
595 guint8
596 mono_fconv_u1 (double a)
598 return (guint8)a;
601 guint16
602 mono_fconv_u2 (double a)
604 return (guint16)a;
607 gboolean
608 mono_fcmp_eq (double a, double b)
610 return a == b;
613 gboolean
614 mono_fcmp_ge (double a, double b)
616 return a >= b;
619 gboolean
620 mono_fcmp_gt (double a, double b)
622 return a > b;
625 gboolean
626 mono_fcmp_le (double a, double b)
628 return a <= b;
631 gboolean
632 mono_fcmp_lt (double a, double b)
634 return a < b;
637 gboolean
638 mono_fcmp_ne_un (double a, double b)
640 return isunordered (a, b) || a != b;
643 gboolean
644 mono_fcmp_ge_un (double a, double b)
646 return isunordered (a, b) || a >= b;
649 gboolean
650 mono_fcmp_gt_un (double a, double b)
652 return isunordered (a, b) || a > b;
655 gboolean
656 mono_fcmp_le_un (double a, double b)
658 return isunordered (a, b) || a <= b;
661 gboolean
662 mono_fcmp_lt_un (double a, double b)
664 return isunordered (a, b) || a < b;
667 gboolean
668 mono_fceq (double a, double b)
670 return a == b;
673 gboolean
674 mono_fcgt (double a, double b)
676 return a > b;
679 gboolean
680 mono_fcgt_un (double a, double b)
682 return isunordered (a, b) || a > b;
685 gboolean
686 mono_fclt (double a, double b)
688 return a < b;
691 gboolean
692 mono_fclt_un (double a, double b)
694 return isunordered (a, b) || a < b;
697 double
698 mono_fload_r4 (float *ptr)
700 return *ptr;
703 void
704 mono_fstore_r4 (double val, float *ptr)
706 *ptr = (float)val;
709 /* returns the integer bitpattern that is passed in the regs or stack */
710 guint32
711 mono_fload_r4_arg (double val)
713 float v = (float)val;
714 return *(guint32*)&v;
717 #endif
719 MonoArray *
720 mono_array_new_n_icall (MonoMethod *cm, gint32 pcount, intptr_t *params)
722 ERROR_DECL (error);
723 g_assert (cm);
724 g_assert (pcount);
725 g_assert (params);
726 intptr_t *lower_bounds = NULL;
728 const int pcount_sig = mono_method_signature_internal (cm)->param_count;
729 const int rank = m_class_get_rank (cm->klass);
730 g_assert (pcount == pcount_sig);
731 g_assert (rank == pcount || rank * 2 == pcount);
733 uintptr_t *lengths = (uintptr_t*)params;
735 if (rank == pcount) {
736 /* Only lengths provided. */
737 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY) {
738 lower_bounds = g_newa (intptr_t, rank);
739 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
741 } else {
742 g_assert (pcount == (rank * 2));
743 /* lower bounds are first. */
744 lower_bounds = params;
745 lengths += rank;
748 MonoArray *arr = mono_array_new_full_checked (mono_domain_get (),
749 cm->klass, lengths, lower_bounds, error);
751 return mono_error_set_pending_exception (error) ? NULL : arr;
754 static MonoArray *
755 mono_array_new_n (MonoMethod *cm, int n, uintptr_t lengths [], intptr_t lower_bounds [])
757 ERROR_DECL (error);
758 intptr_t *plower_bounds = NULL;
759 const int pcount = mono_method_signature_internal (cm)->param_count;
760 const int rank = m_class_get_rank (cm->klass);
762 g_assert (rank == pcount);
763 g_assert (rank == n);
765 if (m_class_get_byval_arg (cm->klass)->type == MONO_TYPE_ARRAY)
766 plower_bounds = lower_bounds;
768 MonoArray *arr = mono_array_new_full_checked (mono_domain_get (),
769 cm->klass, lengths, plower_bounds, error);
771 return mono_error_set_pending_exception (error) ? NULL : arr;
774 /* Specialized version of mono_array_new_va () which avoids varargs */
775 MonoArray *
776 mono_array_new_1 (MonoMethod *cm, guint32 length)
778 uintptr_t lengths [ ] = {length};
779 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
780 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
783 MonoArray *
784 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
786 uintptr_t lengths [ ] = {length1, length2};
787 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
788 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
791 MonoArray *
792 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
794 uintptr_t lengths [ ] = {length1, length2, length3};
795 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
796 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
799 MonoArray *
800 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
802 uintptr_t lengths [ ] = {length1, length2, length3, length4};
803 intptr_t lower_bounds [G_N_ELEMENTS (lengths)] = {0};
804 return mono_array_new_n (cm, G_N_ELEMENTS (lengths), lengths, lower_bounds);
807 gpointer
808 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
810 ERROR_DECL (error);
811 MonoVTable *vtable;
812 gpointer addr;
814 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
816 mono_class_init_internal (field->parent);
818 vtable = mono_class_vtable_checked (domain, field->parent, error);
819 if (!is_ok (error)) {
820 mono_error_set_pending_exception (error);
821 return NULL;
823 if (!vtable->initialized) {
824 if (!mono_runtime_class_init_full (vtable, error)) {
825 mono_error_set_pending_exception (error);
826 return NULL;
830 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
832 if (field->offset == -1) {
833 /* Special static */
834 g_assert (domain->special_static_fields);
835 mono_domain_lock (domain);
836 addr = g_hash_table_lookup (domain->special_static_fields, field);
837 mono_domain_unlock (domain);
838 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
839 } else {
840 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
842 return addr;
845 gpointer
846 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
848 ERROR_DECL (error);
849 MonoClass *handle_class;
850 gpointer res;
852 res = mono_ldtoken_checked (image, token, &handle_class, context, error);
853 if (!is_ok (error)) {
854 mono_error_set_pending_exception (error);
855 return NULL;
857 mono_class_init_internal (handle_class);
859 return res;
862 gpointer
863 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
865 MonoMethodSignature *sig = mono_method_signature_internal (method);
866 MonoGenericContext *generic_context;
868 if (sig->is_inflated) {
869 generic_context = mono_method_get_context (method);
870 } else {
871 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
872 g_assert (generic_container);
873 generic_context = &generic_container->context;
876 return mono_ldtoken_wrapper (image, token, generic_context);
879 guint64
880 mono_fconv_u8 (double v)
882 #if defined(TARGET_X86) || defined(TARGET_AMD64)
883 const double two63 = 2147483648.0 * 4294967296.0;
884 if (v < two63) {
885 return (gint64)v;
886 } else {
887 return (gint64)(v - two63) + ((guint64)1 << 63);
889 #else
890 if (mono_isinf (v) || mono_isnan (v))
891 return 0;
892 return (guint64)v;
893 #endif
896 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
897 guint64
898 mono_fconv_u8_2 (double v)
900 // Separate from mono_fconv_u8 to avoid duplicate JIT icall.
902 // When there are duplicates, there is single instancing
903 // against function address that breaks stuff. For example,
904 // wrappers are only produced for one of them, breaking FullAOT.
905 return mono_fconv_u8 (v);
908 guint64
909 mono_rconv_u8 (float v)
911 #if defined(TARGET_X86) || defined(TARGET_AMD64)
912 const float two63 = 2147483648.0 * 4294967296.0;
913 if (v < two63) {
914 return (gint64)v;
915 } else {
916 return (gint64)(v - two63) + ((guint64)1 << 63);
918 #else
919 if (mono_isinf (v) || mono_isnan (v))
920 return 0;
921 return (guint64)v;
922 #endif
924 #endif
926 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
927 gint64
928 mono_fconv_i8 (double v)
930 return (gint64)v;
932 #endif
934 guint32
935 mono_fconv_u4 (double v)
937 /* MS.NET behaves like this for some reason */
938 if (mono_isinf (v) || mono_isnan (v))
939 return 0;
940 return (guint32)v;
943 #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
944 guint32
945 mono_fconv_u4_2 (double v)
947 // Separate from mono_fconv_u4 to avoid duplicate JIT icall.
949 // When there are duplicates, there is single instancing
950 // against function address that breaks stuff. For example,
951 // wrappers are only produced for one of them, breaking FullAOT.
952 return mono_fconv_u4 (v);
955 guint32
956 mono_rconv_u4 (float v)
958 if (mono_isinf (v) || mono_isnan (v))
959 return 0;
960 return (guint32) v;
962 #endif
964 gint64
965 mono_fconv_ovf_i8 (double v)
967 const gint64 res = (gint64)v;
969 if (mono_isnan (v) || mono_trunc (v) != res) {
970 ERROR_DECL (error);
971 mono_error_set_overflow (error);
972 mono_error_set_pending_exception (error);
973 return 0;
975 return res;
978 guint64
979 mono_fconv_ovf_u8 (double v)
981 guint64 res;
984 * The soft-float implementation of some ARM devices have a buggy guin64 to double
985 * conversion that it looses precision even when the integer if fully representable
986 * as a double.
988 * This was found with 4294967295ull, converting to double and back looses one bit of precision.
990 * To work around this issue we test for value boundaries instead.
992 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
993 if (mono_isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
994 ERROR_DECL (error);
995 mono_error_set_overflow (error);
996 mono_error_set_pending_exception (error);
997 return 0;
999 res = (guint64)v;
1000 #else
1001 res = (guint64)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 #endif
1009 return res;
1012 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
1013 gint64
1014 mono_rconv_i8 (float v)
1016 return (gint64)v;
1018 #endif
1020 gint64
1021 mono_rconv_ovf_i8 (float v)
1023 const gint64 res = (gint64)v;
1025 if (mono_isnan (v) || mono_trunc (v) != res) {
1026 ERROR_DECL (error);
1027 mono_error_set_overflow (error);
1028 mono_error_set_pending_exception (error);
1029 return 0;
1031 return res;
1034 guint64
1035 mono_rconv_ovf_u8 (float v)
1037 guint64 res;
1039 res = (guint64)v;
1040 if (mono_isnan (v) || mono_trunc (v) != res) {
1041 ERROR_DECL (error);
1042 mono_error_set_overflow (error);
1043 mono_error_set_pending_exception (error);
1044 return 0;
1046 return res;
1049 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
1050 double
1051 mono_lconv_to_r8 (gint64 a)
1053 return (double)a;
1055 #endif
1057 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
1058 float
1059 mono_lconv_to_r4 (gint64 a)
1061 return (float)a;
1063 #endif
1065 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1066 double
1067 mono_conv_to_r8_un (guint32 a)
1069 return (double)a;
1071 #endif
1073 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1074 double
1075 mono_lconv_to_r8_un (guint64 a)
1077 return (double)a;
1079 #endif
1081 #ifdef MONO_ARCH_EMULATE_FREM
1082 // Wrapper to avoid taking address of overloaded function.
1083 double
1084 mono_fmod (double a, double b)
1086 return fmod (a, b);
1088 #endif
1090 gpointer
1091 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1093 ERROR_DECL (error);
1094 MonoMethod *vmethod;
1095 gpointer addr;
1096 MonoGenericContext *context = mono_method_get_context (method);
1098 UnlockedIncrement (&mono_jit_stats.generic_virtual_invocations);
1100 if (obj == NULL) {
1101 mono_error_set_null_reference (error);
1102 mono_error_set_pending_exception (error);
1103 return NULL;
1105 vmethod = mono_object_get_virtual_method_internal (obj, method);
1106 g_assert (!mono_class_is_gtd (vmethod->klass));
1107 g_assert (!mono_class_is_ginst (vmethod->klass) || !mono_class_get_generic_class (vmethod->klass)->context.class_inst->is_open);
1108 g_assert (!context->method_inst || !context->method_inst->is_open);
1110 addr = mono_compile_method_checked (vmethod, error);
1111 if (mono_error_set_pending_exception (error))
1112 return NULL;
1113 g_assert (addr);
1115 addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1117 /* Since this is a virtual call, have to unbox vtypes */
1118 if (m_class_is_valuetype (obj->vtable->klass))
1119 *this_arg = mono_object_unbox_internal (obj);
1120 else
1121 *this_arg = obj;
1123 return addr;
1126 MonoString*
1127 ves_icall_mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1129 ERROR_DECL (error);
1130 MonoString *result = mono_ldstr_checked (domain, image, idx, error);
1131 mono_error_set_pending_exception (error);
1132 return result;
1135 MonoString*
1136 mono_helper_ldstr (MonoImage *image, guint32 idx)
1138 ERROR_DECL (error);
1139 MonoString *result = mono_ldstr_checked (mono_domain_get (), image, idx, error);
1140 mono_error_set_pending_exception (error);
1141 return result;
1144 MonoString*
1145 mono_helper_ldstr_mscorlib (guint32 idx)
1147 ERROR_DECL (error);
1148 MonoString *result = mono_ldstr_checked (mono_domain_get (), mono_defaults.corlib, idx, error);
1149 mono_error_set_pending_exception (error);
1150 return result;
1153 MonoObject*
1154 mono_helper_newobj_mscorlib (guint32 idx)
1156 ERROR_DECL (error);
1157 MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, error);
1159 if (!is_ok (error)) {
1160 mono_error_set_pending_exception (error);
1161 return NULL;
1164 MonoObject *obj = mono_object_new_checked (mono_domain_get (), klass, error);
1165 if (!is_ok (error))
1166 mono_error_set_pending_exception (error);
1167 return obj;
1171 * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1172 * in generated code. So instead we emit a call to this function and place a gdb
1173 * breakpoint here.
1175 void
1176 mono_break (void)
1180 MonoException *
1181 mono_create_corlib_exception_0 (guint32 token)
1183 return mono_exception_from_token (mono_defaults.corlib, token);
1186 MonoException *
1187 mono_create_corlib_exception_1 (guint32 token, MonoString *arg_raw)
1189 HANDLE_FUNCTION_ENTER ();
1190 ERROR_DECL (error);
1191 MONO_HANDLE_DCL (MonoString, arg);
1192 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1193 mono_defaults.corlib, token, arg, NULL_HANDLE_STRING, error);
1194 mono_error_set_pending_exception (error);
1195 HANDLE_FUNCTION_RETURN_OBJ (ret);
1198 MonoException *
1199 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1_raw, MonoString *arg2_raw)
1201 HANDLE_FUNCTION_ENTER ();
1202 ERROR_DECL (error);
1203 MONO_HANDLE_DCL (MonoString, arg1);
1204 MONO_HANDLE_DCL (MonoString, arg2);
1205 MonoExceptionHandle ret = mono_exception_from_token_two_strings_checked (
1206 mono_defaults.corlib, token, arg1, arg2, error);
1207 mono_error_set_pending_exception (error);
1208 HANDLE_FUNCTION_RETURN_OBJ (ret);
1211 MonoObject*
1212 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1214 ERROR_DECL (error);
1215 MonoJitTlsData *jit_tls = NULL;
1216 MonoClass *oklass;
1218 if (mini_debug_options.better_cast_details) {
1219 jit_tls = mono_tls_get_jit_tls ();
1220 jit_tls->class_cast_from = NULL;
1223 if (!obj)
1224 return NULL;
1226 oklass = obj->vtable->klass;
1227 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)))
1228 return obj;
1229 if (mono_object_isinst_checked (obj, klass, error))
1230 return obj;
1231 if (mono_error_set_pending_exception (error))
1232 return NULL;
1234 if (mini_debug_options.better_cast_details) {
1235 jit_tls->class_cast_from = oklass;
1236 jit_tls->class_cast_to = klass;
1239 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1240 "System", "InvalidCastException"));
1242 return NULL;
1245 MonoObject*
1246 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1248 ERROR_DECL (error);
1249 MonoJitTlsData *jit_tls = NULL;
1250 gpointer cached_vtable, obj_vtable;
1252 if (mini_debug_options.better_cast_details) {
1253 jit_tls = mono_tls_get_jit_tls ();
1254 jit_tls->class_cast_from = NULL;
1257 if (!obj)
1258 return NULL;
1260 cached_vtable = *cache;
1261 obj_vtable = obj->vtable;
1263 if (cached_vtable == obj_vtable)
1264 return obj;
1266 if (mono_object_isinst_checked (obj, klass, error)) {
1267 *cache = obj_vtable;
1268 return obj;
1270 if (mono_error_set_pending_exception (error))
1271 return NULL;
1273 if (mini_debug_options.better_cast_details) {
1274 jit_tls->class_cast_from = obj->vtable->klass;
1275 jit_tls->class_cast_to = klass;
1278 mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1279 "System", "InvalidCastException"));
1281 return NULL;
1284 MonoObject*
1285 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1287 ERROR_DECL (error);
1288 size_t cached_vtable, obj_vtable;
1290 if (!obj)
1291 return NULL;
1293 cached_vtable = (size_t)*cache;
1294 obj_vtable = (size_t)obj->vtable;
1296 if ((cached_vtable & ~0x1) == obj_vtable) {
1297 return (cached_vtable & 0x1) ? NULL : obj;
1300 if (mono_object_isinst_checked (obj, klass, error)) {
1301 *cache = (gpointer)obj_vtable;
1302 return obj;
1303 } else {
1304 if (mono_error_set_pending_exception (error))
1305 return NULL;
1306 /*negative cache*/
1307 *cache = (gpointer)(obj_vtable | 0x1);
1308 return NULL;
1312 gpointer
1313 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1315 ERROR_DECL (error);
1316 MonoMarshalSpec **mspecs;
1317 MonoMethodPInvoke piinfo;
1318 MonoMethod *m;
1320 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1321 memset (&piinfo, 0, sizeof (piinfo));
1323 m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1325 for (int i = sig->param_count; i >= 0; i--)
1326 if (mspecs [i])
1327 mono_metadata_free_marshal_spec (mspecs [i]);
1328 g_free (mspecs);
1330 gpointer compiled_ptr = mono_compile_method_checked (m, error);
1331 mono_error_set_pending_exception (error);
1332 g_assert (compiled_ptr);
1334 return compiled_ptr;
1337 static MonoMethod*
1338 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg, MonoError *error)
1340 MonoMethod *m;
1341 int vt_slot, iface_offset;
1342 gboolean is_iface = FALSE;
1344 error_init (error);
1346 if (mono_class_is_interface (klass) || !m_class_is_valuetype (klass)) {
1347 MonoObject *this_obj;
1349 is_iface = mono_class_is_interface (klass);
1351 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1352 this_obj = *(MonoObject**)mp;
1353 g_assert (this_obj);
1355 klass = this_obj->vtable->klass;
1358 if (mono_method_signature_internal (cmethod)->pinvoke) {
1359 /* Object.GetType () */
1360 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1361 } else {
1362 /* Lookup the virtual method */
1363 mono_class_setup_vtable (klass);
1364 g_assert (m_class_get_vtable (klass));
1365 vt_slot = mono_method_get_vtable_slot (cmethod);
1366 if (mono_class_is_interface (cmethod->klass)) {
1367 iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1368 g_assert (iface_offset != -1);
1369 vt_slot += iface_offset;
1371 m = m_class_get_vtable (klass) [vt_slot];
1372 if (cmethod->is_inflated) {
1373 m = mono_class_inflate_generic_method_full_checked (m, NULL, mono_method_get_context (cmethod), error);
1374 return_val_if_nok (error, NULL);
1378 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)) {
1380 * Calling a non-vtype method with a vtype receiver, has to box.
1382 *this_arg = mono_value_box_checked (mono_domain_get (), klass, mp, error);
1383 } else if (m_class_is_valuetype (klass)) {
1384 if (is_iface) {
1386 * The original type is an interface, so the receiver is a ref,
1387 the called method is a vtype method, need to unbox.
1389 MonoObject *this_obj = *(MonoObject**)mp;
1391 *this_arg = mono_object_unbox_internal (this_obj);
1392 } else {
1394 * Calling a vtype method with a vtype receiver
1396 *this_arg = mp;
1398 } else {
1400 * Calling a non-vtype method
1402 *this_arg = *(gpointer*)mp;
1405 return m;
1409 * mono_gsharedvt_constrained_call:
1411 * Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1412 * the arguments to the method in the format used by mono_runtime_invoke_checked ().
1414 MonoObject*
1415 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1417 ERROR_DECL (error);
1418 MonoObject *o;
1419 MonoMethod *m;
1420 gpointer this_arg;
1421 gpointer new_args [16];
1423 m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, error);
1424 if (!is_ok (error)) {
1425 mono_error_set_pending_exception (error);
1426 return NULL;
1429 if (!m)
1430 return NULL;
1431 if (args && deref_arg) {
1432 new_args [0] = *(gpointer*)args [0];
1433 args = new_args;
1435 if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1436 /* Object.GetType () */
1437 args = new_args;
1438 args [0] = this_arg;
1439 this_arg = NULL;
1442 o = mono_runtime_invoke_checked (m, this_arg, args, error);
1443 if (!is_ok (error)) {
1444 mono_error_set_pending_exception (error);
1445 return NULL;
1448 return o;
1451 void
1452 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1454 if (m_class_is_valuetype (klass))
1455 mono_value_copy_internal (dest, src, klass);
1456 else
1457 mono_gc_wbarrier_generic_store_internal (dest, *(MonoObject**)src);
1460 void
1461 ves_icall_runtime_class_init (MonoVTable *vtable)
1463 MONO_REQ_GC_UNSAFE_MODE;
1464 ERROR_DECL (error);
1466 mono_runtime_class_init_full (vtable, error);
1467 mono_error_set_pending_exception (error);
1471 void
1472 mono_generic_class_init (MonoVTable *vtable)
1474 ERROR_DECL (error);
1475 mono_runtime_class_init_full (vtable, error);
1476 mono_error_set_pending_exception (error);
1479 void
1480 ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1482 HANDLE_FUNCTION_ENTER ();
1483 ERROR_DECL (error);
1484 MONO_HANDLE_DCL (MonoObject, this_obj);
1485 MONO_HANDLE_DCL (MonoObject, target);
1487 if (!addr) {
1488 mono_error_set_argument_null (error, "method", "");
1489 mono_error_set_pending_exception (error);
1490 goto leave;
1492 mono_delegate_ctor (this_obj, target, addr, NULL, error);
1493 mono_error_set_pending_exception (error);
1495 leave:
1496 HANDLE_FUNCTION_RETURN ();
1499 void
1500 ves_icall_mono_delegate_ctor_interp (MonoObject *this_obj_raw, MonoObject *target_raw, gpointer addr)
1502 HANDLE_FUNCTION_ENTER ();
1503 ERROR_DECL (error);
1504 MONO_HANDLE_DCL (MonoObject, this_obj);
1505 MONO_HANDLE_DCL (MonoObject, target);
1507 if (!addr) {
1508 mono_error_set_argument_null (error, "method", "");
1509 mono_error_set_pending_exception (error);
1510 goto leave;
1512 mini_get_interp_callbacks ()->delegate_ctor (this_obj, target, addr, error);
1513 mono_error_set_pending_exception (error);
1515 leave:
1516 HANDLE_FUNCTION_RETURN ();
1519 gpointer
1520 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1522 ERROR_DECL (error);
1523 gpointer res;
1526 * This is perf critical.
1527 * fill_runtime_generic_context () contains a fallpath.
1529 res = mono_class_fill_runtime_generic_context (vtable, index, error);
1530 if (!is_ok (error)) {
1531 mono_error_set_pending_exception (error);
1532 return NULL;
1534 return res;
1537 gpointer
1538 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1540 ERROR_DECL (error);
1541 gpointer res;
1543 res = mono_method_fill_runtime_generic_context (mrgctx, index, error);
1544 if (!is_ok (error)) {
1545 mono_error_set_pending_exception (error);
1546 return NULL;
1548 return res;
1551 MonoObject*
1552 mono_get_assembly_object (MonoImage *image)
1554 ICALL_ENTRY();
1555 MonoObjectHandle result = MONO_HANDLE_CAST (MonoObject, mono_assembly_get_object_handle (mono_domain_get (), image->assembly, error));
1556 ICALL_RETURN_OBJ (result);
1559 MonoObject*
1560 mono_get_method_object (MonoMethod *method)
1562 ERROR_DECL (error);
1563 MonoObject * result;
1564 result = (MonoObject*)mono_method_get_object_checked (mono_domain_get (), method, method->klass, error);
1565 mono_error_set_pending_exception (error);
1566 return result;
1569 double
1570 mono_ckfinite (double d)
1572 if (mono_isinf (d) || mono_isnan (d))
1573 mono_set_pending_exception (mono_get_exception_arithmetic ());
1574 return d;
1577 void
1578 mono_throw_method_access (MonoMethod *caller, MonoMethod *callee)
1580 char *caller_name = mono_method_get_reflection_name (caller);
1581 char *callee_name = mono_method_get_reflection_name (callee);
1582 ERROR_DECL (error);
1584 mono_error_set_generic_error (error, "System", "MethodAccessException", "Method `%s' is inaccessible from method `%s'", callee_name, caller_name);
1585 mono_error_set_pending_exception (error);
1586 g_free (callee_name);
1587 g_free (caller_name);
1590 void
1591 mono_throw_bad_image ()
1593 ERROR_DECL (error);
1594 mono_error_set_generic_error (error, "System", "BadImageFormatException", "Bad IL format.");
1595 mono_error_set_pending_exception (error);
1598 void
1599 mono_throw_not_supported ()
1601 ERROR_DECL (error);
1602 mono_error_set_generic_error (error, "System", "NotSupportedException", "");
1603 mono_error_set_pending_exception (error);
1606 void
1607 mono_throw_invalid_program (const char *msg)
1609 ERROR_DECL (error);
1610 mono_error_set_invalid_program (error, "Invalid IL due to: %s", msg);
1611 mono_error_set_pending_exception (error);
1614 void
1615 mono_dummy_jit_icall (void)