Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[mono.git] / mono / mini / jit-icalls.c
1 /*
2  * jit-icalls.c: internal calls used by the JIT
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2011 Novell Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
11  */
12 #include <config.h>
13 #include <math.h>
14 #include <limits.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18
19 #include "jit-icalls.h"
20 #include <mono/utils/mono-error-internals.h>
21 void*
22 mono_ldftn (MonoMethod *method)
23 {
24         gpointer addr;
25
26         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
27
28         return mono_create_ftnptr (mono_domain_get (), addr);
29 }
30
31 static void*
32 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
33 {
34         MonoError error;
35         MonoMethod *res;
36
37         if (obj == NULL) {
38                 mono_set_pending_exception (mono_get_exception_null_reference ());
39                 return NULL;
40         }
41
42         res = mono_object_get_virtual_method (obj, method);
43
44         if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
45                 MonoGenericContext context = { NULL, NULL };
46
47                 if (res->klass->generic_class)
48                         context.class_inst = res->klass->generic_class->context.class_inst;
49                 else if (res->klass->generic_container)
50                         context.class_inst = res->klass->generic_container->context.class_inst;
51                 context.method_inst = mono_method_get_context (method)->method_inst;
52
53                 res = mono_class_inflate_generic_method_checked (res, &context, &error);
54                 if (!mono_error_ok (&error)) {
55                         mono_error_set_pending_exception (&error);
56                         return NULL;
57                 }
58         }
59
60         /* An rgctx wrapper is added by the trampolines no need to do it here */
61
62         return mono_ldftn (res);
63 }
64
65 void*
66 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
67 {
68         return ldvirtfn_internal (obj, method, FALSE);
69 }
70
71 void*
72 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) 
73 {
74         return ldvirtfn_internal (obj, method, TRUE);
75 }
76
77 void
78 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
79 {
80         if (!array) {
81                 mono_set_pending_exception (mono_get_exception_null_reference ());
82                 return;
83         }
84         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
85                 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
86                 return;
87         }
88 }
89
90 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
91
92 gint64 
93 mono_llmult (gint64 a, gint64 b)
94 {
95         return a * b;
96 }
97
98 guint64  
99 mono_llmult_ovf_un (guint64 a, guint64 b)
100 {
101         guint32 al = a;
102         guint32 ah = a >> 32;
103         guint32 bl = b;
104         guint32 bh = b >> 32; 
105         guint64 res, t1;
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_set_pending_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         /* 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_set_pending_exception (mono_get_exception_overflow ());
234         return 0;
235 }
236
237 gint64 
238 mono_lldiv (gint64 a, gint64 b)
239 {
240 #ifdef MONO_ARCH_NEED_DIV_CHECK
241         if (!b) {
242                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
243                 return 0;
244         }
245         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
246                 mono_set_pending_exception (mono_get_exception_arithmetic ());
247                 return 0;
248         }
249 #endif
250         return a / b;
251 }
252
253 gint64 
254 mono_llrem (gint64 a, gint64 b)
255 {
256 #ifdef MONO_ARCH_NEED_DIV_CHECK
257         if (!b) {
258                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
259                 return 0;
260         }
261         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
262                 mono_set_pending_exception (mono_get_exception_arithmetic ());
263                 return 0;
264         }
265 #endif
266         return a % b;
267 }
268
269 guint64 
270 mono_lldiv_un (guint64 a, guint64 b)
271 {
272 #ifdef MONO_ARCH_NEED_DIV_CHECK
273         if (!b) {
274                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
275                 return 0;
276         }
277 #endif
278         return a / b;
279 }
280
281 guint64 
282 mono_llrem_un (guint64 a, guint64 b)
283 {
284 #ifdef MONO_ARCH_NEED_DIV_CHECK
285         if (!b) {
286                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
287                 return 0;
288         }
289 #endif
290         return a % b;
291 }
292
293 #endif
294
295 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
296
297 guint64 
298 mono_lshl (guint64 a, gint32 shamt)
299 {
300         guint64 res;
301
302         res = a << (shamt & 0x7f);
303
304         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
305
306         return res;
307 }
308
309 guint64 
310 mono_lshr_un (guint64 a, gint32 shamt)
311 {
312         guint64 res;
313
314         res = a >> (shamt & 0x7f);
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         res = a >> (shamt & 0x7f);
327
328         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
329
330         return res;
331 }
332
333 #endif
334
335 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
336
337 gint32
338 mono_idiv (gint32 a, gint32 b)
339 {
340 #ifdef MONO_ARCH_NEED_DIV_CHECK
341         if (!b) {
342                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
343                 return 0;
344         }
345         else if (b == -1 && a == (0x80000000)) {
346                 mono_set_pending_exception (mono_get_exception_overflow ());
347                 return 0;
348         }
349 #endif
350         return a / b;
351 }
352
353 guint32
354 mono_idiv_un (guint32 a, guint32 b)
355 {
356 #ifdef MONO_ARCH_NEED_DIV_CHECK
357         if (!b) {
358                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
359                 return 0;
360         }
361 #endif
362         return a / b;
363 }
364
365 gint32
366 mono_irem (gint32 a, gint32 b)
367 {
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
369         if (!b) {
370                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
371                 return 0;
372         }
373         else if (b == -1 && a == (0x80000000)) {
374                 mono_set_pending_exception (mono_get_exception_overflow ());
375                 return 0;
376         }
377 #endif
378         return a % b;
379 }
380
381 guint32
382 mono_irem_un (guint32 a, guint32 b)
383 {
384 #ifdef MONO_ARCH_NEED_DIV_CHECK
385         if (!b) {
386                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
387                 return 0;
388         }
389 #endif
390         return a % b;
391 }
392
393 #endif
394
395 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
396
397 gint32
398 mono_imul (gint32 a, gint32 b)
399 {
400         return a * b;
401 }
402
403 gint32
404 mono_imul_ovf (gint32 a, gint32 b)
405 {
406         gint64 res;
407
408         res = (gint64)a * (gint64)b;
409
410         if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
411                 mono_set_pending_exception (mono_get_exception_overflow ());
412                 return 0;
413         }
414
415         return res;
416 }
417
418 gint32
419 mono_imul_ovf_un (guint32 a, guint32 b)
420 {
421         guint64 res;
422
423         res = (guint64)a * (guint64)b;
424
425         if (res >> 32) {
426                 mono_set_pending_exception (mono_get_exception_overflow ());
427                 return 0;
428         }
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         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         pcount = mono_method_signature (cm)->param_count;
651         rank = cm->klass->rank;
652
653         va_start (ap, cm);
654         
655         lengths = alloca (sizeof (uintptr_t) * pcount);
656         for (i = 0; i < pcount; ++i)
657                 lengths [i] = d = va_arg(ap, int);
658
659         if (rank == pcount) {
660                 /* Only lengths provided. */
661                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
662                         lower_bounds = alloca (sizeof (intptr_t) * rank);
663                         memset (lower_bounds, 0, sizeof (intptr_t) * rank);
664                 } else {
665                         lower_bounds = NULL;
666                 }
667         } else {
668                 g_assert (pcount == (rank * 2));
669                 /* lower bounds are first. */
670                 lower_bounds = (intptr_t*)lengths;
671                 lengths += rank;
672         }
673         va_end(ap);
674
675         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
676 }
677
678 /* Specialized version of mono_array_new_va () which avoids varargs */
679 MonoArray *
680 mono_array_new_1 (MonoMethod *cm, guint32 length)
681 {
682         MonoDomain *domain = mono_domain_get ();
683         uintptr_t lengths [1];
684         intptr_t *lower_bounds;
685         int pcount;
686         int rank;
687
688         pcount = mono_method_signature (cm)->param_count;
689         rank = cm->klass->rank;
690
691         lengths [0] = length;
692
693         g_assert (rank == pcount);
694
695         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
696                 lower_bounds = alloca (sizeof (intptr_t) * rank);
697                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
698         } else {
699                 lower_bounds = NULL;
700         }
701
702         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
703 }
704
705 MonoArray *
706 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
707 {
708         MonoDomain *domain = mono_domain_get ();
709         uintptr_t lengths [2];
710         intptr_t *lower_bounds;
711         int pcount;
712         int rank;
713
714         pcount = mono_method_signature (cm)->param_count;
715         rank = cm->klass->rank;
716
717         lengths [0] = length1;
718         lengths [1] = length2;
719
720         g_assert (rank == pcount);
721
722         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
723                 lower_bounds = alloca (sizeof (intptr_t) * rank);
724                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
725         } else {
726                 lower_bounds = NULL;
727         }
728
729         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
730 }
731
732 MonoArray *
733 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
734 {
735         MonoDomain *domain = mono_domain_get ();
736         uintptr_t lengths [3];
737         intptr_t *lower_bounds;
738         int pcount;
739         int rank;
740
741         pcount = mono_method_signature (cm)->param_count;
742         rank = cm->klass->rank;
743
744         lengths [0] = length1;
745         lengths [1] = length2;
746         lengths [2] = length3;
747
748         g_assert (rank == pcount);
749
750         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
751                 lower_bounds = alloca (sizeof (intptr_t) * rank);
752                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
753         } else {
754                 lower_bounds = NULL;
755         }
756
757         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
758 }
759
760 MonoArray *
761 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
762 {
763         MonoDomain *domain = mono_domain_get ();
764         uintptr_t lengths [4];
765         intptr_t *lower_bounds;
766         int pcount;
767         int rank;
768
769         pcount = mono_method_signature (cm)->param_count;
770         rank = cm->klass->rank;
771
772         lengths [0] = length1;
773         lengths [1] = length2;
774         lengths [2] = length3;
775         lengths [3] = length4;
776
777         g_assert (rank == pcount);
778
779         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
780                 lower_bounds = alloca (sizeof (intptr_t) * rank);
781                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
782         } else {
783                 lower_bounds = NULL;
784         }
785
786         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
787 }
788
789 gpointer
790 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
791 {
792         MonoVTable *vtable;
793         gpointer addr;
794         
795         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
796
797         mono_class_init (field->parent);
798
799         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
800         if (!vtable->initialized)
801                 mono_runtime_class_init (vtable);
802
803         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
804
805         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
806                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
807         else
808                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
809         
810         return addr;
811 }
812
813 gpointer
814 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
815 {
816         MonoError error;
817         MonoClass *handle_class;
818         gpointer res;
819
820         res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
821         if (!mono_error_ok (&error)) {
822                 mono_error_set_pending_exception (&error);
823                 return NULL;
824         }
825         mono_class_init (handle_class);
826
827         return res;
828 }
829
830 gpointer
831 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
832 {
833         MonoMethodSignature *sig = mono_method_signature (method);
834         MonoGenericContext *generic_context;
835
836         if (sig->is_inflated) {
837                 generic_context = mono_method_get_context (method);
838         } else {
839                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
840                 g_assert (generic_container);
841                 generic_context = &generic_container->context;
842         }
843
844         return mono_ldtoken_wrapper (image, token, generic_context);
845 }
846
847 guint64
848 mono_fconv_u8 (double v)
849 {
850         return (guint64)v;
851 }
852
853 guint64
854 mono_rconv_u8 (float v)
855 {
856         return (guint64)v;
857 }
858
859 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
860 gint64
861 mono_fconv_i8 (double v)
862 {
863         return (gint64)v;
864 }
865 #endif
866
867 guint32
868 mono_fconv_u4 (double v)
869 {
870         /* MS.NET behaves like this for some reason */
871 #ifdef HAVE_ISINF
872         if (isinf (v) || isnan (v))
873                 return 0;
874 #endif
875
876         return (guint32)v;
877 }
878
879 #ifndef HAVE_TRUNC
880 /* Solaris doesn't have trunc */
881 #ifdef HAVE_AINTL
882 extern long double aintl (long double);
883 #define trunc aintl
884 #else
885 /* FIXME: This means we will never throw overflow exceptions */
886 #define trunc(v) res
887 #endif
888 #endif /* HAVE_TRUNC */
889
890 gint64
891 mono_fconv_ovf_i8 (double v)
892 {
893         gint64 res;
894
895         res = (gint64)v;
896
897         if (isnan(v) || trunc (v) != res) {
898                 mono_set_pending_exception (mono_get_exception_overflow ());
899                 return 0;
900         }
901         return res;
902 }
903
904 guint64
905 mono_fconv_ovf_u8 (double v)
906 {
907         guint64 res;
908
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__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
919         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
920                 mono_set_pending_exception (mono_get_exception_overflow ());
921                 return 0;
922         }
923         res = (guint64)v;
924 #else
925         res = (guint64)v;
926         if (isnan(v) || trunc (v) != res) {
927                 mono_set_pending_exception (mono_get_exception_overflow ());
928                 return 0;
929         }
930 #endif
931         return res;
932 }
933
934 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
935 gint64
936 mono_rconv_i8 (float v)
937 {
938         return (gint64)v;
939 }
940 #endif
941
942 gint64
943 mono_rconv_ovf_i8 (float v)
944 {
945         gint64 res;
946
947         res = (gint64)v;
948
949         if (isnan(v) || trunc (v) != res) {
950                 mono_set_pending_exception (mono_get_exception_overflow ());
951                 return 0;
952         }
953         return res;
954 }
955
956 guint64
957 mono_rconv_ovf_u8 (float v)
958 {
959         guint64 res;
960
961         res = (guint64)v;
962         if (isnan(v) || trunc (v) != res) {
963                 mono_set_pending_exception (mono_get_exception_overflow ());
964                 return 0;
965         }
966         return res;
967 }
968
969 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
970 double
971 mono_lconv_to_r8 (gint64 a)
972 {
973         return (double)a;
974 }
975 #endif
976
977 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
978 float
979 mono_lconv_to_r4 (gint64 a)
980 {
981         return (float)a;
982 }
983 #endif
984
985 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
986 double
987 mono_conv_to_r8_un (guint32 a)
988 {
989         return (double)a;
990 }
991 #endif
992
993 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
994 double
995 mono_lconv_to_r8_un (guint64 a)
996 {
997         return (double)a;
998 }
999 #endif
1000
1001 #if defined(__native_client_codegen__) || defined(__native_client__)
1002 /* When we cross-compile to Native Client we can't directly embed calls */
1003 /* to the math library on the host. This will use the fmod on the target*/
1004 double
1005 mono_fmod(double a, double b)
1006 {
1007         return fmod(a, b);
1008 }
1009 #endif
1010
1011 gpointer
1012 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1013 {
1014         MonoMethod *vmethod;
1015         gpointer addr;
1016         MonoGenericContext *context = mono_method_get_context (method);
1017
1018         mono_jit_stats.generic_virtual_invocations++;
1019
1020         if (obj == NULL) {
1021                 mono_set_pending_exception (mono_get_exception_null_reference ());
1022                 return NULL;
1023         }
1024         vmethod = mono_object_get_virtual_method (obj, method);
1025         g_assert (!vmethod->klass->generic_container);
1026         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1027         g_assert (!context->method_inst || !context->method_inst->is_open);
1028
1029         addr = mono_compile_method (vmethod);
1030
1031         addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1032
1033         /* Since this is a virtual call, have to unbox vtypes */
1034         if (obj->vtable->klass->valuetype)
1035                 *this_arg = mono_object_unbox (obj);
1036         else
1037                 *this_arg = obj;
1038
1039         return addr;
1040 }
1041
1042 MonoString*
1043 mono_helper_ldstr (MonoImage *image, guint32 idx)
1044 {
1045         return mono_ldstr (mono_domain_get (), image, idx);
1046 }
1047
1048 MonoString*
1049 mono_helper_ldstr_mscorlib (guint32 idx)
1050 {
1051         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1052 }
1053
1054 MonoObject*
1055 mono_helper_newobj_mscorlib (guint32 idx)
1056 {
1057         MonoError error;
1058         MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1059
1060         if (!mono_error_ok (&error)) {
1061                 mono_error_set_pending_exception (&error);
1062                 return NULL;
1063         }
1064
1065         return mono_object_new (mono_domain_get (), klass);
1066 }
1067
1068 /*
1069  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1070  * in generated code. So instead we emit a call to this function and place a gdb
1071  * breakpoint here.
1072  */
1073 void
1074 mono_break (void)
1075 {
1076 }
1077
1078 MonoException *
1079 mono_create_corlib_exception_0 (guint32 token)
1080 {
1081         return mono_exception_from_token (mono_defaults.corlib, token);
1082 }
1083
1084 MonoException *
1085 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1086 {
1087         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1088 }
1089
1090 MonoException *
1091 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1092 {
1093         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1094 }
1095
1096 MonoObject*
1097 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1098 {
1099         MonoJitTlsData *jit_tls = NULL;
1100         MonoClass *oklass;
1101
1102         if (mini_get_debug_options ()->better_cast_details) {
1103                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1104                 jit_tls->class_cast_from = NULL;
1105         }
1106
1107         if (!obj)
1108                 return NULL;
1109
1110         oklass = obj->vtable->klass;
1111         if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1112                 return obj;
1113         if (mono_object_isinst (obj, klass))
1114                 return obj;
1115
1116         if (mini_get_debug_options ()->better_cast_details) {
1117                 jit_tls->class_cast_from = oklass;
1118                 jit_tls->class_cast_to = klass;
1119         }
1120
1121         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1122                                         "System", "InvalidCastException"));
1123
1124         return NULL;
1125 }
1126
1127 MonoObject*
1128 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1129 {
1130         MonoJitTlsData *jit_tls = NULL;
1131         gpointer cached_vtable, obj_vtable;
1132
1133         if (mini_get_debug_options ()->better_cast_details) {
1134                 jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1135                 jit_tls->class_cast_from = NULL;
1136         }
1137
1138         if (!obj)
1139                 return NULL;
1140
1141         cached_vtable = *cache;
1142         obj_vtable = obj->vtable;
1143
1144         if (cached_vtable == obj_vtable)
1145                 return obj;
1146
1147         if (mono_object_isinst (obj, klass)) {
1148                 *cache = obj_vtable;
1149                 return obj;
1150         }
1151
1152         if (mini_get_debug_options ()->better_cast_details) {
1153                 jit_tls->class_cast_from = obj->vtable->klass;
1154                 jit_tls->class_cast_to = klass;
1155         }
1156
1157         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1158                                         "System", "InvalidCastException"));
1159
1160         return NULL;
1161 }
1162
1163 MonoObject*
1164 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1165 {
1166         size_t cached_vtable, obj_vtable;
1167
1168         if (!obj)
1169                 return NULL;
1170
1171         cached_vtable = (size_t)*cache;
1172         obj_vtable = (size_t)obj->vtable;
1173
1174         if ((cached_vtable & ~0x1) == obj_vtable) {
1175                 return (cached_vtable & 0x1) ? NULL : obj;
1176         }
1177
1178         if (mono_object_isinst (obj, klass)) {
1179                 *cache = (gpointer)obj_vtable;
1180                 return obj;
1181         } else {
1182                 /*negative cache*/
1183                 *cache = (gpointer)(obj_vtable | 0x1);
1184                 return NULL;
1185         }
1186 }
1187
1188 gpointer
1189 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1190 {
1191         MonoMarshalSpec **mspecs;
1192         MonoMethodPInvoke piinfo;
1193         MonoMethod *m;
1194
1195         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1196         memset (&piinfo, 0, sizeof (piinfo));
1197
1198         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1199
1200         return mono_compile_method (m);
1201 }
1202
1203 static MonoMethod*
1204 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1205 {
1206         MonoMethod *m;
1207         int vt_slot;
1208
1209         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1210                 mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
1211                 return NULL;
1212         }
1213
1214         if (mono_method_signature (cmethod)->pinvoke) {
1215                 /* Object.GetType () */
1216                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1217         } else {
1218                 /* Lookup the virtual method */
1219                 mono_class_setup_vtable (klass);
1220                 g_assert (klass->vtable);
1221                 vt_slot = mono_method_get_vtable_slot (cmethod);
1222                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1223                         int iface_offset;
1224
1225                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1226                         g_assert (iface_offset != -1);
1227                         vt_slot += iface_offset;
1228                 }
1229                 m = klass->vtable [vt_slot];
1230                 if (cmethod->is_inflated)
1231                         m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1232         }
1233         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1234                 /*
1235                  * Calling a non-vtype method with a vtype receiver, has to box.
1236                  */
1237                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1238         else if (klass->valuetype)
1239                 /*
1240                  * Calling a vtype method with a vtype receiver
1241                  */
1242                 *this_arg = mp;
1243         else
1244                 /*
1245                  * Calling a non-vtype method
1246                  */
1247                 *this_arg = *(gpointer*)mp;
1248         return m;
1249 }
1250
1251 /*
1252  * mono_gsharedvt_constrained_call:
1253  *
1254  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1255  * the arguments to the method in the format used by mono_runtime_invoke ().
1256  */
1257 MonoObject*
1258 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1259 {
1260         MonoMethod *m;
1261         gpointer this_arg;
1262         gpointer new_args [16];
1263
1264         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1265         if (!m)
1266                 return NULL;
1267         if (args && deref_arg) {
1268                 new_args [0] = *(gpointer*)args [0];
1269                 args = new_args;
1270         }
1271         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1272                 /* Object.GetType () */
1273                 args = new_args;
1274                 args [0] = this_arg;
1275                 this_arg = NULL;
1276         }
1277         return mono_runtime_invoke (m, this_arg, args, NULL);
1278 }
1279
1280 void
1281 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1282 {
1283         if (klass->valuetype)
1284                 mono_value_copy (dest, src, klass);
1285         else
1286         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1287 }
1288
1289 void
1290 mono_generic_class_init (MonoVTable *vtable)
1291 {
1292         mono_runtime_class_init (vtable);
1293 }
1294
1295 gpointer
1296 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1297 {
1298         return mono_class_fill_runtime_generic_context (vtable, index);
1299 }
1300
1301 gpointer
1302 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1303 {
1304         return mono_method_fill_runtime_generic_context (mrgctx, index);
1305 }