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