[boehm] Put *_freelists into thread_local_freelists (as in BDWGC v7)
[mono.git] / mono / mini / jit-icalls.c
1 /*
2  * jit-icalls.c: internal calls used by the JIT
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2011 Novell Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
11  */
12 #include <config.h>
13 #include <math.h>
14 #include <limits.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18
19 #include "jit-icalls.h"
20 #include <mono/utils/mono-error-internals.h>
21
22 #ifdef ENABLE_LLVM
23 #include "mini-llvm-cpp.h"
24 #endif
25
26 void*
27 mono_ldftn (MonoMethod *method)
28 {
29         gpointer addr;
30
31         if (mono_llvm_only) {
32                 // FIXME: No error handling
33
34                 addr = mono_compile_method (method);
35                 g_assert (addr);
36
37                 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
38                         /* The caller doesn't pass it */
39                         g_assert_not_reached ();
40
41                 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
42                 return addr;
43         }
44
45         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
46
47         return mono_create_ftnptr (mono_domain_get (), addr);
48 }
49
50 static void*
51 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
52 {
53         MonoError error;
54         MonoMethod *res;
55
56         if (obj == NULL) {
57                 mono_set_pending_exception (mono_get_exception_null_reference ());
58                 return NULL;
59         }
60
61         res = mono_object_get_virtual_method (obj, method);
62
63         if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
64                 MonoGenericContext context = { NULL, NULL };
65
66                 if (res->klass->generic_class)
67                         context.class_inst = res->klass->generic_class->context.class_inst;
68                 else if (res->klass->generic_container)
69                         context.class_inst = res->klass->generic_container->context.class_inst;
70                 context.method_inst = mono_method_get_context (method)->method_inst;
71
72                 res = mono_class_inflate_generic_method_checked (res, &context, &error);
73                 if (!mono_error_ok (&error)) {
74                         mono_error_set_pending_exception (&error);
75                         return NULL;
76                 }
77         }
78
79         /* An rgctx wrapper is added by the trampolines no need to do it here */
80
81         return mono_ldftn (res);
82 }
83
84 void*
85 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
86 {
87         return ldvirtfn_internal (obj, method, FALSE);
88 }
89
90 void*
91 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) 
92 {
93         return ldvirtfn_internal (obj, method, TRUE);
94 }
95
96 void
97 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
98 {
99         if (!array) {
100                 mono_set_pending_exception (mono_get_exception_null_reference ());
101                 return;
102         }
103         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
104                 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
105                 return;
106         }
107 }
108
109 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
110
111 gint64 
112 mono_llmult (gint64 a, gint64 b)
113 {
114         return a * b;
115 }
116
117 guint64  
118 mono_llmult_ovf_un (guint64 a, guint64 b)
119 {
120         guint32 al = a;
121         guint32 ah = a >> 32;
122         guint32 bl = b;
123         guint32 bh = b >> 32; 
124         guint64 res, t1;
125
126         // fixme: this is incredible slow
127
128         if (ah && bh)
129                 goto raise_exception;
130
131         res = (guint64)al * (guint64)bl;
132
133         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
134
135         if (t1 > 0xffffffff)
136                 goto raise_exception;
137
138         res += ((guint64)t1) << 32; 
139
140         return res;
141
142  raise_exception:
143         mono_set_pending_exception (mono_get_exception_overflow ());
144         return 0;
145 }
146
147 guint64  
148 mono_llmult_ovf (gint64 a, gint64 b) 
149 {
150         guint32 al = a;
151         gint32 ah = a >> 32;
152         guint32 bl = b;
153         gint32 bh = b >> 32; 
154         /*
155         Use Karatsuba algorithm where:
156                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
157                 where Ah is the "high half" (most significant 32 bits) of a and
158                 where Al is the "low half" (least significant 32 bits) of a and
159                 where  Bh is the "high half" of b and Bl is the "low half" and
160                 where R is the Radix or "size of the half" (in our case 32 bits)
161
162         Note, for the product of two 64 bit numbers to fit into a 64
163         result, ah and/or bh must be 0.  This will save us from doing
164         the AhBh term at all.
165
166         Also note that we refactor so that we don't overflow 64 bits with 
167         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
168         */
169
170         gint64 res, t1;
171         gint32 sign;
172
173         /* need to work with absoulte values, so find out what the
174            resulting sign will be and convert any negative numbers
175            from two's complement
176         */
177         sign = ah ^ bh;
178         if (ah < 0) {
179                 if (((guint32)ah == 0x80000000) && (al == 0)) {
180                         /* This has no two's complement */
181                         if (b == 0)
182                                 return 0;
183                         else if (b == 1)
184                                 return a;
185                         else
186                                 goto raise_exception;
187                 }
188
189                 /* flip the bits and add 1 */
190                 ah ^= ~0;
191                 if (al ==  0)
192                         ah += 1;
193                 else {
194                         al ^= ~0;
195                         al +=1;
196                 }
197         }
198
199         if (bh < 0) {
200                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
201                         /* This has no two's complement */
202                         if (a == 0)
203                                 return 0;
204                         else if (a == 1)
205                                 return b;
206                         else
207                                 goto raise_exception;
208                 }
209
210                 /* flip the bits and add 1 */
211                 bh ^= ~0;
212                 if (bl ==  0)
213                         bh += 1;
214                 else {
215                         bl ^= ~0;
216                         bl +=1;
217                 }
218         }
219                 
220         /* we overflow for sure if both upper halves are greater 
221            than zero because we would need to shift their 
222            product 64 bits to the left and that will not fit
223            in a 64 bit result */
224         if (ah && bh)
225                 goto raise_exception;
226         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
227                 goto raise_exception;
228
229         /* do the AlBl term first */
230         t1 = (gint64)al * (gint64)bl;
231
232         res = t1;
233
234         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
235         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
236         /* check for overflow */
237         t1 <<= 32;
238         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
239                 goto raise_exception;
240
241         res += t1;
242
243         if (res < 0)
244                 goto raise_exception;
245
246         if (sign < 0)
247                 return -res;
248         else
249                 return res;
250
251  raise_exception:
252         mono_set_pending_exception (mono_get_exception_overflow ());
253         return 0;
254 }
255
256 gint64 
257 mono_lldiv (gint64 a, gint64 b)
258 {
259 #ifdef MONO_ARCH_NEED_DIV_CHECK
260         if (!b) {
261                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
262                 return 0;
263         }
264         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
265                 mono_set_pending_exception (mono_get_exception_arithmetic ());
266                 return 0;
267         }
268 #endif
269         return a / b;
270 }
271
272 gint64 
273 mono_llrem (gint64 a, gint64 b)
274 {
275 #ifdef MONO_ARCH_NEED_DIV_CHECK
276         if (!b) {
277                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
278                 return 0;
279         }
280         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
281                 mono_set_pending_exception (mono_get_exception_arithmetic ());
282                 return 0;
283         }
284 #endif
285         return a % b;
286 }
287
288 guint64 
289 mono_lldiv_un (guint64 a, guint64 b)
290 {
291 #ifdef MONO_ARCH_NEED_DIV_CHECK
292         if (!b) {
293                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
294                 return 0;
295         }
296 #endif
297         return a / b;
298 }
299
300 guint64 
301 mono_llrem_un (guint64 a, guint64 b)
302 {
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
304         if (!b) {
305                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
306                 return 0;
307         }
308 #endif
309         return a % b;
310 }
311
312 #endif
313
314 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
315
316 guint64 
317 mono_lshl (guint64 a, gint32 shamt)
318 {
319         guint64 res;
320
321         res = a << (shamt & 0x7f);
322
323         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
324
325         return res;
326 }
327
328 guint64 
329 mono_lshr_un (guint64 a, gint32 shamt)
330 {
331         guint64 res;
332
333         res = a >> (shamt & 0x7f);
334
335         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
336
337         return res;
338 }
339
340 gint64 
341 mono_lshr (gint64 a, gint32 shamt)
342 {
343         gint64 res;
344
345         res = a >> (shamt & 0x7f);
346
347         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
348
349         return res;
350 }
351
352 #endif
353
354 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
355
356 gint32
357 mono_idiv (gint32 a, gint32 b)
358 {
359 #ifdef MONO_ARCH_NEED_DIV_CHECK
360         if (!b) {
361                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
362                 return 0;
363         }
364         else if (b == -1 && a == (0x80000000)) {
365                 mono_set_pending_exception (mono_get_exception_overflow ());
366                 return 0;
367         }
368 #endif
369         return a / b;
370 }
371
372 guint32
373 mono_idiv_un (guint32 a, guint32 b)
374 {
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
376         if (!b) {
377                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
378                 return 0;
379         }
380 #endif
381         return a / b;
382 }
383
384 gint32
385 mono_irem (gint32 a, gint32 b)
386 {
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
388         if (!b) {
389                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
390                 return 0;
391         }
392         else if (b == -1 && a == (0x80000000)) {
393                 mono_set_pending_exception (mono_get_exception_overflow ());
394                 return 0;
395         }
396 #endif
397         return a % b;
398 }
399
400 guint32
401 mono_irem_un (guint32 a, guint32 b)
402 {
403 #ifdef MONO_ARCH_NEED_DIV_CHECK
404         if (!b) {
405                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
406                 return 0;
407         }
408 #endif
409         return a % b;
410 }
411
412 #endif
413
414 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
415
416 gint32
417 mono_imul (gint32 a, gint32 b)
418 {
419         return a * b;
420 }
421
422 gint32
423 mono_imul_ovf (gint32 a, gint32 b)
424 {
425         gint64 res;
426
427         res = (gint64)a * (gint64)b;
428
429         if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
430                 mono_set_pending_exception (mono_get_exception_overflow ());
431                 return 0;
432         }
433
434         return res;
435 }
436
437 gint32
438 mono_imul_ovf_un (guint32 a, guint32 b)
439 {
440         guint64 res;
441
442         res = (guint64)a * (guint64)b;
443
444         if (res >> 32) {
445                 mono_set_pending_exception (mono_get_exception_overflow ());
446                 return 0;
447         }
448
449         return res;
450 }
451 #endif
452
453 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
454 double
455 mono_fdiv (double a, double b)
456 {
457         return a / b;
458 }
459 #endif
460
461 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
462
463 double
464 mono_fsub (double a, double b)
465 {
466         return a - b;
467 }
468
469 double
470 mono_fadd (double a, double b)
471 {
472         return a + b;
473 }
474
475 double
476 mono_fmul (double a, double b)
477 {
478         return a * b;
479 }
480
481 double
482 mono_fneg (double a)
483 {
484         return -a;
485 }
486
487 double
488 mono_fconv_r4 (double a)
489 {
490         return (float)a;
491 }
492
493 double
494 mono_conv_to_r8 (int a)
495 {
496         return (double)a;
497 }
498
499 double
500 mono_conv_to_r4 (int a)
501 {
502         return (double)(float)a;
503 }
504
505 gint8
506 mono_fconv_i1 (double a)
507 {
508         return (gint8)a;
509 }
510
511 gint16
512 mono_fconv_i2 (double a)
513 {
514         return (gint16)a;
515 }
516
517 gint32
518 mono_fconv_i4 (double a)
519 {
520         return (gint32)a;
521 }
522
523 guint8
524 mono_fconv_u1 (double a)
525 {
526         return (guint8)a;
527 }
528
529 guint16
530 mono_fconv_u2 (double a)
531 {
532         return (guint16)a;
533 }
534
535 gboolean
536 mono_fcmp_eq (double a, double b)
537 {
538         return a == b;
539 }
540
541 gboolean
542 mono_fcmp_ge (double a, double b)
543 {
544         return a >= b;
545 }
546
547 gboolean
548 mono_fcmp_gt (double a, double b)
549 {
550         return a > b;
551 }
552
553 gboolean
554 mono_fcmp_le (double a, double b)
555 {
556         return a <= b;
557 }
558
559 gboolean
560 mono_fcmp_lt (double a, double b)
561 {
562         return a < b;
563 }
564
565 gboolean
566 mono_fcmp_ne_un (double a, double b)
567 {
568         return isunordered (a, b) || a != b;
569 }
570
571 gboolean
572 mono_fcmp_ge_un (double a, double b)
573 {
574         return isunordered (a, b) || a >= b;
575 }
576
577 gboolean
578 mono_fcmp_gt_un (double a, double b)
579 {
580         return isunordered (a, b) || a > b;
581 }
582
583 gboolean
584 mono_fcmp_le_un (double a, double b)
585 {
586         return isunordered (a, b) || a <= b;
587 }
588
589 gboolean
590 mono_fcmp_lt_un (double a, double b)
591 {
592         return isunordered (a, b) || a < b;
593 }
594
595 gboolean
596 mono_fceq (double a, double b)
597 {
598         return a == b;
599 }
600
601 gboolean
602 mono_fcgt (double a, double b)
603 {
604         return a > b;
605 }
606
607 gboolean
608 mono_fcgt_un (double a, double b)
609 {
610         return isunordered (a, b) || a > b;
611 }
612
613 gboolean
614 mono_fclt (double a, double b)
615 {
616         return a < b;
617 }
618
619 gboolean
620 mono_fclt_un (double a, double b)
621 {
622         return isunordered (a, b) || a < b;
623 }
624
625 gboolean
626 mono_isfinite (double a)
627 {
628 #ifdef HAVE_ISFINITE
629         return isfinite (a);
630 #else
631         g_assert_not_reached ();
632         return TRUE;
633 #endif
634 }
635
636 double
637 mono_fload_r4 (float *ptr)
638 {
639         return *ptr;
640 }
641
642 void
643 mono_fstore_r4 (double val, float *ptr)
644 {
645         *ptr = (float)val;
646 }
647
648 /* returns the integer bitpattern that is passed in the regs or stack */
649 guint32
650 mono_fload_r4_arg (double val)
651 {
652         float v = (float)val;
653         return *(guint32*)&v;
654 }
655
656 #endif
657
658 MonoArray *
659 mono_array_new_va (MonoMethod *cm, ...)
660 {
661         MonoDomain *domain = mono_domain_get ();
662         va_list ap;
663         uintptr_t *lengths;
664         intptr_t *lower_bounds;
665         int pcount;
666         int rank;
667         int i, d;
668
669         pcount = mono_method_signature (cm)->param_count;
670         rank = cm->klass->rank;
671
672         va_start (ap, cm);
673         
674         lengths = alloca (sizeof (uintptr_t) * pcount);
675         for (i = 0; i < pcount; ++i)
676                 lengths [i] = d = va_arg(ap, int);
677
678         if (rank == pcount) {
679                 /* Only lengths provided. */
680                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
681                         lower_bounds = alloca (sizeof (intptr_t) * rank);
682                         memset (lower_bounds, 0, sizeof (intptr_t) * rank);
683                 } else {
684                         lower_bounds = NULL;
685                 }
686         } else {
687                 g_assert (pcount == (rank * 2));
688                 /* lower bounds are first. */
689                 lower_bounds = (intptr_t*)lengths;
690                 lengths += rank;
691         }
692         va_end(ap);
693
694         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
695 }
696
697 /* Specialized version of mono_array_new_va () which avoids varargs */
698 MonoArray *
699 mono_array_new_1 (MonoMethod *cm, guint32 length)
700 {
701         MonoDomain *domain = mono_domain_get ();
702         uintptr_t lengths [1];
703         intptr_t *lower_bounds;
704         int pcount;
705         int rank;
706
707         pcount = mono_method_signature (cm)->param_count;
708         rank = cm->klass->rank;
709
710         lengths [0] = length;
711
712         g_assert (rank == pcount);
713
714         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
715                 lower_bounds = alloca (sizeof (intptr_t) * rank);
716                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
717         } else {
718                 lower_bounds = NULL;
719         }
720
721         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
722 }
723
724 MonoArray *
725 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
726 {
727         MonoDomain *domain = mono_domain_get ();
728         uintptr_t lengths [2];
729         intptr_t *lower_bounds;
730         int pcount;
731         int rank;
732
733         pcount = mono_method_signature (cm)->param_count;
734         rank = cm->klass->rank;
735
736         lengths [0] = length1;
737         lengths [1] = length2;
738
739         g_assert (rank == pcount);
740
741         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
742                 lower_bounds = alloca (sizeof (intptr_t) * rank);
743                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
744         } else {
745                 lower_bounds = NULL;
746         }
747
748         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
749 }
750
751 MonoArray *
752 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
753 {
754         MonoDomain *domain = mono_domain_get ();
755         uintptr_t lengths [3];
756         intptr_t *lower_bounds;
757         int pcount;
758         int rank;
759
760         pcount = mono_method_signature (cm)->param_count;
761         rank = cm->klass->rank;
762
763         lengths [0] = length1;
764         lengths [1] = length2;
765         lengths [2] = length3;
766
767         g_assert (rank == pcount);
768
769         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
770                 lower_bounds = alloca (sizeof (intptr_t) * rank);
771                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
772         } else {
773                 lower_bounds = NULL;
774         }
775
776         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
777 }
778
779 MonoArray *
780 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
781 {
782         MonoDomain *domain = mono_domain_get ();
783         uintptr_t lengths [4];
784         intptr_t *lower_bounds;
785         int pcount;
786         int rank;
787
788         pcount = mono_method_signature (cm)->param_count;
789         rank = cm->klass->rank;
790
791         lengths [0] = length1;
792         lengths [1] = length2;
793         lengths [2] = length3;
794         lengths [3] = length4;
795
796         g_assert (rank == pcount);
797
798         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
799                 lower_bounds = alloca (sizeof (intptr_t) * rank);
800                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
801         } else {
802                 lower_bounds = NULL;
803         }
804
805         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
806 }
807
808 gpointer
809 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
810 {
811         MonoVTable *vtable;
812         gpointer addr;
813         
814         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
815
816         mono_class_init (field->parent);
817
818         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
819         if (!vtable->initialized)
820                 mono_runtime_class_init (vtable);
821
822         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
823
824         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
825                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
826         else
827                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
828         
829         return addr;
830 }
831
832 gpointer
833 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
834 {
835         MonoError error;
836         MonoClass *handle_class;
837         gpointer res;
838
839         res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
840         if (!mono_error_ok (&error)) {
841                 mono_error_set_pending_exception (&error);
842                 return NULL;
843         }
844         mono_class_init (handle_class);
845
846         return res;
847 }
848
849 gpointer
850 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
851 {
852         MonoMethodSignature *sig = mono_method_signature (method);
853         MonoGenericContext *generic_context;
854
855         if (sig->is_inflated) {
856                 generic_context = mono_method_get_context (method);
857         } else {
858                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
859                 g_assert (generic_container);
860                 generic_context = &generic_container->context;
861         }
862
863         return mono_ldtoken_wrapper (image, token, generic_context);
864 }
865
866 guint64
867 mono_fconv_u8 (double v)
868 {
869         return (guint64)v;
870 }
871
872 guint64
873 mono_rconv_u8 (float v)
874 {
875         return (guint64)v;
876 }
877
878 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
879 gint64
880 mono_fconv_i8 (double v)
881 {
882         return (gint64)v;
883 }
884 #endif
885
886 guint32
887 mono_fconv_u4 (double v)
888 {
889         /* MS.NET behaves like this for some reason */
890 #ifdef HAVE_ISINF
891         if (isinf (v) || isnan (v))
892                 return 0;
893 #endif
894
895         return (guint32)v;
896 }
897
898 #ifndef HAVE_TRUNC
899 /* Solaris doesn't have trunc */
900 #ifdef HAVE_AINTL
901 extern long double aintl (long double);
902 #define trunc aintl
903 #else
904 /* FIXME: This means we will never throw overflow exceptions */
905 #define trunc(v) res
906 #endif
907 #endif /* HAVE_TRUNC */
908
909 gint64
910 mono_fconv_ovf_i8 (double v)
911 {
912         gint64 res;
913
914         res = (gint64)v;
915
916         if (isnan(v) || trunc (v) != res) {
917                 mono_set_pending_exception (mono_get_exception_overflow ());
918                 return 0;
919         }
920         return res;
921 }
922
923 guint64
924 mono_fconv_ovf_u8 (double v)
925 {
926         guint64 res;
927
928 /*
929  * The soft-float implementation of some ARM devices have a buggy guin64 to double
930  * conversion that it looses precision even when the integer if fully representable
931  * as a double.
932  * 
933  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
934  * 
935  * To work around this issue we test for value boundaries instead. 
936  */
937 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
938         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
939                 mono_set_pending_exception (mono_get_exception_overflow ());
940                 return 0;
941         }
942         res = (guint64)v;
943 #else
944         res = (guint64)v;
945         if (isnan(v) || trunc (v) != res) {
946                 mono_set_pending_exception (mono_get_exception_overflow ());
947                 return 0;
948         }
949 #endif
950         return res;
951 }
952
953 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
954 gint64
955 mono_rconv_i8 (float v)
956 {
957         return (gint64)v;
958 }
959 #endif
960
961 gint64
962 mono_rconv_ovf_i8 (float v)
963 {
964         gint64 res;
965
966         res = (gint64)v;
967
968         if (isnan(v) || trunc (v) != res) {
969                 mono_set_pending_exception (mono_get_exception_overflow ());
970                 return 0;
971         }
972         return res;
973 }
974
975 guint64
976 mono_rconv_ovf_u8 (float v)
977 {
978         guint64 res;
979
980         res = (guint64)v;
981         if (isnan(v) || trunc (v) != res) {
982                 mono_set_pending_exception (mono_get_exception_overflow ());
983                 return 0;
984         }
985         return res;
986 }
987
988 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
989 double
990 mono_lconv_to_r8 (gint64 a)
991 {
992         return (double)a;
993 }
994 #endif
995
996 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
997 float
998 mono_lconv_to_r4 (gint64 a)
999 {
1000         return (float)a;
1001 }
1002 #endif
1003
1004 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1005 double
1006 mono_conv_to_r8_un (guint32 a)
1007 {
1008         return (double)a;
1009 }
1010 #endif
1011
1012 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1013 double
1014 mono_lconv_to_r8_un (guint64 a)
1015 {
1016         return (double)a;
1017 }
1018 #endif
1019
1020 #if defined(__native_client_codegen__) || defined(__native_client__)
1021 /* When we cross-compile to Native Client we can't directly embed calls */
1022 /* to the math library on the host. This will use the fmod on the target*/
1023 double
1024 mono_fmod(double a, double b)
1025 {
1026         return fmod(a, b);
1027 }
1028 #endif
1029
1030 gpointer
1031 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1032 {
1033         MonoMethod *vmethod;
1034         gpointer addr;
1035         MonoGenericContext *context = mono_method_get_context (method);
1036
1037         mono_jit_stats.generic_virtual_invocations++;
1038
1039         if (obj == NULL) {
1040                 mono_set_pending_exception (mono_get_exception_null_reference ());
1041                 return NULL;
1042         }
1043         vmethod = mono_object_get_virtual_method (obj, method);
1044         g_assert (!vmethod->klass->generic_container);
1045         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1046         g_assert (!context->method_inst || !context->method_inst->is_open);
1047
1048         addr = mono_compile_method (vmethod);
1049
1050         addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1051
1052         /* Since this is a virtual call, have to unbox vtypes */
1053         if (obj->vtable->klass->valuetype)
1054                 *this_arg = mono_object_unbox (obj);
1055         else
1056                 *this_arg = obj;
1057
1058         return addr;
1059 }
1060
1061 MonoString*
1062 mono_helper_ldstr (MonoImage *image, guint32 idx)
1063 {
1064         return mono_ldstr (mono_domain_get (), image, idx);
1065 }
1066
1067 MonoString*
1068 mono_helper_ldstr_mscorlib (guint32 idx)
1069 {
1070         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1071 }
1072
1073 MonoObject*
1074 mono_helper_newobj_mscorlib (guint32 idx)
1075 {
1076         MonoError error;
1077         MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1078
1079         if (!mono_error_ok (&error)) {
1080                 mono_error_set_pending_exception (&error);
1081                 return NULL;
1082         }
1083
1084         return mono_object_new (mono_domain_get (), klass);
1085 }
1086
1087 /*
1088  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1089  * in generated code. So instead we emit a call to this function and place a gdb
1090  * breakpoint here.
1091  */
1092 void
1093 mono_break (void)
1094 {
1095 }
1096
1097 MonoException *
1098 mono_create_corlib_exception_0 (guint32 token)
1099 {
1100         return mono_exception_from_token (mono_defaults.corlib, token);
1101 }
1102
1103 MonoException *
1104 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1105 {
1106         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1107 }
1108
1109 MonoException *
1110 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1111 {
1112         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1113 }
1114
1115 MonoObject*
1116 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1117 {
1118         MonoJitTlsData *jit_tls = NULL;
1119         MonoClass *oklass;
1120
1121         if (mini_get_debug_options ()->better_cast_details) {
1122                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1123                 jit_tls->class_cast_from = NULL;
1124         }
1125
1126         if (!obj)
1127                 return NULL;
1128
1129         oklass = obj->vtable->klass;
1130         if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1131                 return obj;
1132         if (mono_object_isinst (obj, klass))
1133                 return obj;
1134
1135         if (mini_get_debug_options ()->better_cast_details) {
1136                 jit_tls->class_cast_from = oklass;
1137                 jit_tls->class_cast_to = klass;
1138         }
1139
1140         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1141                                         "System", "InvalidCastException"));
1142
1143         return NULL;
1144 }
1145
1146 MonoObject*
1147 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1148 {
1149         MonoJitTlsData *jit_tls = NULL;
1150         gpointer cached_vtable, obj_vtable;
1151
1152         if (mini_get_debug_options ()->better_cast_details) {
1153                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1154                 jit_tls->class_cast_from = NULL;
1155         }
1156
1157         if (!obj)
1158                 return NULL;
1159
1160         cached_vtable = *cache;
1161         obj_vtable = obj->vtable;
1162
1163         if (cached_vtable == obj_vtable)
1164                 return obj;
1165
1166         if (mono_object_isinst (obj, klass)) {
1167                 *cache = obj_vtable;
1168                 return obj;
1169         }
1170
1171         if (mini_get_debug_options ()->better_cast_details) {
1172                 jit_tls->class_cast_from = obj->vtable->klass;
1173                 jit_tls->class_cast_to = klass;
1174         }
1175
1176         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1177                                         "System", "InvalidCastException"));
1178
1179         return NULL;
1180 }
1181
1182 MonoObject*
1183 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1184 {
1185         size_t cached_vtable, obj_vtable;
1186
1187         if (!obj)
1188                 return NULL;
1189
1190         cached_vtable = (size_t)*cache;
1191         obj_vtable = (size_t)obj->vtable;
1192
1193         if ((cached_vtable & ~0x1) == obj_vtable) {
1194                 return (cached_vtable & 0x1) ? NULL : obj;
1195         }
1196
1197         if (mono_object_isinst (obj, klass)) {
1198                 *cache = (gpointer)obj_vtable;
1199                 return obj;
1200         } else {
1201                 /*negative cache*/
1202                 *cache = (gpointer)(obj_vtable | 0x1);
1203                 return NULL;
1204         }
1205 }
1206
1207 gpointer
1208 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1209 {
1210         MonoMarshalSpec **mspecs;
1211         MonoMethodPInvoke piinfo;
1212         MonoMethod *m;
1213
1214         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1215         memset (&piinfo, 0, sizeof (piinfo));
1216
1217         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1218
1219         return mono_compile_method (m);
1220 }
1221
1222 static MonoMethod*
1223 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1224 {
1225         MonoMethod *m;
1226         int vt_slot;
1227
1228         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1229                 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1230                 return NULL;
1231         }
1232
1233         if (mono_method_signature (cmethod)->pinvoke) {
1234                 /* Object.GetType () */
1235                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1236         } else {
1237                 /* Lookup the virtual method */
1238                 mono_class_setup_vtable (klass);
1239                 g_assert (klass->vtable);
1240                 vt_slot = mono_method_get_vtable_slot (cmethod);
1241                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1242                         int iface_offset;
1243
1244                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1245                         g_assert (iface_offset != -1);
1246                         vt_slot += iface_offset;
1247                 }
1248                 m = klass->vtable [vt_slot];
1249                 if (cmethod->is_inflated)
1250                         m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1251         }
1252         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1253                 /*
1254                  * Calling a non-vtype method with a vtype receiver, has to box.
1255                  */
1256                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1257         else if (klass->valuetype)
1258                 /*
1259                  * Calling a vtype method with a vtype receiver
1260                  */
1261                 *this_arg = mp;
1262         else
1263                 /*
1264                  * Calling a non-vtype method
1265                  */
1266                 *this_arg = *(gpointer*)mp;
1267         return m;
1268 }
1269
1270 /*
1271  * mono_gsharedvt_constrained_call:
1272  *
1273  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1274  * the arguments to the method in the format used by mono_runtime_invoke ().
1275  */
1276 MonoObject*
1277 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1278 {
1279         MonoMethod *m;
1280         gpointer this_arg;
1281         gpointer new_args [16];
1282
1283         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1284         if (!m)
1285                 return NULL;
1286         if (args && deref_arg) {
1287                 new_args [0] = *(gpointer*)args [0];
1288                 args = new_args;
1289         }
1290         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1291                 /* Object.GetType () */
1292                 args = new_args;
1293                 args [0] = this_arg;
1294                 this_arg = NULL;
1295         }
1296         return mono_runtime_invoke (m, this_arg, args, NULL);
1297 }
1298
1299 void
1300 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1301 {
1302         if (klass->valuetype)
1303                 mono_value_copy (dest, src, klass);
1304         else
1305         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1306 }
1307
1308 void
1309 mono_generic_class_init (MonoVTable *vtable)
1310 {
1311         mono_runtime_class_init (vtable);
1312 }
1313
1314 gpointer
1315 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1316 {
1317         return mono_class_fill_runtime_generic_context (vtable, index);
1318 }
1319
1320 gpointer
1321 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1322 {
1323         return mono_method_fill_runtime_generic_context (mrgctx, index);
1324 }
1325
1326 /*
1327  * mono_resolve_iface_call:
1328  *
1329  *   Return the executable code for the iface method IMT_METHOD called on THIS.
1330  */
1331 gpointer
1332 mono_resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_rgctx_arg)
1333 {
1334         MonoVTable *vt;
1335         gpointer *imt, *vtable_slot;
1336         MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1337         gpointer addr, compiled_method, aot_addr;
1338         gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1339
1340         // FIXME: Optimize this
1341
1342         if (!this_obj)
1343                 /* The caller will handle it */
1344                 return NULL;
1345
1346         vt = this_obj->vtable;
1347         imt = (gpointer*)vt - MONO_IMT_SIZE;
1348
1349         vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1350
1351         // FIXME: This can throw exceptions
1352         addr = compiled_method = mono_compile_method (impl_method);
1353         g_assert (addr);
1354
1355         if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
1356                 generic_virtual = imt_method;
1357                 need_rgctx_tramp = TRUE;
1358         }
1359
1360         if (generic_virtual || variant_iface) {
1361                 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1362                         need_unbox_tramp = TRUE;
1363         } else {
1364                 if (impl_method->klass->valuetype)
1365                         need_unbox_tramp = TRUE;
1366         }
1367
1368         addr = mini_add_method_trampoline (impl_method, addr, need_rgctx_tramp, need_unbox_tramp);
1369
1370         if (generic_virtual || variant_iface) {
1371                 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1372
1373                 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1374                                                                                                         vt, imt + imt_slot,
1375                                                                                                         target, addr);
1376         }
1377
1378         *vtable_slot = addr;
1379
1380         if (need_rgctx_tramp && out_rgctx_arg) {
1381                 MonoMethod *m = impl_method;
1382                 MonoJitInfo *ji;
1383
1384                 /*
1385                  * The exact compiled method might not be shared so it doesn't have an rgctx arg.
1386                  */
1387                 ji = mini_jit_info_table_find (mono_domain_get (), compiled_method, NULL);
1388                 if (!ji || (ji && ji->has_generic_jit_info)) {
1389                         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED && m->klass->rank && strstr (m->name, "System.Collections.Generic"))
1390                                 m = mono_aot_get_array_helper_from_wrapper (m);
1391                         *out_rgctx_arg = mini_method_get_rgctx (m);
1392                 }
1393         }
1394
1395         return addr;
1396 }
1397
1398 static gboolean
1399 is_generic_method_definition (MonoMethod *m)
1400 {
1401         MonoGenericContext *context;
1402         if (m->is_generic)
1403                 return TRUE;
1404         if (!m->is_inflated)
1405                 return FALSE;
1406
1407         context = mono_method_get_context (m);
1408         if (!context->method_inst)
1409                 return FALSE;
1410         if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1411                 return TRUE;
1412         return FALSE;
1413 }
1414
1415 /*
1416  * mono_resolve_vcall:
1417  *
1418  *   Return the executable code for calling this_obj->vtable [slot].
1419  */
1420 gpointer
1421 mono_resolve_vcall (MonoObject *this_obj, int slot, MonoMethod *imt_method)
1422 {
1423         MonoVTable *vt;
1424         MonoMethod *m, *generic_virtual = NULL;
1425         gpointer *vtable_slot;
1426         gpointer addr;
1427         gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1428
1429         // FIXME: Optimize this
1430
1431         if (!this_obj)
1432                 /* The caller will handle it */
1433                 return NULL;
1434
1435         vt = this_obj->vtable;
1436
1437         vtable_slot = &(vt->vtable [slot]);
1438
1439         /* Same as in common_call_trampoline () */
1440
1441         /* Avoid loading metadata or creating a generic vtable if possible */
1442         addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1443         if (addr && !vt->klass->valuetype) {
1444                 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
1445                         *vtable_slot = addr;
1446
1447                 return mono_create_ftnptr (mono_domain_get (), addr);
1448         }
1449
1450         m = mono_class_get_vtable_entry (vt->klass, slot);
1451
1452         if (is_generic_method_definition (m)) {
1453                 MonoError error;
1454                 MonoGenericContext context = { NULL, NULL };
1455                 MonoMethod *declaring;
1456
1457                 if (m->is_inflated)
1458                         declaring = mono_method_get_declaring_generic_method (m);
1459                 else
1460                         declaring = m;
1461
1462                 if (m->klass->generic_class)
1463                         context.class_inst = m->klass->generic_class->context.class_inst;
1464                 else
1465                         g_assert (!m->klass->generic_container);
1466
1467                 generic_virtual = imt_method;
1468                 g_assert (generic_virtual);
1469                 g_assert (generic_virtual->is_inflated);
1470                 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1471
1472                 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1473                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1474                 /* FIXME: only do this if the method is sharable */
1475                 // FIXME:
1476                 //g_assert_not_reached ();
1477                 //need_rgctx_tramp = TRUE;
1478         }
1479
1480         if (generic_virtual) {
1481                 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1482                         need_unbox_tramp = TRUE;
1483         } else {
1484                 if (m->klass->valuetype)
1485                         need_unbox_tramp = TRUE;
1486         }
1487
1488         // FIXME: This can throw exceptions
1489         addr = mono_compile_method (m);
1490         g_assert (addr);
1491
1492         addr = mini_add_method_trampoline (m, addr, need_rgctx_tramp, need_unbox_tramp);
1493
1494         *vtable_slot = addr;
1495
1496         return addr;
1497 }
1498
1499 /*
1500  * mono_init_delegate:
1501  *
1502  *   Initialize a MonoDelegate object.
1503  * Similar to mono_delegate_ctor ().
1504  */
1505 void
1506 mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1507 {
1508         MONO_OBJECT_SETREF (del, target, target);
1509         del->method = method;
1510         del->method_ptr = mono_compile_method (method);
1511         if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1512                 del->rgctx = mini_method_get_rgctx (method);
1513 }
1514
1515 void
1516 mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1517 {
1518         g_assert (target);
1519
1520         method = mono_object_get_virtual_method (target, method);
1521
1522         MONO_OBJECT_SETREF (del, target, target);
1523         del->method = method;
1524         del->method_ptr = mono_compile_method (method);
1525         if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1526                 del->rgctx = mini_method_get_rgctx (method);
1527 }
1528
1529 MonoObject*
1530 mono_get_assembly_object (MonoImage *image)
1531 {
1532         return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1533 }
1534
1535 double
1536 mono_ckfinite (double d)
1537 {
1538         if (isinf (d) || isnan (d))
1539                 mono_set_pending_exception (mono_get_exception_arithmetic ());
1540         return d;
1541 }