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