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