[xbuild] Set @(CollectedBuildOutput) for projects build from .sln .
[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  */
10 #include <config.h>
11 #include <math.h>
12 #include <limits.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16
17 #include "jit-icalls.h"
18
19 void*
20 mono_ldftn (MonoMethod *method)
21 {
22         gpointer addr;
23
24         MONO_ARCH_SAVE_REGS;
25
26         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
27
28         return mono_create_ftnptr (mono_domain_get (), addr);
29 }
30
31 static void*
32 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
33 {
34         MonoMethod *res;
35
36         MONO_ARCH_SAVE_REGS;
37
38         if (obj == NULL)
39                 mono_raise_exception (mono_get_exception_null_reference ());
40
41         res = mono_object_get_virtual_method (obj, method);
42
43         if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
44                 MonoGenericContext context = { NULL, NULL };
45
46                 if (res->klass->generic_class)
47                         context.class_inst = res->klass->generic_class->context.class_inst;
48                 else if (res->klass->generic_container)
49                         context.class_inst = res->klass->generic_container->context.class_inst;
50                 context.method_inst = mono_method_get_context (method)->method_inst;
51
52                 res = mono_class_inflate_generic_method (res, &context);
53         }
54
55         /* An rgctx wrapper is added by the trampolines no need to do it here */
56
57         return mono_ldftn (res);
58 }
59
60 void*
61 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
62 {
63         return ldvirtfn_internal (obj, method, FALSE);
64 }
65
66 void*
67 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) 
68 {
69         return ldvirtfn_internal (obj, method, TRUE);
70 }
71
72 void
73 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
74 {
75         MONO_ARCH_SAVE_REGS;
76
77         if (!array)
78                 mono_raise_exception (mono_get_exception_null_reference ());
79         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
80                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
81 }
82
83 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
84
85 gint64 
86 mono_llmult (gint64 a, gint64 b)
87 {
88         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
89         return a * b;
90 }
91
92 guint64  
93 mono_llmult_ovf_un (guint64 a, guint64 b)
94 {
95         guint32 al = a;
96         guint32 ah = a >> 32;
97         guint32 bl = b;
98         guint32 bh = b >> 32; 
99         guint64 res, t1;
100
101         MONO_ARCH_SAVE_REGS;
102
103         // fixme: this is incredible slow
104
105         if (ah && bh)
106                 goto raise_exception;
107
108         res = (guint64)al * (guint64)bl;
109
110         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
111
112         if (t1 > 0xffffffff)
113                 goto raise_exception;
114
115         res += ((guint64)t1) << 32; 
116
117         return res;
118
119  raise_exception:
120         mono_raise_exception (mono_get_exception_overflow ());
121         return 0;
122 }
123
124 guint64  
125 mono_llmult_ovf (gint64 a, gint64 b) 
126 {
127         guint32 al = a;
128         gint32 ah = a >> 32;
129         guint32 bl = b;
130         gint32 bh = b >> 32; 
131         /*
132         Use Karatsuba algorithm where:
133                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
134                 where Ah is the "high half" (most significant 32 bits) of a and
135                 where Al is the "low half" (least significant 32 bits) of a and
136                 where  Bh is the "high half" of b and Bl is the "low half" and
137                 where R is the Radix or "size of the half" (in our case 32 bits)
138
139         Note, for the product of two 64 bit numbers to fit into a 64
140         result, ah and/or bh must be 0.  This will save us from doing
141         the AhBh term at all.
142
143         Also note that we refactor so that we don't overflow 64 bits with 
144         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
145         */
146
147         gint64 res, t1;
148         gint32 sign;
149
150         MONO_ARCH_SAVE_REGS;
151
152         /* need to work with absoulte values, so find out what the
153            resulting sign will be and convert any negative numbers
154            from two's complement
155         */
156         sign = ah ^ bh;
157         if (ah < 0) {
158                 if (((guint32)ah == 0x80000000) && (al == 0)) {
159                         /* This has no two's complement */
160                         if (b == 0)
161                                 return 0;
162                         else if (b == 1)
163                                 return a;
164                         else
165                                 goto raise_exception;
166                 }
167
168                 /* flip the bits and add 1 */
169                 ah ^= ~0;
170                 if (al ==  0)
171                         ah += 1;
172                 else {
173                         al ^= ~0;
174                         al +=1;
175                 }
176         }
177
178         if (bh < 0) {
179                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
180                         /* This has no two's complement */
181                         if (a == 0)
182                                 return 0;
183                         else if (a == 1)
184                                 return b;
185                         else
186                                 goto raise_exception;
187                 }
188
189                 /* flip the bits and add 1 */
190                 bh ^= ~0;
191                 if (bl ==  0)
192                         bh += 1;
193                 else {
194                         bl ^= ~0;
195                         bl +=1;
196                 }
197         }
198                 
199         /* we overflow for sure if both upper halves are greater 
200            than zero because we would need to shift their 
201            product 64 bits to the left and that will not fit
202            in a 64 bit result */
203         if (ah && bh)
204                 goto raise_exception;
205         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
206                 goto raise_exception;
207
208         /* do the AlBl term first */
209         t1 = (gint64)al * (gint64)bl;
210
211         res = t1;
212
213         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
214         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
215         /* check for overflow */
216         t1 <<= 32;
217         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
218                 goto raise_exception;
219
220         res += t1;
221
222         if (res < 0)
223                 goto raise_exception;
224
225         if (sign < 0)
226                 return -res;
227         else
228                 return res;
229
230  raise_exception:
231         mono_raise_exception (mono_get_exception_overflow ());
232         return 0;
233 }
234
235 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
236
237 gint32
238 mono_idiv (gint32 a, gint32 b)
239 {
240         MONO_ARCH_SAVE_REGS;
241
242 #ifdef MONO_ARCH_NEED_DIV_CHECK
243         if (!b)
244                 mono_raise_exception (mono_get_exception_divide_by_zero ());
245         else if (b == -1 && a == (0x80000000))
246                 mono_raise_exception (mono_get_exception_overflow ());
247 #endif
248         return a / b;
249 }
250
251 guint32
252 mono_idiv_un (guint32 a, guint32 b)
253 {
254         MONO_ARCH_SAVE_REGS;
255
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
257         if (!b)
258                 mono_raise_exception (mono_get_exception_divide_by_zero ());
259 #endif
260         return a / b;
261 }
262
263 gint32
264 mono_irem (gint32 a, gint32 b)
265 {
266         MONO_ARCH_SAVE_REGS;
267
268 #ifdef MONO_ARCH_NEED_DIV_CHECK
269         if (!b)
270                 mono_raise_exception (mono_get_exception_divide_by_zero ());
271         else if (b == -1 && a == (0x80000000))
272                 mono_raise_exception (mono_get_exception_overflow ());
273 #endif
274
275         return a % b;
276 }
277
278 guint32
279 mono_irem_un (guint32 a, guint32 b)
280 {
281         MONO_ARCH_SAVE_REGS;
282
283 #ifdef MONO_ARCH_NEED_DIV_CHECK
284         if (!b)
285                 mono_raise_exception (mono_get_exception_divide_by_zero ());
286 #endif
287         return a % b;
288 }
289
290 #endif
291
292 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
293
294 gint32
295 mono_imul (gint32 a, gint32 b)
296 {
297         MONO_ARCH_SAVE_REGS;
298
299         return a * b;
300 }
301
302 gint32
303 mono_imul_ovf (gint32 a, gint32 b)
304 {
305         gint64 res;
306
307         MONO_ARCH_SAVE_REGS;
308
309         res = (gint64)a * (gint64)b;
310
311         if ((res > 0x7fffffffL) || (res < -2147483648LL))
312                 mono_raise_exception (mono_get_exception_overflow ());
313
314         return res;
315 }
316
317 gint32
318 mono_imul_ovf_un (guint32 a, guint32 b)
319 {
320         guint64 res;
321
322         MONO_ARCH_SAVE_REGS;
323
324         res = (guint64)a * (guint64)b;
325
326         if ((res >> 32))
327                 mono_raise_exception (mono_get_exception_overflow ());
328
329         return res;
330 }
331 #endif
332
333 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
334 double
335 mono_fdiv (double a, double b)
336 {
337         MONO_ARCH_SAVE_REGS;
338
339         return a / b;
340 }
341 #endif
342
343 gint64 
344 mono_lldiv (gint64 a, gint64 b)
345 {
346         MONO_ARCH_SAVE_REGS;
347
348 #ifdef MONO_ARCH_NEED_DIV_CHECK
349         if (!b)
350                 mono_raise_exception (mono_get_exception_divide_by_zero ());
351         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
352                 mono_raise_exception (mono_get_exception_arithmetic ());
353 #endif
354         return a / b;
355 }
356
357 gint64 
358 mono_llrem (gint64 a, gint64 b)
359 {
360         MONO_ARCH_SAVE_REGS;
361
362 #ifdef MONO_ARCH_NEED_DIV_CHECK
363         if (!b)
364                 mono_raise_exception (mono_get_exception_divide_by_zero ());
365         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
366                 mono_raise_exception (mono_get_exception_arithmetic ());
367 #endif
368         return a % b;
369 }
370
371 guint64 
372 mono_lldiv_un (guint64 a, guint64 b)
373 {
374         MONO_ARCH_SAVE_REGS;
375
376 #ifdef MONO_ARCH_NEED_DIV_CHECK
377         if (!b)
378                 mono_raise_exception (mono_get_exception_divide_by_zero ());
379 #endif
380         return a / b;
381 }
382
383 guint64 
384 mono_llrem_un (guint64 a, guint64 b)
385 {
386         MONO_ARCH_SAVE_REGS;
387
388 #ifdef MONO_ARCH_NEED_DIV_CHECK
389         if (!b)
390                 mono_raise_exception (mono_get_exception_divide_by_zero ());
391 #endif
392         return a % b;
393 }
394
395 #endif
396
397 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
398
399 guint64 
400 mono_lshl (guint64 a, gint32 shamt)
401 {
402         guint64 res;
403
404         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
405         res = a << shamt;
406
407         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
408
409         return res;
410 }
411
412 guint64 
413 mono_lshr_un (guint64 a, gint32 shamt)
414 {
415         guint64 res;
416
417         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
418         res = a >> shamt;
419
420         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
421
422         return res;
423 }
424
425 gint64 
426 mono_lshr (gint64 a, gint32 shamt)
427 {
428         gint64 res;
429
430         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
431         res = a >> shamt;
432
433         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
434
435         return res;
436 }
437
438 #endif
439
440 #ifdef MONO_ARCH_SOFT_FLOAT
441
442 double
443 mono_fsub (double a, double b)
444 {
445         return a - b;
446 }
447
448 double
449 mono_fadd (double a, double b)
450 {
451         return a + b;
452 }
453
454 double
455 mono_fmul (double a, double b)
456 {
457         return a * b;
458 }
459
460 double
461 mono_fneg (double a)
462 {
463         return -a;
464 }
465
466 double
467 mono_fconv_r4 (double a)
468 {
469         return (float)a;
470 }
471
472 double
473 mono_conv_to_r8 (int a)
474 {
475         return (double)a;
476 }
477
478 double
479 mono_conv_to_r4 (int a)
480 {
481         return (double)(float)a;
482 }
483
484 gint8
485 mono_fconv_i1 (double a)
486 {
487         return (gint8)a;
488 }
489
490 gint16
491 mono_fconv_i2 (double a)
492 {
493         return (gint16)a;
494 }
495
496 gint32
497 mono_fconv_i4 (double a)
498 {
499         return (gint32)a;
500 }
501
502 guint8
503 mono_fconv_u1 (double a)
504 {
505         return (guint8)a;
506 }
507
508 guint16
509 mono_fconv_u2 (double a)
510 {
511         return (guint16)a;
512 }
513
514 gboolean
515 mono_fcmp_eq (double a, double b)
516 {
517         return a == b;
518 }
519
520 gboolean
521 mono_fcmp_ge (double a, double b)
522 {
523         return a >= b;
524 }
525
526 gboolean
527 mono_fcmp_gt (double a, double b)
528 {
529         return a > b;
530 }
531
532 gboolean
533 mono_fcmp_le (double a, double b)
534 {
535         return a <= b;
536 }
537
538 gboolean
539 mono_fcmp_lt (double a, double b)
540 {
541         return a < b;
542 }
543
544 gboolean
545 mono_fcmp_ne_un (double a, double b)
546 {
547         return isunordered (a, b) || a != b;
548 }
549
550 gboolean
551 mono_fcmp_ge_un (double a, double b)
552 {
553         return isunordered (a, b) || a >= b;
554 }
555
556 gboolean
557 mono_fcmp_gt_un (double a, double b)
558 {
559         return isunordered (a, b) || a > b;
560 }
561
562 gboolean
563 mono_fcmp_le_un (double a, double b)
564 {
565         return isunordered (a, b) || a <= b;
566 }
567
568 gboolean
569 mono_fcmp_lt_un (double a, double b)
570 {
571         return isunordered (a, b) || a < b;
572 }
573
574 gboolean
575 mono_fceq (double a, double b)
576 {
577         return a == b;
578 }
579
580 gboolean
581 mono_fcgt (double a, double b)
582 {
583         return a > b;
584 }
585
586 gboolean
587 mono_fcgt_un (double a, double b)
588 {
589         return isunordered (a, b) || a > b;
590 }
591
592 gboolean
593 mono_fclt (double a, double b)
594 {
595         return a < b;
596 }
597
598 gboolean
599 mono_fclt_un (double a, double b)
600 {
601         return isunordered (a, b) || a < b;
602 }
603
604 gboolean
605 mono_isfinite (double a)
606 {
607 #ifdef HAVE_ISFINITE
608         return isfinite (a);
609 #else
610         g_assert_not_reached ();
611         return TRUE;
612 #endif
613 }
614
615 double
616 mono_fload_r4 (float *ptr)
617 {
618         return *ptr;
619 }
620
621 void
622 mono_fstore_r4 (double val, float *ptr)
623 {
624         *ptr = (float)val;
625 }
626
627 /* returns the integer bitpattern that is passed in the regs or stack */
628 guint32
629 mono_fload_r4_arg (double val)
630 {
631         float v = (float)val;
632         return *(guint32*)&v;
633 }
634
635 #endif
636
637 MonoArray *
638 mono_array_new_va (MonoMethod *cm, ...)
639 {
640         MonoDomain *domain = mono_domain_get ();
641         va_list ap;
642         uintptr_t *lengths;
643         intptr_t *lower_bounds;
644         int pcount;
645         int rank;
646         int i, d;
647
648         MONO_ARCH_SAVE_REGS;
649
650         pcount = mono_method_signature (cm)->param_count;
651         rank = cm->klass->rank;
652
653         va_start (ap, cm);
654         
655         lengths = alloca (sizeof (uintptr_t) * pcount);
656         for (i = 0; i < pcount; ++i)
657                 lengths [i] = d = va_arg(ap, int);
658
659         if (rank == pcount) {
660                 /* Only lengths provided. */
661                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
662                         lower_bounds = alloca (sizeof (intptr_t) * rank);
663                         memset (lower_bounds, 0, sizeof (intptr_t) * rank);
664                 } else {
665                         lower_bounds = NULL;
666                 }
667         } else {
668                 g_assert (pcount == (rank * 2));
669                 /* lower bounds are first. */
670                 lower_bounds = (intptr_t*)lengths;
671                 lengths += rank;
672         }
673         va_end(ap);
674
675         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
676 }
677
678 /* Specialized version of mono_array_new_va () which avoids varargs */
679 MonoArray *
680 mono_array_new_1 (MonoMethod *cm, guint32 length)
681 {
682         MonoDomain *domain = mono_domain_get ();
683         uintptr_t lengths [1];
684         intptr_t *lower_bounds;
685         int pcount;
686         int rank;
687
688         MONO_ARCH_SAVE_REGS;
689
690         pcount = mono_method_signature (cm)->param_count;
691         rank = cm->klass->rank;
692
693         lengths [0] = length;
694
695         g_assert (rank == pcount);
696
697         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
698                 lower_bounds = alloca (sizeof (intptr_t) * rank);
699                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
700         } else {
701                 lower_bounds = NULL;
702         }
703
704         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
705 }
706
707 MonoArray *
708 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
709 {
710         MonoDomain *domain = mono_domain_get ();
711         uintptr_t lengths [2];
712         intptr_t *lower_bounds;
713         int pcount;
714         int rank;
715
716         MONO_ARCH_SAVE_REGS;
717
718         pcount = mono_method_signature (cm)->param_count;
719         rank = cm->klass->rank;
720
721         lengths [0] = length1;
722         lengths [1] = length2;
723
724         g_assert (rank == pcount);
725
726         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
727                 lower_bounds = alloca (sizeof (intptr_t) * rank);
728                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
729         } else {
730                 lower_bounds = NULL;
731         }
732
733         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
734 }
735
736 MonoArray *
737 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
738 {
739         MonoDomain *domain = mono_domain_get ();
740         uintptr_t lengths [3];
741         intptr_t *lower_bounds;
742         int pcount;
743         int rank;
744
745         MONO_ARCH_SAVE_REGS;
746
747         pcount = mono_method_signature (cm)->param_count;
748         rank = cm->klass->rank;
749
750         lengths [0] = length1;
751         lengths [1] = length2;
752         lengths [2] = length3;
753
754         g_assert (rank == pcount);
755
756         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
757                 lower_bounds = alloca (sizeof (intptr_t) * rank);
758                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
759         } else {
760                 lower_bounds = NULL;
761         }
762
763         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
764 }
765
766 gpointer
767 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
768 {
769         MonoVTable *vtable;
770         gpointer addr;
771         
772         MONO_ARCH_SAVE_REGS;
773
774         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
775
776         mono_class_init (field->parent);
777
778         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
779         if (!vtable->initialized)
780                 mono_runtime_class_init (vtable);
781
782         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
783
784         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
785                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
786         else
787                 addr = (char*)vtable->data + field->offset;
788         
789         return addr;
790 }
791
792 gpointer
793 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
794 {
795         MonoClass *handle_class;
796         gpointer res;
797
798         MONO_ARCH_SAVE_REGS;
799         res = mono_ldtoken (image, token, &handle_class, context);      
800         mono_class_init (handle_class);
801
802         return res;
803 }
804
805 gpointer
806 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
807 {
808         MonoMethodSignature *sig = mono_method_signature (method);
809         MonoGenericContext *generic_context;
810
811         if (sig->is_inflated) {
812                 generic_context = mono_method_get_context (method);
813         } else {
814                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
815                 g_assert (generic_container);
816                 generic_context = &generic_container->context;
817         }
818
819         return mono_ldtoken_wrapper (image, token, generic_context);
820 }
821
822 guint64
823 mono_fconv_u8 (double v)
824 {
825         return (guint64)v;
826 }
827
828 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
829 gint64
830 mono_fconv_i8 (double v)
831 {
832         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
833         return (gint64)v;
834 }
835 #endif
836
837 guint32
838 mono_fconv_u4 (double v)
839 {
840         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
841         return (guint32)v;
842 }
843
844 #ifndef HAVE_TRUNC
845 /* Solaris doesn't have trunc */
846 #ifdef HAVE_AINTL
847 extern long double aintl (long double);
848 #define trunc aintl
849 #else
850 /* FIXME: This means we will never throw overflow exceptions */
851 #define trunc(v) res
852 #endif
853 #endif /* HAVE_TRUNC */
854
855 gint64
856 mono_fconv_ovf_i8 (double v)
857 {
858         gint64 res;
859
860         MONO_ARCH_SAVE_REGS;
861
862         res = (gint64)v;
863
864         if (isnan(v) || trunc (v) != res) {
865                 mono_raise_exception (mono_get_exception_overflow ());
866         }
867         return res;
868 }
869
870 guint64
871 mono_fconv_ovf_u8 (double v)
872 {
873         guint64 res;
874
875         MONO_ARCH_SAVE_REGS;
876 /*
877  * The soft-float implementation of some ARM devices have a buggy guin64 to double
878  * conversion that it looses precision even when the integer if fully representable
879  * as a double.
880  * 
881  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
882  * 
883  * To work around this issue we test for value boundaries instead. 
884  */
885 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT 
886         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
887                 mono_raise_exception (mono_get_exception_overflow ());
888         }
889         res = (guint64)v;
890 #else
891         res = (guint64)v;
892         if (isnan(v) || trunc (v) != res) {
893                 mono_raise_exception (mono_get_exception_overflow ());
894         }
895 #endif
896         return res;
897 }
898
899 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
900 double
901 mono_lconv_to_r8 (gint64 a)
902 {
903         return (double)a;
904 }
905 #endif
906
907 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
908 float
909 mono_lconv_to_r4 (gint64 a)
910 {
911         return (float)a;
912 }
913 #endif
914
915 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
916 double
917 mono_conv_to_r8_un (guint32 a)
918 {
919         return (double)a;
920 }
921 #endif
922
923 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
924 double
925 mono_lconv_to_r8_un (guint64 a)
926 {
927         return (double)a;
928 }
929 #endif
930
931 #if defined(__native_client_codegen__) || defined(__native_client__)
932 /* When we cross-compile to Native Client we can't directly embed calls */
933 /* to the math library on the host. This will use the fmod on the target*/
934 double
935 mono_fmod(double a, double b)
936 {
937         return fmod(a, b);
938 }
939 #endif
940
941 gpointer
942 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
943 {
944         MonoMethod *vmethod;
945         gpointer addr;
946         MonoGenericContext *context = mono_method_get_context (method);
947
948         mono_jit_stats.generic_virtual_invocations++;
949
950         if (obj == NULL)
951                 mono_raise_exception (mono_get_exception_null_reference ());
952         vmethod = mono_object_get_virtual_method (obj, method);
953         g_assert (!vmethod->klass->generic_container);
954         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
955         g_assert (!context->method_inst || !context->method_inst->is_open);
956
957         addr = mono_compile_method (vmethod);
958
959         if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
960                 addr = mono_create_static_rgctx_trampoline (vmethod, addr);
961
962         /* Since this is a virtual call, have to unbox vtypes */
963         if (obj->vtable->klass->valuetype)
964                 *this_arg = mono_object_unbox (obj);
965         else
966                 *this_arg = obj;
967
968         return addr;
969 }
970
971 MonoString*
972 mono_helper_ldstr (MonoImage *image, guint32 idx)
973 {
974         return mono_ldstr (mono_domain_get (), image, idx);
975 }
976
977 MonoString*
978 mono_helper_ldstr_mscorlib (guint32 idx)
979 {
980         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
981 }
982
983 MonoObject*
984 mono_helper_newobj_mscorlib (guint32 idx)
985 {
986         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
987         
988         g_assert (klass);
989
990         return mono_object_new (mono_domain_get (), klass);
991 }
992
993 /*
994  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
995  * in generated code. So instead we emit a call to this function and place a gdb
996  * breakpoint here.
997  */
998 void
999 mono_break (void)
1000 {
1001 }
1002
1003 MonoException *
1004 mono_create_corlib_exception_0 (guint32 token)
1005 {
1006         return mono_exception_from_token (mono_defaults.corlib, token);
1007 }
1008
1009 MonoException *
1010 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1011 {
1012         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1013 }
1014
1015 MonoException *
1016 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1017 {
1018         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1019 }
1020
1021 MonoObject*
1022 mono_object_castclass (MonoObject *obj, MonoClass *klass)
1023 {
1024         MonoJitTlsData *jit_tls = NULL;
1025
1026         if (mini_get_debug_options ()->better_cast_details) {
1027                 jit_tls = TlsGetValue (mono_jit_tls_id);
1028                 jit_tls->class_cast_from = NULL;
1029         }
1030
1031         if (!obj)
1032                 return NULL;
1033
1034         if (mono_object_isinst (obj, klass))
1035                 return obj;
1036
1037         if (mini_get_debug_options ()->better_cast_details) {
1038                 jit_tls->class_cast_from = obj->vtable->klass;
1039                 jit_tls->class_cast_to = klass;
1040         }
1041
1042         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1043                                         "System", "InvalidCastException"));
1044
1045         return NULL;
1046 }
1047
1048 MonoObject*
1049 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1050 {
1051         MonoJitTlsData *jit_tls = NULL;
1052         gpointer cached_vtable, obj_vtable;
1053
1054         if (mini_get_debug_options ()->better_cast_details) {
1055                 jit_tls = TlsGetValue (mono_jit_tls_id);
1056                 jit_tls->class_cast_from = NULL;
1057         }
1058
1059         if (!obj)
1060                 return NULL;
1061
1062         cached_vtable = *cache;
1063         obj_vtable = obj->vtable;
1064
1065         if (cached_vtable == obj_vtable)
1066                 return obj;
1067
1068         if (mono_object_isinst (obj, klass)) {
1069                 *cache = obj_vtable;
1070                 return obj;
1071         }
1072
1073         if (mini_get_debug_options ()->better_cast_details) {
1074                 jit_tls->class_cast_from = obj->vtable->klass;
1075                 jit_tls->class_cast_to = klass;
1076         }
1077
1078         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1079                                         "System", "InvalidCastException"));
1080
1081         return NULL;
1082 }
1083
1084 MonoObject*
1085 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1086 {
1087         size_t cached_vtable, obj_vtable;
1088
1089         if (!obj)
1090                 return NULL;
1091
1092         cached_vtable = (size_t)*cache;
1093         obj_vtable = (size_t)obj->vtable;
1094
1095         if ((cached_vtable & ~0x1) == obj_vtable) {
1096                 return (cached_vtable & 0x1) ? NULL : obj;
1097         }
1098
1099         if (mono_object_isinst (obj, klass)) {
1100                 *cache = (gpointer)obj_vtable;
1101                 return obj;
1102         } else {
1103                 /*negative cache*/
1104                 *cache = (gpointer)(obj_vtable | 0x1);
1105                 return NULL;
1106         }
1107 }
1108
1109 gpointer
1110 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1111 {
1112         MonoMarshalSpec **mspecs;
1113         MonoMethodPInvoke piinfo;
1114         MonoMethod *m;
1115
1116         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1117         memset (&piinfo, 0, sizeof (piinfo));
1118
1119         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1120
1121         return mono_compile_method (m);
1122 }