Merge pull request #1267 from ramtinkermani/master
[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         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 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_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_FALLBACK)
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_FALLBACK
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
875         /* MS.NET behaves like this for some reason */
876 #ifdef HAVE_ISINF
877         if (isinf (v) || isnan (v))
878                 return 0;
879 #endif
880
881         return (guint32)v;
882 }
883
884 #ifndef HAVE_TRUNC
885 /* Solaris doesn't have trunc */
886 #ifdef HAVE_AINTL
887 extern long double aintl (long double);
888 #define trunc aintl
889 #else
890 /* FIXME: This means we will never throw overflow exceptions */
891 #define trunc(v) res
892 #endif
893 #endif /* HAVE_TRUNC */
894
895 gint64
896 mono_fconv_ovf_i8 (double v)
897 {
898         gint64 res;
899
900         MONO_ARCH_SAVE_REGS;
901
902         res = (gint64)v;
903
904         if (isnan(v) || trunc (v) != res) {
905                 mono_raise_exception (mono_get_exception_overflow ());
906         }
907         return res;
908 }
909
910 guint64
911 mono_fconv_ovf_u8 (double v)
912 {
913         guint64 res;
914
915         MONO_ARCH_SAVE_REGS;
916 /*
917  * The soft-float implementation of some ARM devices have a buggy guin64 to double
918  * conversion that it looses precision even when the integer if fully representable
919  * as a double.
920  * 
921  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
922  * 
923  * To work around this issue we test for value boundaries instead. 
924  */
925 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
926         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
927                 mono_raise_exception (mono_get_exception_overflow ());
928         }
929         res = (guint64)v;
930 #else
931         res = (guint64)v;
932         if (isnan(v) || trunc (v) != res) {
933                 mono_raise_exception (mono_get_exception_overflow ());
934         }
935 #endif
936         return res;
937 }
938
939 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
940 double
941 mono_lconv_to_r8 (gint64 a)
942 {
943         return (double)a;
944 }
945 #endif
946
947 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
948 float
949 mono_lconv_to_r4 (gint64 a)
950 {
951         return (float)a;
952 }
953 #endif
954
955 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
956 double
957 mono_conv_to_r8_un (guint32 a)
958 {
959         return (double)a;
960 }
961 #endif
962
963 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
964 double
965 mono_lconv_to_r8_un (guint64 a)
966 {
967         return (double)a;
968 }
969 #endif
970
971 #if defined(__native_client_codegen__) || defined(__native_client__)
972 /* When we cross-compile to Native Client we can't directly embed calls */
973 /* to the math library on the host. This will use the fmod on the target*/
974 double
975 mono_fmod(double a, double b)
976 {
977         return fmod(a, b);
978 }
979 #endif
980
981 gpointer
982 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
983 {
984         MonoMethod *vmethod;
985         gpointer addr;
986         MonoGenericContext *context = mono_method_get_context (method);
987
988         mono_jit_stats.generic_virtual_invocations++;
989
990         if (obj == NULL)
991                 mono_raise_exception (mono_get_exception_null_reference ());
992         vmethod = mono_object_get_virtual_method (obj, method);
993         g_assert (!vmethod->klass->generic_container);
994         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
995         g_assert (!context->method_inst || !context->method_inst->is_open);
996
997         addr = mono_compile_method (vmethod);
998
999         addr = mini_add_method_trampoline (NULL, vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1000
1001         /* Since this is a virtual call, have to unbox vtypes */
1002         if (obj->vtable->klass->valuetype)
1003                 *this_arg = mono_object_unbox (obj);
1004         else
1005                 *this_arg = obj;
1006
1007         return addr;
1008 }
1009
1010 MonoString*
1011 mono_helper_ldstr (MonoImage *image, guint32 idx)
1012 {
1013         return mono_ldstr (mono_domain_get (), image, idx);
1014 }
1015
1016 MonoString*
1017 mono_helper_ldstr_mscorlib (guint32 idx)
1018 {
1019         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1020 }
1021
1022 MonoObject*
1023 mono_helper_newobj_mscorlib (guint32 idx)
1024 {
1025         MonoError error;
1026         MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1027         mono_error_raise_exception (&error);
1028
1029         return mono_object_new (mono_domain_get (), klass);
1030 }
1031
1032 /*
1033  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1034  * in generated code. So instead we emit a call to this function and place a gdb
1035  * breakpoint here.
1036  */
1037 void
1038 mono_break (void)
1039 {
1040 }
1041
1042 MonoException *
1043 mono_create_corlib_exception_0 (guint32 token)
1044 {
1045         return mono_exception_from_token (mono_defaults.corlib, token);
1046 }
1047
1048 MonoException *
1049 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1050 {
1051         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1052 }
1053
1054 MonoException *
1055 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1056 {
1057         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1058 }
1059
1060 MonoObject*
1061 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1062 {
1063         MonoJitTlsData *jit_tls = NULL;
1064         MonoClass *oklass;
1065
1066         if (mini_get_debug_options ()->better_cast_details) {
1067                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1068                 jit_tls->class_cast_from = NULL;
1069         }
1070
1071         if (!obj)
1072                 return NULL;
1073
1074         oklass = obj->vtable->klass;
1075         if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1076                 return obj;
1077         if (mono_object_isinst (obj, klass))
1078                 return obj;
1079
1080         if (mini_get_debug_options ()->better_cast_details) {
1081                 jit_tls->class_cast_from = oklass;
1082                 jit_tls->class_cast_to = klass;
1083         }
1084
1085         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1086                                         "System", "InvalidCastException"));
1087
1088         return NULL;
1089 }
1090
1091 MonoObject*
1092 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1093 {
1094         MonoJitTlsData *jit_tls = NULL;
1095         gpointer cached_vtable, obj_vtable;
1096
1097         if (mini_get_debug_options ()->better_cast_details) {
1098                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1099                 jit_tls->class_cast_from = NULL;
1100         }
1101
1102         if (!obj)
1103                 return NULL;
1104
1105         cached_vtable = *cache;
1106         obj_vtable = obj->vtable;
1107
1108         if (cached_vtable == obj_vtable)
1109                 return obj;
1110
1111         if (mono_object_isinst (obj, klass)) {
1112                 *cache = obj_vtable;
1113                 return obj;
1114         }
1115
1116         if (mini_get_debug_options ()->better_cast_details) {
1117                 jit_tls->class_cast_from = obj->vtable->klass;
1118                 jit_tls->class_cast_to = klass;
1119         }
1120
1121         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
1122                                         "System", "InvalidCastException"));
1123
1124         return NULL;
1125 }
1126
1127 MonoObject*
1128 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1129 {
1130         size_t cached_vtable, obj_vtable;
1131
1132         if (!obj)
1133                 return NULL;
1134
1135         cached_vtable = (size_t)*cache;
1136         obj_vtable = (size_t)obj->vtable;
1137
1138         if ((cached_vtable & ~0x1) == obj_vtable) {
1139                 return (cached_vtable & 0x1) ? NULL : obj;
1140         }
1141
1142         if (mono_object_isinst (obj, klass)) {
1143                 *cache = (gpointer)obj_vtable;
1144                 return obj;
1145         } else {
1146                 /*negative cache*/
1147                 *cache = (gpointer)(obj_vtable | 0x1);
1148                 return NULL;
1149         }
1150 }
1151
1152 gpointer
1153 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1154 {
1155         MonoMarshalSpec **mspecs;
1156         MonoMethodPInvoke piinfo;
1157         MonoMethod *m;
1158
1159         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1160         memset (&piinfo, 0, sizeof (piinfo));
1161
1162         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1163
1164         return mono_compile_method (m);
1165 }
1166
1167 static MonoMethod*
1168 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1169 {
1170         MonoMethod *m;
1171         int vt_slot;
1172
1173         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
1174                 mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
1175
1176         if (mono_method_signature (cmethod)->pinvoke) {
1177                 /* Object.GetType () */
1178                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1179         } else {
1180                 /* Lookup the virtual method */
1181                 mono_class_setup_vtable (klass);
1182                 g_assert (klass->vtable);
1183                 vt_slot = mono_method_get_vtable_slot (cmethod);
1184                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1185                         int iface_offset;
1186
1187                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1188                         g_assert (iface_offset != -1);
1189                         vt_slot += iface_offset;
1190                 }
1191                 m = klass->vtable [vt_slot];
1192         }
1193         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1194                 /*
1195                  * Calling a non-vtype method with a vtype receiver, has to box.
1196                  */
1197                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1198         else if (klass->valuetype)
1199                 /*
1200                  * Calling a vtype method with a vtype receiver
1201                  */
1202                 *this_arg = mp;
1203         else
1204                 /*
1205                  * Calling a non-vtype method
1206                  */
1207                 *this_arg = *(gpointer*)mp;
1208         return m;
1209 }
1210
1211 /*
1212  * mono_gsharedvt_constrained_call:
1213  *
1214  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1215  * the arguments to the method in the format used by mono_runtime_invoke ().
1216  */
1217 MonoObject*
1218 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1219 {
1220         MonoMethod *m;
1221         gpointer this_arg;
1222         gpointer new_args [16];
1223
1224         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1225         if (args && deref_arg) {
1226                 new_args [0] = *(gpointer*)args [0];
1227                 args = new_args;
1228         }
1229         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1230                 /* Object.GetType () */
1231                 args = new_args;
1232                 args [0] = this_arg;
1233                 this_arg = NULL;
1234         }
1235         return mono_runtime_invoke (m, this_arg, args, NULL);
1236 }
1237
1238 void
1239 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1240 {
1241         if (klass->valuetype)
1242                 mono_value_copy (dest, src, klass);
1243         else
1244         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1245 }