Merge pull request #642 from Ventero/CleanCopyLocal
[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 gint64 
238 mono_lldiv (gint64 a, gint64 b)
239 {
240         MONO_ARCH_SAVE_REGS;
241
242 #ifdef MONO_ARCH_NEED_DIV_CHECK
243         if (!b)
244                 mono_raise_exception (mono_get_exception_divide_by_zero ());
245         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
246                 mono_raise_exception (mono_get_exception_arithmetic ());
247 #endif
248         return a / b;
249 }
250
251 gint64 
252 mono_llrem (gint64 a, gint64 b)
253 {
254         MONO_ARCH_SAVE_REGS;
255
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
257         if (!b)
258                 mono_raise_exception (mono_get_exception_divide_by_zero ());
259         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
260                 mono_raise_exception (mono_get_exception_arithmetic ());
261 #endif
262         return a % b;
263 }
264
265 guint64 
266 mono_lldiv_un (guint64 a, guint64 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 #endif
274         return a / b;
275 }
276
277 guint64 
278 mono_llrem_un (guint64 a, guint64 b)
279 {
280         MONO_ARCH_SAVE_REGS;
281
282 #ifdef MONO_ARCH_NEED_DIV_CHECK
283         if (!b)
284                 mono_raise_exception (mono_get_exception_divide_by_zero ());
285 #endif
286         return a % b;
287 }
288
289 #endif
290
291 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
292
293 guint64 
294 mono_lshl (guint64 a, gint32 shamt)
295 {
296         guint64 res;
297
298         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
299         res = a << shamt;
300
301         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
302
303         return res;
304 }
305
306 guint64 
307 mono_lshr_un (guint64 a, gint32 shamt)
308 {
309         guint64 res;
310
311         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
312         res = a >> shamt;
313
314         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
315
316         return res;
317 }
318
319 gint64 
320 mono_lshr (gint64 a, gint32 shamt)
321 {
322         gint64 res;
323
324         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
325         res = a >> shamt;
326
327         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
328
329         return res;
330 }
331
332 #endif
333
334 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
335
336 gint32
337 mono_idiv (gint32 a, gint32 b)
338 {
339         MONO_ARCH_SAVE_REGS;
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         return a / b;
348 }
349
350 guint32
351 mono_idiv_un (guint32 a, guint32 b)
352 {
353         MONO_ARCH_SAVE_REGS;
354
355 #ifdef MONO_ARCH_NEED_DIV_CHECK
356         if (!b)
357                 mono_raise_exception (mono_get_exception_divide_by_zero ());
358 #endif
359         return a / b;
360 }
361
362 gint32
363 mono_irem (gint32 a, gint32 b)
364 {
365         MONO_ARCH_SAVE_REGS;
366
367 #ifdef MONO_ARCH_NEED_DIV_CHECK
368         if (!b)
369                 mono_raise_exception (mono_get_exception_divide_by_zero ());
370         else if (b == -1 && a == (0x80000000))
371                 mono_raise_exception (mono_get_exception_overflow ());
372 #endif
373
374         return a % b;
375 }
376
377 guint32
378 mono_irem_un (guint32 a, guint32 b)
379 {
380         MONO_ARCH_SAVE_REGS;
381
382 #ifdef MONO_ARCH_NEED_DIV_CHECK
383         if (!b)
384                 mono_raise_exception (mono_get_exception_divide_by_zero ());
385 #endif
386         return a % b;
387 }
388
389 #endif
390
391 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
392
393 gint32
394 mono_imul (gint32 a, gint32 b)
395 {
396         MONO_ARCH_SAVE_REGS;
397
398         return a * b;
399 }
400
401 gint32
402 mono_imul_ovf (gint32 a, gint32 b)
403 {
404         gint64 res;
405
406         MONO_ARCH_SAVE_REGS;
407
408         res = (gint64)a * (gint64)b;
409
410         if ((res > 0x7fffffffL) || (res < -2147483648LL))
411                 mono_raise_exception (mono_get_exception_overflow ());
412
413         return res;
414 }
415
416 gint32
417 mono_imul_ovf_un (guint32 a, guint32 b)
418 {
419         guint64 res;
420
421         MONO_ARCH_SAVE_REGS;
422
423         res = (guint64)a * (guint64)b;
424
425         if ((res >> 32))
426                 mono_raise_exception (mono_get_exception_overflow ());
427
428         return res;
429 }
430 #endif
431
432 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
433 double
434 mono_fdiv (double a, double b)
435 {
436         MONO_ARCH_SAVE_REGS;
437
438         return a / b;
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 MonoArray *
769 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
770 {
771         MonoDomain *domain = mono_domain_get ();
772         uintptr_t lengths [4];
773         intptr_t *lower_bounds;
774         int pcount;
775         int rank;
776
777         MONO_ARCH_SAVE_REGS;
778
779         pcount = mono_method_signature (cm)->param_count;
780         rank = cm->klass->rank;
781
782         lengths [0] = length1;
783         lengths [1] = length2;
784         lengths [2] = length3;
785         lengths [3] = length4;
786
787         g_assert (rank == pcount);
788
789         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
790                 lower_bounds = alloca (sizeof (intptr_t) * rank);
791                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
792         } else {
793                 lower_bounds = NULL;
794         }
795
796         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
797 }
798
799 gpointer
800 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
801 {
802         MonoVTable *vtable;
803         gpointer addr;
804         
805         MONO_ARCH_SAVE_REGS;
806
807         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
808
809         mono_class_init (field->parent);
810
811         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
812         if (!vtable->initialized)
813                 mono_runtime_class_init (vtable);
814
815         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
816
817         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
818                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
819         else
820                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
821         
822         return addr;
823 }
824
825 gpointer
826 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
827 {
828         MonoClass *handle_class;
829         gpointer res;
830
831         MONO_ARCH_SAVE_REGS;
832         res = mono_ldtoken (image, token, &handle_class, context);      
833         mono_class_init (handle_class);
834
835         return res;
836 }
837
838 gpointer
839 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
840 {
841         MonoMethodSignature *sig = mono_method_signature (method);
842         MonoGenericContext *generic_context;
843
844         if (sig->is_inflated) {
845                 generic_context = mono_method_get_context (method);
846         } else {
847                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
848                 g_assert (generic_container);
849                 generic_context = &generic_container->context;
850         }
851
852         return mono_ldtoken_wrapper (image, token, generic_context);
853 }
854
855 guint64
856 mono_fconv_u8 (double v)
857 {
858         return (guint64)v;
859 }
860
861 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
862 gint64
863 mono_fconv_i8 (double v)
864 {
865         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
866         return (gint64)v;
867 }
868 #endif
869
870 guint32
871 mono_fconv_u4 (double v)
872 {
873         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
874         return (guint32)v;
875 }
876
877 #ifndef HAVE_TRUNC
878 /* Solaris doesn't have trunc */
879 #ifdef HAVE_AINTL
880 extern long double aintl (long double);
881 #define trunc aintl
882 #else
883 /* FIXME: This means we will never throw overflow exceptions */
884 #define trunc(v) res
885 #endif
886 #endif /* HAVE_TRUNC */
887
888 gint64
889 mono_fconv_ovf_i8 (double v)
890 {
891         gint64 res;
892
893         MONO_ARCH_SAVE_REGS;
894
895         res = (gint64)v;
896
897         if (isnan(v) || trunc (v) != res) {
898                 mono_raise_exception (mono_get_exception_overflow ());
899         }
900         return res;
901 }
902
903 guint64
904 mono_fconv_ovf_u8 (double v)
905 {
906         guint64 res;
907
908         MONO_ARCH_SAVE_REGS;
909 /*
910  * The soft-float implementation of some ARM devices have a buggy guin64 to double
911  * conversion that it looses precision even when the integer if fully representable
912  * as a double.
913  * 
914  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
915  * 
916  * To work around this issue we test for value boundaries instead. 
917  */
918 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT 
919         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
920                 mono_raise_exception (mono_get_exception_overflow ());
921         }
922         res = (guint64)v;
923 #else
924         res = (guint64)v;
925         if (isnan(v) || trunc (v) != res) {
926                 mono_raise_exception (mono_get_exception_overflow ());
927         }
928 #endif
929         return res;
930 }
931
932 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
933 double
934 mono_lconv_to_r8 (gint64 a)
935 {
936         return (double)a;
937 }
938 #endif
939
940 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
941 float
942 mono_lconv_to_r4 (gint64 a)
943 {
944         return (float)a;
945 }
946 #endif
947
948 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
949 double
950 mono_conv_to_r8_un (guint32 a)
951 {
952         return (double)a;
953 }
954 #endif
955
956 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
957 double
958 mono_lconv_to_r8_un (guint64 a)
959 {
960         return (double)a;
961 }
962 #endif
963
964 #if defined(__native_client_codegen__) || defined(__native_client__)
965 /* When we cross-compile to Native Client we can't directly embed calls */
966 /* to the math library on the host. This will use the fmod on the target*/
967 double
968 mono_fmod(double a, double b)
969 {
970         return fmod(a, b);
971 }
972 #endif
973
974 gpointer
975 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
976 {
977         MonoMethod *vmethod;
978         gpointer addr;
979         MonoGenericContext *context = mono_method_get_context (method);
980
981         mono_jit_stats.generic_virtual_invocations++;
982
983         if (obj == NULL)
984                 mono_raise_exception (mono_get_exception_null_reference ());
985         vmethod = mono_object_get_virtual_method (obj, method);
986         g_assert (!vmethod->klass->generic_container);
987         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
988         g_assert (!context->method_inst || !context->method_inst->is_open);
989
990         addr = mono_compile_method (vmethod);
991
992         if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE))
993                 addr = mono_create_static_rgctx_trampoline (vmethod, addr);
994
995         /* Since this is a virtual call, have to unbox vtypes */
996         if (obj->vtable->klass->valuetype)
997                 *this_arg = mono_object_unbox (obj);
998         else
999                 *this_arg = obj;
1000
1001         return addr;
1002 }
1003
1004 MonoString*
1005 mono_helper_ldstr (MonoImage *image, guint32 idx)
1006 {
1007         return mono_ldstr (mono_domain_get (), image, idx);
1008 }
1009
1010 MonoString*
1011 mono_helper_ldstr_mscorlib (guint32 idx)
1012 {
1013         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1014 }
1015
1016 MonoObject*
1017 mono_helper_newobj_mscorlib (guint32 idx)
1018 {
1019         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
1020         
1021         g_assert (klass);
1022
1023         return mono_object_new (mono_domain_get (), klass);
1024 }
1025
1026 /*
1027  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1028  * in generated code. So instead we emit a call to this function and place a gdb
1029  * breakpoint here.
1030  */
1031 void
1032 mono_break (void)
1033 {
1034 }
1035
1036 MonoException *
1037 mono_create_corlib_exception_0 (guint32 token)
1038 {
1039         return mono_exception_from_token (mono_defaults.corlib, token);
1040 }
1041
1042 MonoException *
1043 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1044 {
1045         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1046 }
1047
1048 MonoException *
1049 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1050 {
1051         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1052 }
1053
1054 MonoObject*
1055 mono_object_castclass (MonoObject *obj, MonoClass *klass)
1056 {
1057         MonoJitTlsData *jit_tls = NULL;
1058
1059         if (mini_get_debug_options ()->better_cast_details) {
1060                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1061                 jit_tls->class_cast_from = NULL;
1062         }
1063
1064         if (!obj)
1065                 return NULL;
1066
1067         if (mono_object_isinst (obj, klass))
1068                 return obj;
1069
1070         if (mini_get_debug_options ()->better_cast_details) {
1071                 jit_tls->class_cast_from = obj->vtable->klass;
1072                 jit_tls->class_cast_to = klass;
1073         }
1074
1075         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1076                                         "System", "InvalidCastException"));
1077
1078         return NULL;
1079 }
1080
1081 MonoObject*
1082 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1083 {
1084         MonoJitTlsData *jit_tls = NULL;
1085         gpointer cached_vtable, obj_vtable;
1086
1087         if (mini_get_debug_options ()->better_cast_details) {
1088                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1089                 jit_tls->class_cast_from = NULL;
1090         }
1091
1092         if (!obj)
1093                 return NULL;
1094
1095         cached_vtable = *cache;
1096         obj_vtable = obj->vtable;
1097
1098         if (cached_vtable == obj_vtable)
1099                 return obj;
1100
1101         if (mono_object_isinst (obj, klass)) {
1102                 *cache = obj_vtable;
1103                 return obj;
1104         }
1105
1106         if (mini_get_debug_options ()->better_cast_details) {
1107                 jit_tls->class_cast_from = obj->vtable->klass;
1108                 jit_tls->class_cast_to = klass;
1109         }
1110
1111         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1112                                         "System", "InvalidCastException"));
1113
1114         return NULL;
1115 }
1116
1117 MonoObject*
1118 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1119 {
1120         size_t cached_vtable, obj_vtable;
1121
1122         if (!obj)
1123                 return NULL;
1124
1125         cached_vtable = (size_t)*cache;
1126         obj_vtable = (size_t)obj->vtable;
1127
1128         if ((cached_vtable & ~0x1) == obj_vtable) {
1129                 return (cached_vtable & 0x1) ? NULL : obj;
1130         }
1131
1132         if (mono_object_isinst (obj, klass)) {
1133                 *cache = (gpointer)obj_vtable;
1134                 return obj;
1135         } else {
1136                 /*negative cache*/
1137                 *cache = (gpointer)(obj_vtable | 0x1);
1138                 return NULL;
1139         }
1140 }
1141
1142 gpointer
1143 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1144 {
1145         MonoMarshalSpec **mspecs;
1146         MonoMethodPInvoke piinfo;
1147         MonoMethod *m;
1148
1149         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1150         memset (&piinfo, 0, sizeof (piinfo));
1151
1152         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1153
1154         return mono_compile_method (m);
1155 }
1156
1157 static MonoMethod*
1158 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1159 {
1160         MonoMethod *m;
1161         int vt_slot;
1162
1163         /* Lookup the virtual method */
1164         mono_class_setup_vtable (klass);
1165         g_assert (klass->vtable);
1166         vt_slot = mono_method_get_vtable_slot (cmethod);
1167         m = klass->vtable [vt_slot];
1168         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1169                 /*
1170                  * Calling a non-vtype method with a vtype receiver, has to box.
1171                  */
1172                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1173         else if (klass->valuetype)
1174                 /*
1175                  * Calling a vtype method with a vtype receiver
1176                  */
1177                 *this_arg = mp;
1178         else
1179                 /*
1180                  * Calling a non-vtype method
1181                  */
1182                 *this_arg = *(gpointer*)mp;
1183         return m;
1184 }
1185
1186 MonoObject*
1187 mono_object_tostring_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass)
1188 {
1189         MonoMethod *m;
1190         gpointer this_arg;
1191
1192         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1193         return mono_runtime_invoke (m, this_arg, NULL, NULL);
1194 }
1195
1196 int
1197 mono_object_gethashcode_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass)
1198 {
1199         MonoMethod *m;
1200         gpointer this_arg;
1201         MonoObject *res;
1202         gpointer p;
1203
1204         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1205         // FIXME: This boxes the result
1206         res = mono_runtime_invoke (m, this_arg, NULL, NULL);
1207         p = mono_object_unbox (res);
1208         return *(int*)p;
1209 }
1210
1211 MonoBoolean
1212 mono_object_equals_gsharedvt (gpointer mp, MonoMethod *cmethod, MonoClass *klass, MonoObject *arg)
1213 {
1214         MonoMethod *m;
1215         gpointer this_arg;
1216         MonoObject *res;
1217         gpointer p;
1218         void **args;
1219
1220         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1221         // FIXME: This boxes the result
1222         args = (void**)&arg;
1223         res = mono_runtime_invoke (m, this_arg, args, NULL);
1224         p = mono_object_unbox (res);
1225         return *(MonoBoolean*)p;
1226 }
1227
1228 void
1229 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1230 {
1231         if (klass->valuetype)
1232                 mono_value_copy (dest, src, klass);
1233         else
1234         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1235 }