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