[runtime] Updates comments.
[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_set_pending_exception (mono_get_exception_overflow ());
939                 return 0;
940         }
941         return res;
942 }
943
944 guint64
945 mono_rconv_ovf_u8 (float v)
946 {
947         guint64 res;
948
949         res = (guint64)v;
950         if (isnan(v) || trunc (v) != res) {
951                 mono_set_pending_exception (mono_get_exception_overflow ());
952                 return 0;
953         }
954         return res;
955 }
956
957 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
958 double
959 mono_lconv_to_r8 (gint64 a)
960 {
961         return (double)a;
962 }
963 #endif
964
965 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
966 float
967 mono_lconv_to_r4 (gint64 a)
968 {
969         return (float)a;
970 }
971 #endif
972
973 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
974 double
975 mono_conv_to_r8_un (guint32 a)
976 {
977         return (double)a;
978 }
979 #endif
980
981 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
982 double
983 mono_lconv_to_r8_un (guint64 a)
984 {
985         return (double)a;
986 }
987 #endif
988
989 #if defined(__native_client_codegen__) || defined(__native_client__)
990 /* When we cross-compile to Native Client we can't directly embed calls */
991 /* to the math library on the host. This will use the fmod on the target*/
992 double
993 mono_fmod(double a, double b)
994 {
995         return fmod(a, b);
996 }
997 #endif
998
999 gpointer
1000 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1001 {
1002         MonoMethod *vmethod;
1003         gpointer addr;
1004         MonoGenericContext *context = mono_method_get_context (method);
1005
1006         mono_jit_stats.generic_virtual_invocations++;
1007
1008         if (obj == NULL) {
1009                 mono_set_pending_exception (mono_get_exception_null_reference ());
1010                 return NULL;
1011         }
1012         vmethod = mono_object_get_virtual_method (obj, method);
1013         g_assert (!vmethod->klass->generic_container);
1014         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1015         g_assert (!context->method_inst || !context->method_inst->is_open);
1016
1017         addr = mono_compile_method (vmethod);
1018
1019         addr = mini_add_method_trampoline (NULL, vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1020
1021         /* Since this is a virtual call, have to unbox vtypes */
1022         if (obj->vtable->klass->valuetype)
1023                 *this_arg = mono_object_unbox (obj);
1024         else
1025                 *this_arg = obj;
1026
1027         return addr;
1028 }
1029
1030 MonoString*
1031 mono_helper_ldstr (MonoImage *image, guint32 idx)
1032 {
1033         return mono_ldstr (mono_domain_get (), image, idx);
1034 }
1035
1036 MonoString*
1037 mono_helper_ldstr_mscorlib (guint32 idx)
1038 {
1039         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1040 }
1041
1042 MonoObject*
1043 mono_helper_newobj_mscorlib (guint32 idx)
1044 {
1045         MonoError error;
1046         MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1047         mono_error_raise_exception (&error);
1048
1049         return mono_object_new (mono_domain_get (), klass);
1050 }
1051
1052 /*
1053  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1054  * in generated code. So instead we emit a call to this function and place a gdb
1055  * breakpoint here.
1056  */
1057 void
1058 mono_break (void)
1059 {
1060 }
1061
1062 MonoException *
1063 mono_create_corlib_exception_0 (guint32 token)
1064 {
1065         return mono_exception_from_token (mono_defaults.corlib, token);
1066 }
1067
1068 MonoException *
1069 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1070 {
1071         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1072 }
1073
1074 MonoException *
1075 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1076 {
1077         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1078 }
1079
1080 MonoObject*
1081 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1082 {
1083         MonoJitTlsData *jit_tls = NULL;
1084         MonoClass *oklass;
1085
1086         if (mini_get_debug_options ()->better_cast_details) {
1087                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1088                 jit_tls->class_cast_from = NULL;
1089         }
1090
1091         if (!obj)
1092                 return NULL;
1093
1094         oklass = obj->vtable->klass;
1095         if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1096                 return obj;
1097         if (mono_object_isinst (obj, klass))
1098                 return obj;
1099
1100         if (mini_get_debug_options ()->better_cast_details) {
1101                 jit_tls->class_cast_from = oklass;
1102                 jit_tls->class_cast_to = klass;
1103         }
1104
1105         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1106                                         "System", "InvalidCastException"));
1107
1108         return NULL;
1109 }
1110
1111 MonoObject*
1112 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1113 {
1114         MonoJitTlsData *jit_tls = NULL;
1115         gpointer cached_vtable, obj_vtable;
1116
1117         if (mini_get_debug_options ()->better_cast_details) {
1118                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1119                 jit_tls->class_cast_from = NULL;
1120         }
1121
1122         if (!obj)
1123                 return NULL;
1124
1125         cached_vtable = *cache;
1126         obj_vtable = obj->vtable;
1127
1128         if (cached_vtable == obj_vtable)
1129                 return obj;
1130
1131         if (mono_object_isinst (obj, klass)) {
1132                 *cache = obj_vtable;
1133                 return obj;
1134         }
1135
1136         if (mini_get_debug_options ()->better_cast_details) {
1137                 jit_tls->class_cast_from = obj->vtable->klass;
1138                 jit_tls->class_cast_to = klass;
1139         }
1140
1141         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1142                                         "System", "InvalidCastException"));
1143
1144         return NULL;
1145 }
1146
1147 MonoObject*
1148 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1149 {
1150         size_t cached_vtable, obj_vtable;
1151
1152         if (!obj)
1153                 return NULL;
1154
1155         cached_vtable = (size_t)*cache;
1156         obj_vtable = (size_t)obj->vtable;
1157
1158         if ((cached_vtable & ~0x1) == obj_vtable) {
1159                 return (cached_vtable & 0x1) ? NULL : obj;
1160         }
1161
1162         if (mono_object_isinst (obj, klass)) {
1163                 *cache = (gpointer)obj_vtable;
1164                 return obj;
1165         } else {
1166                 /*negative cache*/
1167                 *cache = (gpointer)(obj_vtable | 0x1);
1168                 return NULL;
1169         }
1170 }
1171
1172 gpointer
1173 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1174 {
1175         MonoMarshalSpec **mspecs;
1176         MonoMethodPInvoke piinfo;
1177         MonoMethod *m;
1178
1179         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1180         memset (&piinfo, 0, sizeof (piinfo));
1181
1182         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1183
1184         return mono_compile_method (m);
1185 }
1186
1187 static MonoMethod*
1188 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1189 {
1190         MonoMethod *m;
1191         int vt_slot;
1192
1193         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1194                 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1195                 return NULL;
1196         }
1197
1198         if (mono_method_signature (cmethod)->pinvoke) {
1199                 /* Object.GetType () */
1200                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1201         } else {
1202                 /* Lookup the virtual method */
1203                 mono_class_setup_vtable (klass);
1204                 g_assert (klass->vtable);
1205                 vt_slot = mono_method_get_vtable_slot (cmethod);
1206                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1207                         int iface_offset;
1208
1209                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1210                         g_assert (iface_offset != -1);
1211                         vt_slot += iface_offset;
1212                 }
1213                 m = klass->vtable [vt_slot];
1214                 if (cmethod->is_inflated)
1215                         m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1216         }
1217         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1218                 /*
1219                  * Calling a non-vtype method with a vtype receiver, has to box.
1220                  */
1221                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1222         else if (klass->valuetype)
1223                 /*
1224                  * Calling a vtype method with a vtype receiver
1225                  */
1226                 *this_arg = mp;
1227         else
1228                 /*
1229                  * Calling a non-vtype method
1230                  */
1231                 *this_arg = *(gpointer*)mp;
1232         return m;
1233 }
1234
1235 /*
1236  * mono_gsharedvt_constrained_call:
1237  *
1238  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1239  * the arguments to the method in the format used by mono_runtime_invoke ().
1240  */
1241 MonoObject*
1242 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1243 {
1244         MonoMethod *m;
1245         gpointer this_arg;
1246         gpointer new_args [16];
1247
1248         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1249         if (args && deref_arg) {
1250                 new_args [0] = *(gpointer*)args [0];
1251                 args = new_args;
1252         }
1253         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1254                 /* Object.GetType () */
1255                 args = new_args;
1256                 args [0] = this_arg;
1257                 this_arg = NULL;
1258         }
1259         return mono_runtime_invoke (m, this_arg, args, NULL);
1260 }
1261
1262 void
1263 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1264 {
1265         if (klass->valuetype)
1266                 mono_value_copy (dest, src, klass);
1267         else
1268         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1269 }