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