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